由于現代 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)) // 只拷貝自身的可枚舉屬