由于现代 JavaScript 引擎优化属性访问所带来的特性的关系,更改对象的 [[Prototype]]即__proto__在各个浏览器和 JavaScript 引擎上都是一个很慢的操作。
一 Object原型方法
1 Object.setPrototypeOf(obj, proto)
- 用该方法而不是直接修改__proto__
- 返回值是设置好原型的obj,即第一个参数
- 若第一个参数不是对象,则该操作没有效果,将第一个参数构造函数的原型作为obj的原型
const n = new Number(1)
console.log(n)
console.log(Object.getPrototypeOf(n))
const obj = Object.setPrototypeOf(1, { a: 100 })
console.log(obj)
console.log(Object.getPrototypeOf(obj)) // 查看原型是否设置上
- 若第一个参数是undefined/null(没有包装类),则报错
2 Object.getPrototypeOf()
- 当参数是原始值,则返回其包装类构造函数的原型
3 Object.keys()
- 返回可枚举属性,不含继承属性
- for in可以拿到继承的属性
4 Object.values()
- 返回可枚举属性值
5 Object.entries()
const obj = { a: 1 }
Object.defineProperties(obj, {b: {value: 2,enumerable: true},c: {value: 3}
})
const p = { d: 4 }
Object.setPrototypeOf(obj, p)
console.log(obj)
console.log('keys', Object.keys(obj))
console.log('values', Object.values(obj))
console.log('entries', Object.entries(obj))
super
- 指向对象的原型对象
- 使用限制:必须是对象的方法,且是简写时才能访问到super
let proto = {y: 20,z: 40
}
let obj = {x: 10,foo() {console.log(super.y)}
}
Object.setPrototypeOf(obj, proto)
obj.foo() // 20
Symbol
- 解决对象属性重名的问题
- 是原始值类型
- Symbol是构造函数,new会报错
- 生成独一无二的值
- typeof返回
symbol
- 挂不上属性
包装类是这么挂属性么
let s1 = Symbol()
s1.a = 1;
console.log(s1.a) // undefined
console.log(Symbol()) // Symbol()
console.log(Symbol(undefined)) // Symbol()
console.log(Symbol(null)) // Symbol(null)
console.log(Symbol(1)) // Symbol(1)
console.log(Symbol(true)) // Symbol(true)
console.log(Symbol('1')) // Symbol(1)
console.log(Symbol({})) // Symbol([object Object])
console.log(Symbol(function () { })) // Symbol(function(){})
console.log(Symbol([])) // Symbol()
console.log(Symbol([1, 2, 3])) // Symbol(1,2,3)
console.log(String(Symbol('字符串'))) // Symbol(字符串)
console.log(Boolean(Symbol(1))) // true
console.log(Boolean(Symbol(null))) // true 注意为false的就6种
const s1 = Symbol()
console.log(Object.getPrototypeOf(s1)) // Symbol.prototype
// Cannot convert a Symbol value to a number
console.log(Number(Symbol(1))) // 报错
console.log(Symbol() + 1) // 报错
很明显,生成Symbol时,在括号内使用了对应变量的toString方法,数组、对象、方法的返回值各不相同
- Symbol有自己的toString方法
- 显式转换只有Number不能转,Boolean、String可以
- 隐式转换仅限Boolean
Symbol作为对象属性
- obj[s1] = xx
- const obj = { [s1]: xxx }
- Object.defineProperty(obj, s1, { value: xxx })
Symbol方法
- Symbol.for(‘foo’)获取到同样的Symbol值
- 传相同的key
- Symbol.keyFor(s1)获取到用Symbol.for指定的key值
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1 === s2) // true
console.log(Symbol.keyFor(s1)) // foo
const s22 = Symbol()
const s3 = Symbol(null)
const s4 = Symbol(1)
console.log(Symbol.keyFor(s22)) // undefined 他们都没有用Symbol.for指定key
console.log(Symbol.keyFor(s3)) // undefined
console.log(Symbol.keyFor(s4)) // undefined
Symbol属性遍历
- for in不能遍历到Symbol类型的属性
- for of不能遍历到Symbol类型的属性
- 特有的api
Object.getOwnPropertySymbols(obj)
仅遍历obj的Symbol类型的属性
for…in语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性(包括继承)。
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
在给定对象自身上找到的所有 Symbol 属性的数组。(和枚举无关)
const obj = { c: 1, d: 2 }
let a = Symbol('a')
let b = Symbol('b')
let _a = Symbol('_a')
let _b = Symbol('_b')
obj[a] = 'hello'
obj[b] = 'world'
Object.defineProperties(obj, {e: {value: 5,enumerable: true,},f: {value: 6,enumerable: false,},[_a]: {value: -1,enumerable: true,},[_b]: {value: -2,enumerable: false,},
})
let h = Symbol('h')
let i = Symbol('i')
let j = Symbol('j')const obj1 = {g: 7,[h]: 8
}
Object.defineProperties(obj1, {[i]: {value: 9,enumerable: true,},[j]: {value: 10,},k: {value: 11}
})
Object.setPrototypeOf(obj, obj1)
console.log(obj)
for (let i in obj) {console.log(i) // c d e g
}
console.log(Object.keys(obj)) // ["c", "d", "e"]
console.log(Object.getOwnPropertySymbols(obj))
// [Symbol(a), Symbol(b), Symbol(_a), Symbol(_b)]
console.log(Object.assign(obj)) // 只拷贝自身的可枚举属