# 属性的可枚举性
对象属性有可枚举和不可枚举之分,主要影响到以下操作。
- for...in 遍历对象的可枚举属性,包括原型链上的属性
- Object.keys() 遍历对象自身的可枚举属性
- Object.entries() 返回对象自身可枚举属性键值对数组(二维数组)
- JSON.stringfy() 仅读取并序列号对象自身的可枚举属性
如何判断属性是否可枚举?
- Object.prototype.propertyIsEnumerable() 仅可用来判断对象自身属性是否可枚举
- Object.getOwnPropertyDescriptor()获取对象自身属性的描述符,查看描述符的enumerable属性
# 不可扩展对象、密封对象、冻结对象区别
# 不可扩展对象
Object.preventExtensions Object.isExtensible
仅限制对象是否能够新增属性,不限制属性的修改和删除。
# 密封对象
Object.seal Object.isSealed
限制对象不可新增或删除属性,可以修改自身属性,但不可修改configurable和enumerable属性。
# 冻结对象
Object.freeze Object.isFrozen
限制对象的一切属性的增删与修改。 一个冻结对象是密封对象,更是不可扩展对象。
# Object方法一览
创建
- 1 Object
- 2 Object.create
- 3 Object.fromEntries
修改
- 4 Object.assign
- 5 Object.defineProperty
- 6 Object.defineProperties
- 7 Object.setPrototypeOf
- 8 Object.freeze
- 9 Object.seal
- 10 Object.preventExtensions
遍历
- 11 Object.keys
- 12 Object.values
- 13 Object.entries
判断
- 14 Object.is
- 15 Object.isFrozen
- 16 Object.isSealed
- 17 Object.isExtensible
- 18 Object.prototype.hasOwnProperty
- 19 Object.prototype.isPrototypeOf
- 20 Object.prototype.propertyIsEnumerable
查询
- 21 Object.getPrototypeOf
- 22 Object.getOwnPropertyNames
- 23 Object.getOwnPropertySymbols
- 24 Object.getOwnPropertyDescriptor
- 25 Object.getOwnPropertyDescriptors
- 26 Object.prototype.valueOf
- 27 Object.prototype.toString
# 1. Object构造函数
传入不同类型的返回值
// 1.传入引用类型,返回其值本身
// {a:'a', b:'b'}
const obj = {a:'a', b:'b'}
const o1 = new Object(obj);
obj === o1; // true
// [1,2,3]
const o2 = new Object([1,2,3]);
// 2.传入null 、undefined返回空对象
// {}
const o3 = new Object(null);
const o4 = new Object(undefined);
// 3.传入基础类型,返回其包装类型的对象
// [String: '123']
const o5 = new Object('123');
// [Number: 1]
const o6 = new Object(1);
o6 === 1;// false
// [Bollean: true]
const o7 = new Object(true);
# 2.Object.create
以一个对象(第一参数)作为原型,创建一个实例对象,该对象包含(第二参数的)属性。 使用场景:继承
const p = {
nickName: "alan",
sayHi: function () {
console.log("i am " + this.nickName);
},
};
const obj = Object.create(p, {
age: {
writable: true,
configurable: true,
enumerable: true,
value: "22",
},
logInfo: {
writable: true,
configurable: true,
enumerable: true,
value: function() {
console.log("age:"+this.age);
}
},
});
obj.sayHi();// i am alan
obj.logInfo();// age:22
obj.__proto__ === p; // true
const obj = Object.create(func.prototype);
//相当于
const obj = {};
obj.__proto__ = func.prototype;
# 3. Object.fromEntries()
与entries相反,它将键值对列表转为对象。
const entriesArr = [['a','1'],['b','2'],['c','3']];
const obj = Object.fromEntries(entriesArr);
//{ a: '1', b: '2', c: '3' }
// 可用于Map转对象,如 Object.fromEntries(aMap)
# 4. Object.assign
浅复制某对象上的属性到目标对象上 (第二参数复制属性到第一参数)
const o = {};
const obj = {
a:'a',
arr:[1,2,3,4]
}
Object.assign(o, obj);
obj.a = 'b';
obj.arr[1] = 0;
o// { a:'a', arr: [1,0,2,4] }
# 5. Object.defineProperty
为某对象(第一参数), 定义一个属性(第二参数属性名), 该属性的遵循描述符约定(第三参数)
描述符主要有两种形式:
数据描述符 value 属性值,默认undefined
configurable 描述符除value和writable外的属性是否可改变,默认false
enumerable 属性是否可枚举,默认false
writable 属性是否能被'='重新赋值,默认false
存储描述符
configurable、enumerable可选
get 访问属性时会调用getter函数。
set 属性值被修改时调用setter函数。
注意,存储描述符使用value、writable是无意义的。
由此可见此类定义属性的方式,与'='赋值的理念有所不同,后者默认都是可枚举的。通过此类方式,可以定义不被枚举的属性。
const obj = {};
Object.defineProperty(obj, 'nickName', {
value:'Alex',
configurable: true,
enumerable: true,
writable: true
})
// 等价于 obj.nickName = '22';
Object.defineProperty(obj, 'age', {
configurable: false,
enumerable: true,
get: function () {
return '22';
},
set: function(){
console.log("set value");
}
});
obj; // { nickName: 'Alex', age: [Getter/Setter] }
以上只是defineProperty的简单使用,详见文章
# 6. Object.defineProperties
跟defineProperty类似,该方法能一次处理多个属性。
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
// etc. etc.
});
# 7. Object.setPrototypeOf
设置对象新的原型
function A(){}
function B(){}
const a = new A();
console.log(a.__proto__);// A{}
console.log(Object.getPrototypeOf(a));// A{}
Object.setPrototypeOf(a, B.prototype);
console.log(a.__proto__);// B{}
console.log(Object.getPrototypeOf(a));// B{}
# 8~10 Object.freeze()
浅冻结对象或数组,使其属性不能增删改; 判断是否冻结Object.isFrozen();
注意: 一个冻结的对象, 也是一个密封对象(seal、isSealed) 更是一个不可扩展对象(preventExtensions、isExtensible)
递归实现深冻结。
// 深冻结函数.
function deepFreeze(obj) {
// 取回定义在obj上的属性名
var propNames = Object.getOwnPropertyNames(obj);
// 在冻结自身之前冻结属性
propNames.forEach(function(name) {
var prop = obj[name];
// 如果prop是个对象,冻结它
if (typeof prop == 'object' && prop !== null)
deepFreeze(prop);
});
// 冻结自身(no-op if already frozen)
return Object.freeze(obj);
}
# 11. Object.keys()
返回自身可枚举属性的属性名列表。
const obj = {
a: '1',
b: '2',
c: '3'
}
Object.defineProperty(obj, 'd', {
value:'4',
enumerlable: false
})
Object.keys(obj);// [ 'a', 'b', 'c' ]
# 12. Object.values()
返回自身可枚举属性的值列表。
const obj = {
a: '1',
b: '2',
c: '3'
}
Object.defineProperty(obj, 'd', {
value:'4',
enumerlable: false
})
Object.values(obj);// [ '1', '2', '3' ]
# 13. Object.entries()
返回对象自身可枚举属性的键值对列表(二维数组) “entry: 条目”
const obj = {
a: '1',
b: '2',
c: '3'
}
const entriesArr = Object.entries(obj);
// [ [ 'a', '1' ], [ 'b', '2' ], [ 'c', '3' ] ]
// 接下来可以进行for...of遍历,转Map结构等操作
# 14. Object.is()
判断两个值是否相等,不会像==一样会发生隐式转换,与===很相似,但也不全是。
console.log(Object.is(1,1));// true
console.log(Object.is(1,'1'));// false
# 18. Object.prototype.hasOwnProperty()
查询对象自身是否存在该属性
const obj = {
a: "a",
hasOwnProperty: function () {
return false;
},
};
obj.hasOwnProperty("a");// false
//这种方式可以避免访问obj篡改的方法
Object.prototype.hasOwnProperty.call(obj, "a");// true
# 19. Object.prototype.isPrototypeOf
A.isPrototypeOf(B) A对象是否在B对象的原型链上。
注意:跟instanceof有点像,不过instanceof需要A走一步prototype,再判断是否在B的原型链上,所以有
A.prototype.isPrototypeOf(B)
等同于
B instanceof A
function A() {}
function B() {}
function C() {}
B.prototype = Object.create(A.prototype);// B继承A
C.prototype = Object.create(B.prototype);// C继承B
const c = new C();
// C.prototype是否存在实例c的原型链上
console.log(C.prototype.isPrototypeOf(c));// true
console.log(c instanceof C);// 同理,true,C走一步prototype,踏在c的原型链上
// B.prototype是否存在实例c的原型链上
console.log(B.prototype.isPrototypeOf(c));// true
console.log(c instanceof B);// 同理,true,B走一步prototype,踏在c的原型链上
// A.prototype是否存在实例c的原型链上
console.log(A.prototype.isPrototypeOf(c));// true
console.log(c instanceof A);// 同理,true,A走一步prototype,踏在c的原型链上
// Object.prototype是否存在实例c的原型链上
console.log(Object.prototype.isPrototypeOf(c));// true
console.log(c instanceof Object);// 同理,true,Object走一步prototype,踏在c的原型链上
# 20. Object.prototype.propertyIsEnumerable()
查询对象属性是否可枚举。
const obj = {a:'a'};
obj.propertyIsEnumerable('a');// true
# 21. Object.getPrototypeOf()
获取实例对象的__proto__,即构造函数的prototype
function Person(nickName){
this.nickName = nickName;
}
const p = new Person('Alice');
console.log(p.__proto__ === Person.prototype);// true
console.log(Object.getPrototypeOf(p) === Person.prototype);// true
console.log(Object.getPrototypeOf(Person));// [Function]
# 22. Object.getOwnPropertyNames()
获取对象自身属性的属性名列表。 (包括可枚举与不可枚举) (不包括Symbol)
const obj = { a: "1", b: "2", c: "3" };
// 包括不可枚举属性
Object.defineProperty(obj, 'd', {
value: '4',
enumerable: false
});
// 不包括symbol属性
obj[Symbol()] = '5';
const propNameList = Object.getOwnPropertyNames(obj);
// [ 'a', 'b', 'c', 'd' ]
# 23. Object.getOwnPropertySymbols()
获取对象自身属性的Symbol属性名列表。
const obj = {};
obj[Symbol('a')] = '1';
obj[Symbol('b')] = '2';
obj.c = '3';
const symbolList = Object.getOwnPropertySymbols(obj);
//[ Symbol(a), Symbol(b) ]
# 24~25 Object.getOwnPropertyDescriptor
获取对象上自身属性的描述符。Object.getOwnPropertyDescriptors批量处理多个属性。
const obj = {
a: '1',
b: '2'
}
const descriptor = Object.getOwnPropertyDescriptor(obj, 'a');
//{ value: '1', writable: true, enumerable: true, configurable: true }
const descriptors = Object.getOwnPropertyDescriptors(obj);
// {
// a: { value: '1', writable: true, enumerable: true, configurable: true },
// b: { value: '2', writable: true, enumerable:}
// }
# 26. Object.prototype.toString()
返回对象的字符串表示。与、toLocaleString()方法与其功能一样。
# 27. Object.prototype.valueOf()
获取对象转换的原始值。 (原始值不一定是原始类型,也可以是引用类型,对象的原始值就是本身,数组的原始值也是本身)
某些隐式转换会先考虑valueOf(),再考虑toString(),直到返回原始类型。
← 事件委托 与 处理大量节点插入 严格模式 →