8个原型链方法和属性
1.Object.prototype.constructor
constructor
返回实例该对象构造函数的引用
js
function Person(name, age){
this.name = name;
this.age = age;
}
const person = new Person('虫洞空间', 23);
console.log(person.constructoe === Person); // true
2.Object.prototype.__proto__
**已弃用: ** 该属性已从web标准中移除。
如需获取或更改原型可以使用
Object.getPrototypeOf()
/Object.setPrototypeOf()
js
function Person(name, age){
this.name = name;
this.age = age;
}
const person = new Person('虫洞空间', 23);
console.log(person.__proto__ === Person.prototype); // true
__proto__
的 getter 函数暴露了一个对象内部的 [[Prototype]]
的值。__proto__
的 setter 允许修改一个对象的 [[Prototype]]
。提供的值必须是一个对象或 null
,任何其他值都不会产生作用。
__proto__
是 Object.prototype
上的访问器属性。原型为null
的对象__proto__
的值会为undefined
,并且对 __proto__
的任何赋值都将创建一个名为 __proto__
的新属性,而不是设置对象的原型,因此,这种情况下__proto__
不再是 [[Prototype]]
的访问器,无法在通过__proto__
设置对象的原型。综上,我们想要设置和获取原型对象应使用Object.getPrototypeOf()
/ Object.setPrototypeOf()
。
3.Object.prototype.hasOwnProperty()
返回该属性是否是对象的自身属性(非继承属性)
参数
属性 | 类型 | 含义 | 必填项 |
---|---|---|---|
prop | string | Symbol | 属性名 | 是 |
返回值
只要指定的属性是该对象的直接属性,无论何值,该方法都会返回true
。
如果指定的属性是继承的,或者没有该属性,则该方法返回 false
。
注意:
该方法为原型链方法,使用该方法的对象必须继承自
Object.prototype
,否则不能使用。所以在判断属性是否自身属性时,建议使用
Object.hasOwn()
4.Object.prototype.isPrototypeOf()
检查一个对象是否存在于另一个对象的原型链中
参数
属性 | 类型 | 含义 | 必填项 |
---|---|---|---|
prop | object | 需查找的对象 | 是 |
返回值
- 当入参是
undefined
或者null
时,直接报。 - 当入参是基本类型时直接返回
false
。 - 在传入参数的原型链中查找
this
的值,只到查找到该值或者查找到原型链的末端为止。
5.Object.prototype.propertyIsEnumerable()
返回该属性是否是对象的自身属性并且是可枚举属性
参数
属性 | 类型 | 含义 | 必填项 |
---|---|---|---|
prop | string | Symbol | 属性名 | 是 |
返回值
只要指定的属性是该对象的直接属性并且是可枚举属性,无论何值,该方法都会返回true
。
如果指定的属性是继承或者是非枚举属性,或者没有该属性,则该方法返回 false
。
js
for(key in obj) {
if(obj.hasOwnProperty(key)) {
// 可以在处获取到的key,返回值即为true
}
}
6.Object.prototype.valueOf()
JavaScript 调用 valueOf
方法来将对象转换成基本类型值。
强制数字类型转换 和强制基本类型转换 会优先调用该方法,而强制字符串转换 会优先调用 toString()
。
当对象被当作一个原始值使用时,这个方法会被自动调用。例如,当对象被用作数学运算的操作数时,或者在比较操作符(如 ==
或 ===
)中使用时。
- 获取对象的原始值 :
valueOf()
方法返回一个表示该对象的原始值。对于大多数对象,这个原始值就是对象本身(即,返回对象本身)。但是,对于某些内置对象(如日期、数字和字符串)和一些自定义对象,valueOf()
可以返回不同的值。 - 在类型转换中的使用 :当对象需要被转换为原始值(如数字、字符串或布尔值)时,JavaScript 会首先尝试调用对象的
valueOf()
方法。如果valueOf()
返回了一个原始值,那么这个值就会被用来进行后续的操作。 - 与
toString()
的协作 :如果valueOf()
没有返回原始值,JavaScript 会接着尝试调用对象的toString()
方法来获取原始值。
valueOf()
方法通常不需要显式调用,因为 JavaScript 会在需要的时候自动调用它。但是,你仍然可以在代码中显式调用这个方法。
下面是一些使用 valueOf()
的例子:
javascript
const obj = {
value: 10,
valueOf: function() {
return this.value;
}
};
// 当对象被用作数学运算的操作数时
const sum = obj + 5; // 调用 obj.valueOf() 获取原始值,然后进行加法运算
console.log(sum); // 输出 15
// 在比较操作中使用
const isEqual = obj === 10; // 调用 obj.valueOf() 获取原始值,然后进行比较
console.log(isEqual); // 输出 true
// 显式调用 valueOf()
const primitiveValue = obj.valueOf();
console.log(primitiveValue); // 输出 10
在这个例子中,我们创建了一个自定义对象 obj
,并覆盖了它的 valueOf()
方法,使其返回对象的 value
属性。当我们尝试将 obj
与另一个数字相加,或者将其与数字 10
进行比较时,JavaScript 会自动调用 obj.valueOf()
来获取一个原始值,然后进行相应的操作。
对于大多数普通的对象,valueOf()
默认返回对象本身,所以如果你没有覆盖这个方法,那么显式调用 obj.valueOf()
通常会返回对象本身。但是,对于内置对象(如日期、数字和字符串),valueOf()
会返回它们的原始值。例如,对于日期对象,valueOf()
返回自1970年1月1日00:00:00 UTC以来的毫秒数。
7.Object.prototype.toString()
JavaScript 调用 toString
方法将对象转换为一个原始值。
- 确定对象的类型 :
Object.prototype.toString()
返回一个字符串,这个字符串描述了调用它的对象的类型。 - 区分原生对象和用户自定义对象:由于这个方法返回的是对象的内部类型,因此可以用来区分原生对象(如数组、函数、日期等)和用户自定义对象。
- 避免
typeof
的局限性 :typeof
操作符在某些情况下可能无法准确判断对象的类型(例如,对于null
和数组),而Object.prototype.toString()
则可以提供更准确的结果。
使用 Object.prototype.toString()
很简单,只需要在需要确定类型的对象上调用这个方法即可。例如:
javascript
const obj = [];
console.log(Object.prototype.toString.call(obj)); // 输出 "[object Array]"
const func = function() {};
console.log(Object.prototype.toString.call(func)); // 输出 "[object Function]"
const date = new Date();
console.log(Object.prototype.toString.call(date)); // 输出 "[object Date]"
const nullValue = null;
console.log(Object.prototype.toString.call(nullValue)); // 输出 "[object Null]"
const objWithCustomPrototype = Object.create({});
console.log(Object.prototype.toString.call(objWithCustomPrototype)); // 输出 "[object Object]"
Object.prototype.toString()
返回一个字符串,这个字符串通常是 [object Type]
,其中 Type
是该对象的类型。
在自定义对象中此处的Type
默认为[object Object]
, 可以通过设置Symbol.toStringTag
属性来设置Type
js
const obj = {
a:1
}
console.log(Object.prototype.toString.call(obj)); // 输出 "[object Object]"
const newObj = {
a:1,
[Symbol.toStringTag]: "自定义Type"
}
console.log(Object.prototype.toString.call(obj)); // 输出 "[object 自定义Type]"
注意,如果你只是简单地调用 obj.toString()
(而不是 Object.prototype.toString.call(obj)
),那么可能会得到对象自己的字符串表示,而不是它的类型信息。因此,在使用 toString()
方法时,要确保你调用的是 Object.prototype.toString()
方法,而不是对象自己的 toString()
方法。
8.Object.prototype.toLocaleString()
相比于toString()
来说,toLocaleString()
的返回值会根据提供的地区设置(locale)而变化,并可能包含地区特定的格式和符号。而toString()
的返回值通常是一个更通用的、不依赖于地区设置的字符串表示。
- 如果自定义对象没有覆盖
toLocaleString()
方法,其默认行为通常是调用toString()
方法。
例如:21344543.23
转换成千分位形式21,344,543.23
js
const num = 21344543.23;
// 转换成英语,字符串
console.log(num.toLocalString('en-US')) // 21,344,543.23
22个静态方法
1.Object.assign()
将一个或者多个源对象 中所有可枚举 的自有属性复制到目标对象,并返回修改后的目标对象。
js
Object.assign(target, ...sources)
参数
属性 | 类型 | 含义 | 必填项 |
---|---|---|---|
target | Object | 需要应用源对象属性的目标对象,修改后将作为返回值 | 是 |
sources | Object | 一个或多个包含要应用的属性的源对象 | 是 |
返回值:修改后的目标对象
该方法是浅拷贝 对象,字符串
和 Symbol
类型属性都会被复制。
如果目标对象与源对象具有相同的属性,则目标对象中的属性将被源对象中的属性覆盖,后面的源对象的属性将类似地覆盖前面的源对象的同名属性。
js
const obj1 = {
a: 1,
};
const obj2 = {
a: 2,
};
const obj3 = {
a: 3,
};
console.log(Object.assign(obj1, obj2, obj3)); // { a: 3 }
console.log(Object.assign(obj1, obj2, obj3) === obj1); // true
2.Object.create()
用于创建一个新对象,并且这个新对象会使用现有的一个对象作为其原型。这就意味着新创建的对象会继承原型对象的所有属性和方法。
javascript
Object.create(proto, [propertiesObject])
参数
属性 | 类型 | 含义 | 必填项 |
---|---|---|---|
proto | Object|Null | 新创建对象的原型对象 | 是 |
propertiesObject | Object | 一个可选的对象,其自身的可枚举属性将被添加到新创建的对象上作为新创建对象的可枚举属性(与Object.defineProperties 第二个参数一致) |
否 |
Object.create()
的作用主要有两个:
- 创建一个新的空对象,并且这个新对象有指定的原型。
- 在新创建的对象上定义新的属性或方法。
javascript
let person = {
isHuman: false,
printIntroduction: function() {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
}
};
let me = Object.create(person);
me.name = "虫洞空间"; // "name" 是一个新属性
me.isHuman = true; // "isHuman" 覆盖了原型对象上的属性
me.printIntroduction();
// 输出:
// "My name is Matthew. Am I human? true"
3.Object.defineProperty()
用于直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。
js
Object.defineProperty(obj, prop, descriptor)
参数
属性 | 类型 | 含义 | 必填项 |
---|---|---|---|
obj | Object | 要在其上定义属性的对象 | 是 |
prop | String | 要定义或修改的属性的名称 | 是 |
descriptor | Object | 将被定义或修改的属性描述符 | 是 |
descriptor
:将被定义或修改的属性描述符。属性描述符是一个对象。
对象中存在两种属性描述符:数据描述符 和访问器描述符。数据描述符 是一个具有可写或不可写值的属性。访问器描述符 是由 getter/setter
函数对描述的属性。描述符只能是这两种类型之一,不能同时为两者。
-
configurable
:布尔值,当且仅当该属性的configurable
键值为true
时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为false
。 -
enumerable
:布尔值,表示目标属性是否可以被枚举。默认为false
。
数据描述符:
value
:设置属性的值。默认为undefined
。writable
:布尔值,表示属性值是否可以被重写。默认为false
。
访问器描述符:
get
:一个函数,用于获取属性的值。默认为undefined
。set
:一个函数,用于设置属性的值。默认为undefined
。
如果描述符没有 value
、writable
、get
和 set
键中的任何一个,那它就是数据描述符 。如果描述符同时具有 [value
或 writable
] 和 [get
或 set
] 键,则会抛出异常。
javascript
const obj = {};
// 使用 value 和 writable 属性
Object.defineProperty(obj, 'name', {
value: '虫洞空间',
writable: true
});
console.log(obj.name); // 输出 "虫洞空间"
obj.name = '虫洞空间'; // 由于 writable 为 true,所以可以修改属性值
console.log(obj.name); // 输出 "虫洞空间"
// 使用 get 和 set 方法
let age = 25;
Object.defineProperty(obj, 'age', {
get: function() {
return age;
},
set: function(newValue) {
age = newValue;
}
});
console.log(obj.age); // 输出 25
obj.age = 18; // 使用 set 方法设置新的属性值
console.log(obj.age); // 输出 18
注意:使用 Object.defineProperty() 方法定义的属性默认是不可枚举的,除非明确的将 enumerable
属性设置为 true
。
4.Object.defineProperties()
与 Object.defineProperty()
用法一致,唯一一点不同为: Object.defineProperty()
一次只能修改或添加一个属性,Object.defineProperties()
提供的是批量操作。
js
const obj = {};
let age = 25;
Object.defineProperties(obj, {
// 使用 value 和 writable 属性
name: {
value: "虫洞空间",
writable: true,
},
// 使用 get 和 set 方法
age: {
get: function () {
return age;
},
set: function (newValue) {
age = newValue;
},
},
});
console.log(obj.name); // 输出 "虫洞空间"
obj.name = "虫洞空间"; // 由于 writable 为 true,所以可以修改属性值
console.log(obj.name); // 输出 "虫洞空间"
console.log(obj.age); // 输出 25
obj.age = 18; // 使用 set 方法设置新的属性值
console.log(obj.age); // 输出 18
5.Object.getOwnPropertyDescriptor()
获取对象自身属性的描述符。这个描述符是一个对象。
javascript
Object.getOwnPropertyDescriptor(obj, prop)
属性 | 类型 | 含义 | 必填项 |
---|---|---|---|
obj | Object | 要在其中查找属性的对象 | 是 |
prop | String | 要检索其描述的属性的名称 | 是 |
返回值:
- 如果指定的属性存在于对象上,该方法将返回一个属性描述符对象,否则返回
undefined
。
javascript
const obj = {};
let age = 25;
Object.defineProperties(obj, {
// 使用 value 和 writable 属性
name: {
value: "虫洞空间",
writable: true,
},
// 使用 get 和 set 方法
age: {
get: function () {
return age;
},
set: function (newValue) {
age = newValue;
},
},
});
console.log(Object.getOwnPropertyDescriptor(obj, "name"));
// 输出:{ value: "虫洞空间", writable: true, enumerable: false, configurable: false }
console.log(Object.getOwnPropertyDescriptor(obj, "age"));
// 输出:{ enumerable: false, configurable: false,get: [Function: get], set: [Function: set] }
注意:Object.getOwnPropertyDescriptor() 只返回对象自身的属性描述符,不包括继承自原型链的属性。如果你想要获取一个对象所有属性(包括继承属性)的描述符,你可能需要使用其他方法,如递归遍历原型链。
6.Object.getOwnPropertyDescriptors()
返回所有自由属性的描述符。
javascript
Object.getOwnPropertyDescriptors(obj)
返回值:
- 该方法返回一个对象,该对象的键是原始对象的属性名,值是对应属性的描述符。如果对象没有任何自身的属性,它将返回一个空对象。
js
const obj = {};
let age = 25;
Object.defineProperties(obj, {
// 使用 value 和 writable 属性
name: {
value: "虫洞空间",
writable: true,
},
// 使用 get 和 set 方法
age: {
get: function () {
return age;
},
set: function (newValue) {
age = newValue;
},
},
});
console.log(Object.getOwnPropertyDescriptors(obj));
/* 输出:
{
name: {
value: '虫洞空间',
writable: true,
enumerable: false,
configurable: false
},
age: {
get: [Function: get],
set: [Function: set],
enumerable: false,
configurable: false
}
} */
注意:Object.getOwnPropertyDescriptors()
返回的是对象所有自身属性的描述符,包括不可枚举属性,但不会返回 Symbol
类型的属性。
7.Object.entries()
将指定对象自身自有的可枚举的属性和值转换为数组。
js
const obj = {
name: '虫洞空间',
age: 18
}
console.log(Object.entries(obj)); // [ [ 'name', '虫洞空间' ], [ 'age', 18 ] ]
8.Object.fromEntries()
与Object.entries()
相反,它是将键值对链表转换为对象
js
const arr = [
["name", "虫洞空间"],
["age", 18],
];
console.log(Object.fromEntries(arr)); // { name: '虫洞空间', age: 18 }
// 也可以将Map转换为对象
const map = new Map([
["name", "虫洞空间"],
["age", 18],
]);
console.log(Object.fromEntries(map)); // { name: '虫洞空间', age: 18 }
9.Object.getOwnPropertyNames()
获取指定对象的所有自身属性的属性名(包括不可枚举属性,但不包括以 Symbol 值作为名称的属性)。
javascript
Object.getOwnPropertyNames(obj)
obj
:要获取其所有自身属性名称的对象。
返回值:
- 返回一个包含对象所有自身属性名称的字符串数组。数组中枚举属性的顺序与通过
for...in
循环(或Object.keys
)迭代该对象属性时一致。数组中不可枚举属性的顺序未定义。
示例:
javascript
const obj = {
name: '虫洞空间',
age: 18,
};
// 使用 Object.defineProperty() 添加一个不可枚举属性
Object.defineProperty(obj, 'height', {
value: 180,
enumerable: false
});
const propertyNames = Object.getOwnPropertyNames(obj);
console.log(propertyNames); // 输出:["name", "age", "height"]
在这个例子中,Object.getOwnPropertyNames()
返回了包括不可枚举属性 height
在内的所有属性名称。
需要注意的是,Object.getOwnPropertyNames()
与 Object.keys()
不同。Object.keys()
只返回自身可枚举属性的键名字符串,而 Object.getOwnPropertyNames()
则返回自身所有属性的键名字符串,包括不可枚举的,但不包括以 Symbol 值作为名称的属性。
10.Object.getOwnPropertySymbols()
获取给定对象自身所有的 Symbol 属性。
javascript
Object.getOwnPropertySymbols(obj)
obj
:要检索其 Symbol 属性键的对象。
返回值:
- 返回一个数组,包含对象自身所有的 Symbol 属性键。如果对象没有 Symbol 属性,则返回一个空数组。
示例:
javascript
const obj = {
[Symbol('name')]: '虫洞空间',
[Symbol('age')]: 18
};
const symbols = Object.getOwnPropertySymbols(obj);
console.log(symbols);
// 输出:[Symbol(name), Symbol(age)]
console.log(symbols[0]); // 输出:Symbol(name)
console.log(symbols[1]); // 输出:Symbol(age)
console.log(obj[symbols[0]]); // 输出:"虫洞空间"
console.log(obj[symbols[1]]); // 输出:18
需要注意的是,Object.getOwnPropertySymbols()
只返回对象自身的 Symbol 属性键,不包括继承自原型链的属性。此外,常规的可枚举属性和不可枚举属性(使用字符串作为键名的属性)不会被包括在返回的数组中。
当你需要遍历对象的所有属性,包括那些使用非字符串键名的属性时,Object.getOwnPropertySymbols()
是非常有用的。结合 Object.getOwnPropertyNames()
或Object.keys()
,你可以获取到对象的所有属性,无论它们是使用字符串还是 Symbol 作为键名。
11.Object.keys()
获取一个对象的所有可枚举属性的键名。
javascript
Object.keys(obj)
obj
:要返回其可枚举属性键名的对象。
返回值:
- 返回一个包含对象所有可枚举属性键名的字符串数组。如果对象没有任何可枚举属性,则返回一个空数组。
javascript
const obj = {
name: '虫洞空间',
age: 18,
};
// 使用 Object.defineProperty() 添加一个不可枚举属性
Object.defineProperty(obj, 'height', {
value: 180,
enumerable: false
});
const keys = Object.keys(obj);
console.log(keys);
// 输出:["name", "age"]
需要注意的是,Object.keys()
只返回对象的可枚举属性。如果一个属性是通过 Object.defineProperty()
方法定义的,并且其 enumerable
属性被设置为 false
,那么这个属性将不会被 Object.keys()
返回。同时,Object.keys()
返回的是对象自身的可枚举属性,不包括从原型链上继承的属性。
Object.keys()
与Object.getOwnPropertyNames()
的区别在于Object.keys()
只能获取自身的可枚举属性 ,而Object.getOwnPropertyNames()
可以获取自身的所有属性。
12.Object.values()
获取对象自身所有可枚举属性值。
javascript
Object.values(obj)
obj
:要返回其可枚举属性值的对象。
返回值:
- 返回一个包含对象自身所有可枚举属性值的数组。如果对象没有可枚举的属性,则返回一个空数组。
javascript
const obj = {
name: '虫洞空间',
age: 18,
city: '北京'
};
const values = Object.values(obj);
console.log(values);
// 输出:["虫洞空间", 18, "北京"]
13.Object.hasOwn()
用于确定一个对象的属性是否是自身属性,而不是从原型链上继承的属性。
该方法提供了一种更简单的方式来检查对象的属性,与
Object.prototype.hasOwnProperty()
方法类似,但使用上更为简洁。在支持
Object.hasOwn
的浏览器中,建议使用Object.hasOwn()
,而非hasOwnProperty()
。
javascript
Object.hasOwn(obj, propName)
obj
:要检查的对象。propName
:要检查的属性名称。
属性 | 类型 | 含义 | 必填项 |
---|---|---|---|
obj | Object | 要在其中查找属性的对象 | 是 |
propName | String|Symbol | 要检索其描述的属性的名称 | 是 |
返回值:
- 如果对象
obj
拥有名为propName
的属性(即该属性是其自身的属性,而非继承的属性),则返回true
。 - 如果对象
obj
不拥有名为propName
的属性,则返回false
。
示例:
javascript
const obj = {
prop1: 'value1',
prop2: 'value2'
};
console.log(Object.hasOwn(obj, 'prop1')); // 输出:true
console.log(Object.hasOwn(obj, 'prop2')); // 输出:true
console.log(Object.hasOwn(obj, 'prop3')); // 输出:false
// 创建一个没有原型的对象
const objNoProto = Object.create(null);
objNoProto.prop1 = 'value1';
console.log(objNoProto.hasOwnProperty('prop1')); // 报错,因为 objNoProto 没有继承 Object.prototype
console.log(Object.hasOwn(objNoProto, 'prop1')); // 输出:true
在这个例子中,Object.hasOwn()
方法正确地判断了 obj
对象是否拥有 prop1
和 prop2
属性,并且对于没有继承 Object.prototype
的 objNoProto
对象也能正常工作,而 hasOwnProperty()
在这种情况下会报错。
Object.hasOwn()
方法在处理不继承 Object.prototype
的对象时不会报错,这是它的一个优点,相比 hasOwnProperty()
提供了更好的兼容性。
14.Object.is()
比较两个值是否相等。
javascript
Object.is(value1, value2)
value1
和value2
是要进行比较的两个值。
返回值:
- 如果
value1
和value2
严格相等,则返回true
;否则返回false
。
它的行为与严格相等运算符**(===
)**几乎相同,但在以下特殊情况时表现不同:
+0
和-0
不相等:虽然+0
和-0
在数值上都是零,Object.is()
会认为它们不相等。NaN
等于自身:在 JavaScript 中,NaN
)与任何值(包括其自身)比较都会返回false
,但Object.is()
认为NaN
等于其自身。
javascript
console.log(Object.is(0, -0)); // false
console.log(Object.is(-0, -0)); // true
console.log(Object.is(NaN, NaN)); // true
需要注意的是,Object.is()
是ES6中引入的方法,用于提供更准确的相等性比较。在 ES5 及之前的版本中,我们通常使用 ===
运算符来进行严格相等性比较,但在一些些特殊情况下(如 +0
和 -0
,以及 NaN
的比较)可能需要额外的逻辑来处理。Object.is()
方法的引入用来解决这种问题。
15.Object.getPrototypeOf()
获取指定对象的原型 ( 即内部 [[Prototype]]
属性的值 )。
javascript
Object.getPrototypeOf(obj)
obj
:要获取其原型对象的对象。
返回值:
- 返回对象的原型对象。如果对象没有原型(即该对象是
null
),则返回null
。 - **注意:**在 ES5 中,如果
obj
参数不是对象,则会抛出TypeError
异常。在 ES2015 中,该参数将被强制转换为Object
。
javascript
const person = {
isHuman: false,
printIntroduction: function() {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
}
};
const me = Object.create(person);
me.name = 'Matthew'; // "name" 是 "me" 的一个属性
me.isHuman = true; // "isHuman" 是从原型 "person" 继承的属性
const proto = Object.getPrototypeOf(me);
console.log(proto === person); // 输出: true
Object.getPrototypeOf("foo");
// TypeError: "foo" is not an object (ES5 code)
Object.getPrototypeOf("foo");
// String.prototype (ES2015 code)
在这个例子中,me
对象是通过 Object.create(person)
创建的,因此 person
是 me
的原型。通过 Object.getPrototypeOf(me)
,我们可以得到 me
的原型对象 person
。
需要注意的是,Object.getPrototypeOf()
只能用于普通对象。对于函数对象,它返回的是函数的原型对象,而不是构造函数本身。如果你想获取一个对象的构造函数,可以使用 Object.constructor
属性。
16.Object.setPrototypeOf()
将一个指定对象的原型(即内部的 [[Prototype]]
属性)设置为另一个对象或者 null
。
javascript
Object.setPrototypeOf(obj, prototype)
obj
:要设置原型的目标对象。prototype
:新的原型对象。
返回值:
- 返回被设置原型的目标对象。
javascript
const person = {
isHuman: false,
printIntroduction: function() {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
}
};
const me = {
name: '虫洞空间'
};
// 使用 Object.setPrototypeOf() 设置 me 的原型为 person
Object.setPrototypeOf(me, person);
// 现在 me 继承了 person 的属性和方法
me.isHuman = true;
console.log(me.printIntroduction());
// 输出: "My name is 虫洞空间. Am I human? true"
console.log(me instanceof person); // 输出: true
注意: 在需要修改对象的原型时,应使用
Object.setPrototypeOf()
, 不应该使用Object.prototype.__proto__
17.Object.freeze()
使一个对象被冻结 。冻结对象可以防止扩展,并使现有的属性不可写入和不可配置。被冻结的对象不能再被更改:不能添加新的属性,不能移除现有的属性,不能更改它们的可枚举性、可配置性、可写性或值,对象的原型也不能被重新指定。
javascript
Object.freeze(obj)
obj
:要冻结的对象。
返回值:
- 返回被冻结的对象。
js
const obj = {
name: '虫洞空间',
age: 18
};
// 冻结对象
Object.freeze(obj);
// 尝试修改对象的属性
obj.age = 20; // 这行代码不会有任何效果
console.log(obj.age); // 输出: 18
// 尝试添加新的属性
obj.gender = 'male'; // 这行代码也不会有任何效果
console.log(obj.gender); // 输出: undefined
// 尝试删除属性
delete obj.name; // 这行代码同样不会有任何效果
console.log(obj.name); // 输出: 虫洞空间
冻结一个对象就是使其不可扩展,即现有属性不可删除,不可添加新的属性;此对象下的所有现有属性的描述符的 configurable
特性更改为 false
;数据属性把 writable
特性更改为 false
。
需要注意的是,Object.freeze()
只影响对象本身的属性,不会递归地冻结对象内部的子对象。如果对象包含可写的子对象,那么这些子对象仍然可以被修改,所以Object.freeze()
是浅冻结。
既然是浅冻结,那么我们自己来实现一个深冻结
js
function deepFreeze(object) {
// 如果对象已经冻结,直接返回
if (Object.isFrozen(object)) {
return object;
}
// 获取对象的属性名
const propNames = Reflect.ownKeys(object);
// 冻结自身前先冻结属性
for (const name of propNames) {
const value = object[name];
if ((value && typeof value === "object") || typeof value === "function") {
deepFreeze(value);
}
}
return Object.freeze(object);
}
const obj2 = {
internal: {
a: null,
},
};
deepFreeze(obj2);
obj2.internal.a = "anotherValue"; // 非严格模式下会静默失败
obj2.internal.a; // null
18.Object.isFrozen()
判断一个对象是否被冻结。
javascript
Object.isFrozen(obj)
obj
:要检测的对象。
返回值:
- 如果对象被冻结,返回
true
。 - 如果对象没有被冻结,返回
false
。 - 一个对象,当且仅当它不可拓展,且所有属性都是不可配置的,所有的数据属性(即不是有 getter 或 setter 的访问器属性的属性)都是不可写的时,它就是被冻结的。
19.Object.preventExtensions()
防止一个对象添加新的属性,防止对象被重新指定原型。
一旦对象被 Object.preventExtensions()
处理,任何尝试添加新属性的操作都将失败,并且不会抛出错误。但是,这并不影响修改现有属性的值或删除已有属性(如果属性是可配置的)。
该方法还使对象的 [[Prototype]]
不可变;任何重新赋值 [[Prototype]]
操作都会抛出 TypeError
。这种行为只针对内部的 [[Prototype]]
属性,目标对象的其他属性将保持可变。
javascript
Object.preventExtensions(obj)
obj
:要防止扩展的对象。
返回值:
- 返回被处理的对象。
javascript
const obj = {
property1: 'Hello'
};
// 防止对象扩展
Object.preventExtensions(obj);
// 尝试添加新属性
obj.newProperty = 'World'; // 操作无效,但不会抛出错误
console.log(obj.newProperty); // 输出: undefined,新属性没有被添加
console.log(obj.property1); // 输出: Hello
// 尝试删除已有属性
delete obj.property1; // 如果属性是可配置的,可以删除;否则,删除操作无效
console.log(obj.property1); // 如果属性没有被删除,输出: Hello;否则,输出: undefined
// 检测对象是否可扩展
const isExtensible = Object.isExtensible(obj);
console.log(isExtensible); // 输出: false
20.Object.isExtensible()
判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)
javascript
Object.isExtensible(obj)
obj
:要检查扩展性的对象。
返回值:
- 如果对象可扩展,返回
true
。 - 如果对象不可扩展,返回
false
。
js
const obj = { a: 1 };
Object.preventExtensions(obj);
console.log(Object.isExtensible(obj)); // false
const obj1 = { a: 2 };
Object.freeze(obj1);
console.log(Object.isExtensible(obj1)); // false
const obj2 = { a: 3 };
Object.seal(obj2);
console.log(Object.isExtensible(obj2)); // false
21.Object.seal()
密封 一个对象。密封一个对象会阻止其扩展 并且使得现有属性不可配置 。密封对象有一组固定的属性:不能添加新属性、不能删除现有属性或更改其可枚举性和可配置性、不能重新分配其原型。只要现有属性的值是可写的,它们仍然可以更改。
Object.seal()
是 JavaScript 中的一个方法,用于密封一个对象。密封一个对象意味着这个对象不能再添加新的属性,同时已有的属性也不能被删除。但是,已存在的属性仍然可以被修改(如果它们是可写的)。
javascript
Object.seal(obj)
obj
:要密封的对象。
返回值:
- 返回被密封的对象。
javascript
const obj = {
property1: 'Hello',
property2: 'World'
};
// 密封对象
Object.seal(obj);
// 尝试添加新属性
obj.newProperty = 'New'; // 操作无效,但不会抛出错误
// 尝试删除已有属性
delete obj.property1; // 操作无效,属性不会被删除
// 尝试修改已有属性
obj.property2 = 'New World'; // 如果属性是可写的,可以修改
console.log(obj.newProperty); // 输出: undefined,新属性没有被添加
console.log(obj.property1); // 输出: Hello,属性没有被删除
console.log(obj.property2); // 输出: New World,如果之前是可写的,则属性被修改
// 检测对象是否密封
const isSealed = Object.isSealed(obj);
console.log(isSealed); // 输出: true
这里的密封依然是一个浅密封。
这里要说一下它与Object.freeze()
的区别,通过 Object.seal()
密封的对象可以更改其现有属性,只要它们是可写的;通过Object.freeze()
冻结的对象,是不可以更改现有属性的。
22.Object.isSealed()
判断一个对象是否被密封。
javascript
Object.isSealed(obj)
obj
:要检查的对象。
返回值:
- 如果对象是密封的,返回
true
。 - 如果对象不是密封的,返回
false
。
密封对象是指那些不可扩展的,且所有自有属性都不可配置且因此不可删除(但不一定是不可写)的对象。
所以冻结对象一定是密封对象。