基础随记

判断对象是否存在指定键名

ini 复制代码
Object.keys(data).find(x => x === 'name')

Object.keys(data) :作用:获取对象 newQuery 所有自身可枚举属性的键名,返回一个字符串数组

示例:若 data = { id: 1, copy: true, name: 'test' },则返回 ['id', 'copy', 'name']

.find(x => x === 'name') 作用:遍历数组(此处是键名数组),找到第一个满足条件x === 'name')的元素并返回;若遍历完无匹配元素,返回 undefined

示例:遍历 ['id', 'copy', 'name'] 时,第一个匹配 'copy' 的元素是 'copy',故返回 'copy';若数组中无 'copy',则返回 undefined

使用场景:精准判断对象键名存在性

判断对象是否自身拥有 某键名(排除原型链上的属性) const data = { name: '1' }; if (Object.keys(data).find(x => x === 'name')) { console.log('存在 name 键'); // 执行 }

传统写法:data.hasOwnProperty('name')(返回布尔值 true/false

返回键名 'copy'undefined,可直接用于条件判断(效果等同于 hasOwnProperty

使用场景:动态匹配键名(支持变量 / 模糊匹配)

键名不确定(由变量传入),或需要模糊匹配(如包含某字符串、符合正则) 示例 1:动态判断变量键名

ini 复制代码
```
const key = 'copy'; // 可从接口/用户输入获取
const hasKey = Object.keys(data).find(x => x === key);
if (hasKey) {
  console.log(`存在键 ${hasKey}`);
}
```

示例 2:模糊匹配(判断是否存在以 copy 开头的键)

ini 复制代码
```
const data = { copy1: 'a', copy2: 'b', other: 'c' };
const matchKey = Object.keys(data).find(x => x.startsWith('copy'));
console.log(matchKey); // 'copy1'(返回第一个匹配项)
```

在键名数组中查找并后续操作

找到键名后,需直接使用该键名(如获取对应属性值、修改属性)

ini 复制代码
const data = { id: 1, copy: '原始数据' };
const targetKey = Object.keys(data).find(x => x === 'copy');

if (targetKey) {
  console.log(data[targetKey]); // 输出 '原始数据'(通过找到的键名获取值)
  data[targetKey] = '修改后数据'; // 通过键名修改值
}

处理可能存在的原型链污染(安全判断)

避免对象原型链上的属性干扰判断(如 __proto__constructor 等)

ini 复制代码
const data = {};
newQuery.__proto__.copy = '原型链上的属性';

console.log('copy' in data); // true(不期望的结果)
console.log(Object.keys(data).find(x => x === 'copy')); // undefined(正确,排除原型链)

性能略低于 hasOwnProperty,但简单直观、支持动态查找、可用于复杂条件匹配

替代:Object.prototype.hasOwnProperty.call(obj, key)Reflect.has(obj, key)

Object.prototype.hasOwnProperty.call(obj, key)Reflect.has(obj, key)区别

hasOwnProperty 只检查对象自身的属性,不包括原型链;Reflect.has 检查对象自身及其原型链上的所有属性

Object.prototype.hasOwnProperty.call(obj, key)

作用 :仅判断指定的 key 是否为对象 obj 自身的、可枚举或不可枚举的属性(不包括原型链上继承的属性)。

Reflect.has(obj, key)

作用 :判断指定的 key 是否为对象 obj 自身的属性,或者是其原型链上任何一个对象的属性

javascript 复制代码
// 1. 创建一个原型对象
const animalPrototype = {
  type: 'animal' // 这是一个原型上的属性
};

// 2. 使用 Object.create 创建一个新对象,并将其原型指向 animalPrototype
const cat = Object.create(animalPrototype);
cat.name = 'Tom'; // 这是 cat 对象自身的属性

console.log('--- 检查自身属性 "name" ---');
console.log(Object.prototype.hasOwnProperty.call(cat, 'name')); // true
console.log(Reflect.has(cat, 'name'));                         // true
console.log('-------------------------\n');

console.log('--- 检查原型链上的属性 "type" ---');
console.log(Object.prototype.hasOwnProperty.call(cat, 'type')); // false -> 'type' 不是 cat 自身的属性
console.log(Reflect.has(cat, 'type'));                         // true  -> 'type' 是 cat 原型链上的属性
console.log('-------------------------\n');

console.log('--- 检查一个不存在的属性 "age" ---');
console.log(Object.prototype.hasOwnProperty.call(cat, 'age')); // false
console.log(Reflect.has(cat, 'age'));                         // false



--- 检查自身属性 "name" ---
true
true
-------------------------

--- 检查原型链上的属性 "type" ---
false
true
-------------------------

--- 检查一个不存在的属性 "age" ---
false
false

使用场景推荐

什么时候用 Object.prototype.hasOwnProperty.call

需要严格判断一个属性是否是对象自身定义的 ,而不是从原型链上继承来的。例如在遍历对象属性时(for...in 循环)。

什么时候用 Reflect.has

需要检查一个属性是否在对象或其原型链上存在 时,它的功能与 in 运算符完全相同,但语法是函数式的,更适合用于函数式编程或需要将操作作为参数传递的场景。 当你在使用其他 Reflect 方法(如 Reflect.get, Reflect.set)时,为了保持代码风格的一致性,可以统一使用 Reflect.has。 想替代 'key' in obj,就用 Reflect.has(obj, 'key')

盒模型

当一个DOM节点在浏览器中渲染后会占用一个方形区域,这个方形区域就是盒子。

盒子的组成分别是:

1.宽度:这个属性决定了此盒子的宽度。

2.高度:这个属性决定了此盒子的高度。

3.内边距:盒子里内容与边框之间的距离。

4.外边距:盒子与盒子之间的距离。

因为浏览器不同分为两种盒模型:

1.标准盒模型:由W3C组织制定的,除了低版本IE外,其他浏览器都遵循标准。width和height的值是内容区域的大小,而盒子实际大小需要加上边框和内边距的值。

2.怪异盒模型:又叫IE盒模型,width和height的值就是盒子实际大小,边框和内边距都是在宽和高的值内,内容区域就是减去边框和外边框的值。

标准盒子模型下进行布局时需要计算下内边距和边框,并不方便计算及布局。所以怪异模式下,盒子大小确定,设置好内边距和边框,内容区域浏览器进行计算,方便很多。

box-sizing属性解决了这个问题,css中通过设置box-sizing指定使用哪种盒子模型,进行混合使用。

外边距折叠: margin是盒子与盒子之间的距离,如果盒子都设置了外边距可能会出现外边距折叠,一般是指垂直方向相邻的外边距会发生重叠现象,对于上下相邻的块级元素和父子元素之间的外边距。

如A盒子下边距10px,B盒子上边距20px,中间相隔的距离是20px,而不是相加一起30px。因为盒子间距实际值如果两个值都是正值取两个盒子之间较大的那个值,如果两个值一正一负,取两个值的和,如果两个都是负值,取绝对值较大的。

父元素的上边距和第一个子元素的上边距会折叠或父元素的下边距和最后一个子元素的下边距会折叠,取其中较大的值作为最终的外边距。

文档流

DOM节点排版布局过程中,元素自动从左往右,从上往下的流式排列。一行排满自动换下一行,如果使用绝对定位,固定位或者浮动,这个元素就会脱离文档流。所以HTML是一个三维的空间,有平面的 x,y 位置,也有 z 轴上的层叠关系。

层叠关系就是:标准文档流内容在第一层,使用浮动的元素,在标准文档流之后渲染,处于标准文档流之上。而绝对定位的元素最后渲染,处于最上面一层,但是可以通过z-index 来操作层叠的位置。

页面渲染

1.输入URL获取到HTML文件,并进行解析。

2.解析HTML过程中,如果发现含有外部资源链接,js,css,图片时,会启动其他线程进行下载。但是遇见js文件时候,会停止HTML解析,等js文件下载结束并执行完,再进行解析。是因为js可能会出现修改DOM已经完成解析的结果,所以等js结束才会继续解析。

3.HTML解析的同时,解析器把解析完的HTML转化成DOM对象,再进一步构建DOM树。

4.css下载完之后,css解析器开始解析css文件,解析成css对象,构成CSSOM树。

5.DOM树和CSSOM树都构建完成以后,浏览器会根据这两棵树构建出一颗渲染树。

6.渲染树构建完成之后,进行布局计算。

7.布局计算完成后,页面渲染元素,内容呈现在屏幕上。

重排:

DOM数中进行增加,删除,修改元素的大小,位置,布局方式等都需要重新计算,重新经历DOM改动,CSSOM树的构建,渲染树的构建,重新绘制整个流程,也叫回流

重绘:

改变元素颜色等外观属性时候,不改变位置大小,影响其他元素布局,这个就无需重新构建渲染树,就只对样式进行重新绘制。

vue3:获取当前路由的完整 URL 路径

router.currentRoute.value.fullPath 的作用是 获取当前路由的完整 URL 路径(包含查询参数和哈希值)

  1. router:

    这通常是指在 Vue.js 项目中通过 createRouter 创建的路由实例。它管理着整个应用的路由配置和导航状态。

  2. currentRoute:

    这是 router 实例上的一个属性,它返回一个 响应式的(reactive)路由对象 。 这个对象包含了当前页面的路由信息,例如路径 (path)、参数 (params)、查询参数 (query) 等。 在 Vue 3 中,currentRoute 是一个 Ref 对象,所以你需要通过 .value 来访问它的值。

  3. value:

    因为 currentRoute 是一个 Ref 对象,它的值被包裹在 .value 属性中。 所以 router.currentRoute.value 才是获取到的当前路由的实际对象

  4. fullPath:

    这是路由对象上的一个属性。

    它返回当前路由的完整路径字符串,包括:

    markdown 复制代码
    -   路径 (`path`)
    -   查询参数(以 `?` 开头)
    -   哈希值(以 `#` 开头)

假设你当前在浏览器中的 URL 是:http://localhost:8080/user/profile?id=123&name=张三#info

xml 复制代码
<script setup>
import { useRouter } from 'vue-router';

const router = useRouter();

// 获取当前路由对象
const currentRoute = router.currentRoute;

console.log(currentRoute.value.fullPath); 
// 输出: "/user/profile?id=123&name=张三#info"

// 你也可以分别获取其他属性
console.log(currentRoute.value.path);      
// 输出: "/user/profile" (不包含查询参数和哈希)
console.log(currentRoute.value.query);     
// 输出: { id: '123', name: '张三' } (一个解析后的对象)
console.log(currentRoute.value.hash);      
// 输出: "#info"
</script>

常见使用场景

  1. 在组件中获取当前 URL 信息

    当你需要根据当前 URL 的查询参数来加载不同的数据时。 例如,列表页根据 ?page=2 来加载第二页的数据。

  2. 导航守卫(Navigation Guards)

    在路由守卫中,你可能需要根据从哪个页面来(from.fullPath)或者要到哪个页面去(to.fullPath)来做一些判断逻辑。 例如,判断用户是否有权限访问某个需要特定查询参数的页面。

  3. 记录或分享当前页面地址

    如果你想实现一个 "分享当前页面" 的功能,fullPath 就非常有用,因为它包含了所有必要的信息,可以让其他人打开后看到和你一模一样的页面状态。

  4. 处理面包屑导航(Breadcrumb)

    虽然面包屑导航主要依赖 $route.matched 数组,但在某些复杂情况下,也可能需要用到 fullPath 来生成正确的链接。

相关推荐
Sakura_洁2 小时前
解决 el-table 在 fixed 状态下获取 dom 不准确的问题
前端
best6662 小时前
Vue3什么时候不会触发onMounted生命周期钩子?
前端·vue.js
best6662 小时前
Javascript有哪些遍历数组的方法?哪些不支持中断?那些不支持异步遍历?
前端·javascript·面试
特级业务专家2 小时前
Chrome DevTools 高级调试技巧:从入门到真香
前端·javascript·浏览器
爱学习的程序媛2 小时前
【Web前端】Angular核心知识点梳理
前端·javascript·typescript·angular.js
小时前端2 小时前
前端架构师视角:如何设计一个“站稳多端”的跨端体系?
前端·javascript·面试
Hilaku2 小时前
这 5 个冷门的 HTML 标签,能让你少写 100 行 JS
前端·javascript·html
杰克尼2 小时前
vue_day06
前端·javascript·vue.js
DcTbnk2 小时前
ESM (放到打包里 import) 和 IIFE (URL 动态 loadScript)
前端·javascript