Object.keys 与 Object.getOwnPropertyNames() 有何区别
Object.keys()和Object.getOwnPropertyNames()都是用于获取对象自身属性名的方法,但它们之间存在一些区别:
一、返回值类型
-
Object.keys():- 返回一个由对象自身可枚举属性名组成的数组。
- 可枚举属性是指那些可以通过
for...in循环遍历到的属性。
-
Object.getOwnPropertyNames():- 返回一个由对象自身所有属性名组成的数组,无论属性是否可枚举。
二、可枚举性处理
-
Object.keys():- 只返回可枚举属性的名称。如果一个属性被设置为不可枚举,它将不会出现在
Object.keys()的返回结果中。 - 例如,使用
Object.defineProperty()定义的不可枚举属性不会被包含在Object.keys()的结果中。
- 只返回可枚举属性的名称。如果一个属性被设置为不可枚举,它将不会出现在
-
Object.getOwnPropertyNames():-
返回所有属性的名称,包括可枚举和不可枚举的属性。
-
这使得它在需要获取对象的所有属性,无论其可枚举性如何时非常有用。
-
const obj = {
property1: "value1",
property2: "value2",
};
Object.defineProperty(obj, "nonEnumerableProperty", {
value: "value3",
enumerable: false,
});
console.log(Object.keys(obj)); // ['property1', 'property2']
console.log(Object.getOwnPropertyNames(obj)); // ['property1', 'property2', 'nonEnumerableProperty']
在这个例子中,Object.keys()只返回了可枚举的属性property1和property2,而Object.getOwnPropertyNames()返回了所有属性,包括不可枚举的nonEnumerableProperty。
eslint 如何集成到 webpack
要将 ESLint 集成到 Webpack 中,可以按照以下步骤进行操作:
一、安装必要的包
-
确保已经安装了 Webpack 和 ESLint。如果还没有安装,可以使用以下命令进行安装:
-
使用 npm:
npm install webpack webpack-cli eslint --save-dev -
使用 yarn:
yarn add webpack webpack-cli eslint --dev
-
-
安装
eslint-webpack-plugin插件,这个插件可以将 ESLint 集成到 Webpack 构建过程中。-
使用 npm:
npm install eslint-webpack-plugin --save-dev -
使用 yarn:
yarn add eslint-webpack-plugin --dev
-
二、配置 ESLint
- 在项目根目录下,运行
eslint --init命令来初始化 ESLint 配置。按照提示选择适合项目的选项,生成.eslintrc.*配置文件。 - 根据项目需求,调整 ESLint 配置文件中的规则、解析器、插件等选项。
三、配置 Webpack
-
在 Webpack 配置文件(通常是
webpack.config.js)中,引入eslint-webpack-plugin插件:const ESLintPlugin = require("eslint-webpack-plugin"); -
在 Webpack 配置对象的
plugins数组中添加ESLintPlugin实例:module.exports = { //...其他配置项 plugins: [ new ESLintPlugin({ // 可以在这里配置 ESLintPlugin 的选项,例如指定要检查的文件路径 files: ["./src/**/*.js"], }), ], };
如何判定一个属性来自于对象本身, 还是来自于原型链
一、使用 hasOwnProperty() 方法
-
方法介绍:
hasOwnProperty()是 JavaScript 对象的一个方法,用于判断一个对象自身是否具有指定的属性。- 它不会检查原型链上的属性,只关注对象本身是否拥有该属性。
function Person() {}
Person.prototype.name = "prototype name";
const person = new Person();
person.age = 30;
console.log(person.hasOwnProperty("age")); // true,说明 age 属性是对象本身的属性
console.log(person.hasOwnProperty("name")); // false,说明 name 属性不在对象本身,而是在原型链上
二、使用 in 操作符结合 hasOwnProperty()
-
方法介绍:
in操作符用于检查一个对象及其原型链中是否具有指定的属性。- 可以结合
hasOwnProperty()来判断属性的来源。
function Person() {}
Person.prototype.name = "prototype name";
const person = new Person();
person.age = 30;
const propertyName = "name";
if (person.hasOwnProperty(propertyName)) {
console.log(`${propertyName} is an own property of the object.`);
} else if (propertyName in person) {
console.log(`${propertyName} is inherited from the prototype.`);
} else {
console.log(`${propertyName} is not found in the object or its prototype.`);
}
三、使用 Object.getOwnPropertyDescriptor() 方法
-
方法介绍:
Object.getOwnPropertyDescriptor()方法返回指定对象上一个自有属性的属性描述符。- 如果对象没有指定的自有属性,则返回
undefined。
function Person() {}
Person.prototype.name = "prototype name";
const person = new Person();
person.age = 30;
const ageDescriptor = Object.getOwnPropertyDescriptor(person, "age");
const nameDescriptor = Object.getOwnPropertyDescriptor(person, "name");
if (ageDescriptor) {
console.log("age is an own property of the object.");
}
if (!nameDescriptor) {
console.log("name is not an own property of the object.");
}
绑定事件的元素节点销毁又重新创建, 绑定的事件还会生效吗
如果将事件绑定在 body 上,然后移除了这个 body 标签并重新创建一个 body 标签,之前绑定在旧 body 上的事件不会生效在新的 body 上。
原因如下:
当你使用传统的事件绑定方式(如 addEventListener)将事件绑定到一个特定的 DOM 元素上时,这个绑定是针对特定的实例。一旦该元素被移除,与之相关的事件处理程序也会与该元素一起被销毁。当重新创建一个新的 body 标签时,它是一个全新的 DOM 元素,没有与之前被移除的 body 上的事件处理程序相关联。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
</head>
<body>
<script>
document.body.addEventListener("click", function () {
console.log("body clicked");
});
// 假设这里有一些代码移除了 body 并重新创建一个新的 body
const oldBody = document.body;
oldBody.parentNode.removeChild(oldBody);
const newBody = document.createElement("body");
document.documentElement.appendChild(newBody);
</script>
</body>
</html>
比如我把事件委托注册在 body 上面, 我如何去针对性的出发 不同的子元素
event.target 属性:
- 当事件在
body上触发时,可以通过event.target来获取实际触发事件的元素。
document.body.addEventListener("click", function (event) {
const target = event.target;
if (target.classList.contains("button1")) {
// 处理按钮 1 的点击事件
} else if (target.classList.contains("button2")) {
// 处理按钮 2 的点击事件
}
});
matches() 方法:
- 可以使用
event.target.matches(selector)方法来检查目标元素是否与特定的 CSS 选择器匹配。 - 例如
document.body.addEventListener("click", function (event) {
const target = event.target;
if (target.matches("#element1")) {
// 处理元素 1 的点击事件
} else if (target.matches(".class2")) {
// 处理具有特定类名的元素的点击事件
}
});
- 这里使用
matches()方法来判断点击的元素是否与特定的 ID 或类名选择器匹配,从而执行相应的操作。
二、使用数据属性进行区分
设置 data-* 属性:
- 可以在 HTML 元素上设置自定义的
data-*属性来标识不同的元素,并在事件处理函数中根据这些属性进行区分。
<button data-action="action1">Button 1</button> <button data-action="action2">Button 2</button>
然后在 JavaScript 中:
document.body.addEventListener("click", function (event) {
const target = event.target;
if (target.dataset.action === "action1") {
// 处理按钮 1 的点击事件
} else if (target.dataset.action === "action2") {
// 处理按钮 2 的点击事件
}
});
通过这些方法,可以在事件委托到 body 的情况下,有针对性地处理不同子元素的事件,提高代码的效率和可维护性。
Vue的异步更新队列是什么?
Vue的异步更新队列是Vue实现响应式系统的一种方式。当数据发生变化时,Vue会将其放入异步更新队列中,而不是立即更新DOM。这样做可以提高性能,因为多个数据变化可以合并成一个DOM更新操作。
描述下Vue从初始化页面到修改数据再到刷新页面UI的过程。
:Vue在初始化页面时,会创建Vue实例,并遍历data对象中的所有属性,使用Object.defineProperty()将它们转为getter/setter。当用户修改数据时,setter函数会被触发,Vue会记录数据的变化。然后,Vue会使用虚拟DOM技术,将变化的数据渲染到页面上,从而实现UI的更新。
Vue中如何实现路由的懒加载?
在Vue中,可以通过路由的懒加载来优化性能。具体做法是将路由对应的组件设置为一个函数,该函数返回一个Promise对象,Promise对象通过import()动态导入组件。这样,只有在访问该路由时,才会加载对应的组件,减少初始加载时间