2021.04.27(方法的 name 属性、属性的可枚举性和遍历)
方法的 name 属性
函数的 name 属性,返回函数名。对象方法也是函数,因此也有 name 属性。
1. const person = { 2. sayName() { 3. console.log('hello!'); 4. }, 5. }; 6. 7. person.sayName.name // "sayName"
上面代码中,方法的 name 属性返回函数名(即方法名)。
如果对象的方法使用了取值函数( getter )和存值函数( setter ),则 name 属性不是在该
方法上面,而是该方法的属性的描述对象的 get 和 set 属性上面,返回值是方法名前加
上 get 和 set 。
1. const obj = { 2. get foo() {}, 3. set foo(x) {} 4. }; 5. 6. obj.foo.name 7. // TypeError: Cannot read property 'name' of undefined 8. 9. const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo'); 10. 11. descriptor.get.name // "get foo" 12. descriptor.set.name // "set foo"
有两种特殊情况: bind 方法创造的函数, name 属性返回 bound 加上原函数的名
字; Function 构造函数创造的函数, name 属性返回 anonymous 。
1. (new Function()).name // "anonymous" 2. 3. var doSomething = function() { 4. // ... 5. }; 6. doSomething.bind().name // "bound doSomething"
如果对象的方法是一个 Symbol 值,那么 name 属性返回的是这个 Symbol 值的描述。
1. const key1 = Symbol('description'); 2. const key2 = Symbol(); 3. let obj = { 4. [key1]() {}, 5. [key2]() {}, 6. }; 7. obj[key1].name // "[description]" 8. obj[key2].name // ""
上面代码中, key1 对应的 Symbol 值有描述, key2 没有。
属性的可枚举性和遍历
可枚举性
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行
为。 Object.getOwnPropertyDescriptor 方法可以获取该属性的描述对象。
1. let obj = { foo: 123 }; 2. Object.getOwnPropertyDescriptor(obj, 'foo') 3. // { 4. // value: 123, 5. // writable: true, 6. // enumerable: true, 7. // configurable: true 8. // }
描述对象的 enumerable 属性,称为“可枚举性”,如果该属性为 false ,就表示某些操作会忽略
当前属性。
目前,有四个操作会忽略 enumerable 为 false 的属性。
for...in 循环:只遍历对象自身的和继承的可枚举的属性。
Object.keys() :返回对象自身的所有可枚举的属性的键名。
JSON.stringify() :只串行化对象自身的可枚举的属性。
Object.assign() : 忽略 enumerable 为 false 的属性,只拷贝对象自身的可枚举的属性。
1. Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable 2. // false 3. 4. Object.getOwnPropertyDescriptor([], 'length').enumerable 5. // false
上面代码中, toString 和 length 属性的 enumerable 都是 false ,因此 for...in 不会
遍历到这两个继承自原型的属性。
另外,ES6 规定,所有 Class 的原型的方法都是不可枚举的。
1. Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable 2. // false
总的来说,操作中引入继承的属性会让问题复杂化,大多数时候,我们只关心对象自身的属性。所以,
尽量不要用 for...in 循环,而用 Object.keys() 代替。
属性的遍历
ES6 一共有 5 种方法可以遍历对象的属性。
(1)for…in
for...in 循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
(2)Object.keys(obj)
Object.keys 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属
性)的键名。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames 返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但
是包括不可枚举属性)的键名。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols 返回一个数组,包含对象自身的所有 Symbol 属性的键名。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys 返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol
或字符串,也不管是否可枚举。
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
首先遍历所有数值键,按照数值升序排列。
其次遍历所有字符串键,按照加入时间升序排列。
最后遍历所有 Symbol 键,按照加入时间升序排列。
1. Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 }) 2. // ['2', '10', 'b', 'a', Symbol()]
上面代码中, Reflect.ownKeys 方法返回一个数组,包含了参数对象的所有属性。这个数组的属性次序是这样的,首先是数值属性 2 和 10 ,其次是字符串属性 b 和 a ,最后是 Symbol 属
性。
2021-04-27 15:13:35