對(duì)象屬性
一、屬性類型
ECMAScript 中有數(shù)據(jù)屬性和訪問(wèn)器屬性兩種屬性,各有 4 個(gè)描述其行為的特征,其中兩種屬性都有的特性是:
- [[configurable]] 默認(rèn)為 true,能否刪除屬性、修改屬性特征、修改屬性類型
- [[enumerable]] 默認(rèn)為 true,是否可枚舉,即被 for-in 循環(huán)、Object.keys 等遍歷到
數(shù)據(jù)屬性 同時(shí)可具有:
- [[value]] 默認(rèn)為 undefined,數(shù)據(jù)值
- [[writable]] 默認(rèn)為 true,能否修改屬性的值
訪問(wèn)器屬性同時(shí)可具有:
- [[get]] 默認(rèn)為 undefined,讀取屬性時(shí)調(diào)用的 getter 函數(shù)
- [[set]] 默認(rèn)為 undefined,讀取屬性時(shí)調(diào)用的 setter 函數(shù)
需要注意的是,數(shù)據(jù)屬性和訪問(wèn)器屬性不能同時(shí)存在
可以是用 Object.defineProperty或者Object.defineProperties來(lái)修改對(duì)象的屬性,在使用這兩個(gè)函數(shù)的時(shí)候,如果不指定,configurable、enumerable、writable的默認(rèn)值都為 false
原型
實(shí)例.__proto__ === 原型
原型.constructor === 構(gòu)造函數(shù)
構(gòu)造函數(shù).prototype === 原型
原型鏈
每個(gè)對(duì)象都有 __proto__ 屬性,指向了創(chuàng)建該對(duì)象的構(gòu)造函數(shù)的原型,__proto__將對(duì)象連接起來(lái)組成了原型鏈,原型鏈可以用于實(shí)現(xiàn)繼承和共享屬性
繼承
一、原型鏈繼承
- 優(yōu)點(diǎn):簡(jiǎn)單
- 缺點(diǎn):多個(gè)實(shí)例共享引用類型的屬性
function Parent(age) {
this.names = []
this.age = age
}
Parent.prototype.foo = () => {}
function Child() {}
Child.prototype = new Parent()
var child1 = new Child(5)
var child2 = new Child(6)
child1.names.push(1)
child2.names.push(2)
二、構(gòu)造函數(shù)
- 優(yōu)點(diǎn):
1.不共享引用類型的屬性
2.可傳參 - 缺點(diǎn):
1.每次創(chuàng)建實(shí)例都會(huì)重新創(chuàng)建一遍方法,函數(shù)沒(méi)有復(fù)用
2.不屬于原型鏈的一環(huán),子類實(shí)例不能使用父類的方法
function Parent(age) {
this.names = []
this.age = age
this.foo = function () {}
}
function Child(age) {
Parent.call(this, age)
}
var child = new Child(11)
三、組合繼承
- 優(yōu)點(diǎn):
1.原型鏈確保了函數(shù)復(fù)用
2.構(gòu)造函數(shù)實(shí)現(xiàn)了對(duì)實(shí)例屬性的繼承 - 缺點(diǎn):
1.調(diào)用了兩次父類構(gòu)造函數(shù)
function Parent(age) {
this.name = 'Bill'
this.age = age
}
Parent.prototype.foo = function () {}
function Child(age) {
Parent.call(this, age) //第二次調(diào)用構(gòu)造函數(shù)
}
Child.prototype = new Parent() //第一次調(diào)用構(gòu)造函數(shù)
Child.prototype.constructor = Child
var child = new Child(11)
四、原型式繼承
與原型鏈類似
- 優(yōu)點(diǎn):簡(jiǎn)單
- 缺點(diǎn):多個(gè)實(shí)例共享引用類型的屬性
const objectCreate = (o) => {
// 就是Object.create 靜態(tài)方法的實(shí)現(xiàn)
// 實(shí)際上只是對(duì) o 進(jìn)行了淺拷貝
function F() {}
F.prototype = o
return new F()
}
五、寄生式繼承
與借用構(gòu)造函數(shù)類似
- 缺點(diǎn):每次創(chuàng)建實(shí)例都會(huì)重新創(chuàng)建一遍方法,函數(shù)沒(méi)有復(fù)用
function create(o) {
var f = Object.create(o)
f.foo = function() {}
return f
}
六、寄生組合式繼承
主要是改進(jìn)了組合繼承需要調(diào)用兩次構(gòu)造函數(shù)的缺點(diǎn)
function object(o) {
function F() {}
F.prototype = o
return new F()
}
// 這里代替了用來(lái) 組合式繼承 第一次調(diào)用構(gòu)造函數(shù)
// 將父類的原型進(jìn)行一次淺拷貝
// 并將這個(gè)淺拷貝的對(duì)像作為原型鏈接到子類
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype)
prototype.constructor = subType
subType.prototype = prototype
}
function SuperType(name) {
this.name = name
this.colors = ['red', 'blue']
}
SuperType.prototype.sayName = function() {
alert(this.name)
}
function SubType(name, age) {
SuperType.call(this, name)
this.age = age
}
SubType.prototype.sayAge = function() {
alert(this.age)
}
inheritPrototype(SubType, SuperType)