公司做網(wǎng)站 優(yōu)幫云國(guó)外免費(fèi)建站網(wǎng)站搭建
文章目錄
- 一、原型
- 1、prototype
- 2、constructor
- 二、原型鏈
- 1、字面量原型鏈
- 2、字面量繼承
- 3、構(gòu)造函數(shù)的原型鏈
- 4、Object.create
- 5、Object.setPrototypeOf
- 三、繼承
- 1、構(gòu)造函數(shù)繼承
- 2、原型鏈繼承
- 3、組合繼承
- 四、常見鏈條
- 1、Function
- 2、Object.prototype
繼承是指將特性從父代傳遞給子代,以便新代碼可以重用并基于現(xiàn)有代碼的特性進(jìn)行構(gòu)建。JavaScript 使用對(duì)象實(shí)現(xiàn)繼承。每個(gè)對(duì)象都有一條鏈接到另一個(gè)稱作原型的對(duì)象的內(nèi)部鏈。該原型對(duì)象有自己的原型,依此類推,直到原型是 null 的對(duì)象。
一、原型
1、prototype
- 構(gòu)造函數(shù)自帶原型對(duì)象
prototype
,可以在prototype增加屬性和方法,這樣構(gòu)造函數(shù)產(chǎn)生的實(shí)例可以共享這些屬性和方法(如果實(shí)例上沒有的話)- 實(shí)例
__proto__
屬性指向最近的上級(jí)prototype(如果有繼承),如果沒有繼承那么指向構(gòu)造函數(shù)的prototype;__proto__在瀏覽器上顯示的是[[Prototype]]
- 注意原型對(duì)象prototype也是對(duì)象,他是被Object創(chuàng)建出來的
const ParentFun = function () {this.name = "張三";
};
ParentFun.prototype.getName = function () {return this.name;
};
const parentObj = new ParentFun();
parentObj.__proto__ === ParentFun.prototype // true
2、constructor
constructor
其實(shí)依賴于prototype,只是prototype上的一個(gè)屬性,指向構(gòu)造函數(shù)本身(函數(shù)對(duì)象,函數(shù)也可以被認(rèn)為是一個(gè)對(duì)象,可以掛載屬性和方法)- 在原型鏈繼承的時(shí)候,錯(cuò)誤操作可能只顧著繼承prototype,而丟失constructor屬性
instanceof
: a instanceof b會(huì)在鏈條往上查找prototype.constructor,看a的原型鏈上有沒有b;逐級(jí)上查
const ParentFun = function () {this.name = "張三";
};
ParentFun.prototype.constructor === ParentFun // true
// 等同于;因?yàn)镻arentFunObj默認(rèn)往上查找一層就是ParentFun.prototype
ParentFunObj.constructor === ParentFun // trueconst ParentFunObj = new ParentFun();
ParentFunObj instanceof ParentFun // true
ParentFunObj instanceof Object // true
二、原型鏈
1、字面量原型鏈
- 注意對(duì)象中設(shè)置字面量{ proto: … },是被允許的、合理的;不合理是設(shè)置隱式原型obj.proto = …
const obj = {a: 1,// __proto__ 設(shè)置了 [[Prototype]]。在這里它被指定為另一個(gè)對(duì)象字面量。__proto__: {b: 2,__proto__: {c: 3,},},
};
obj.a // 1
obj.b // 2
obj.c // 3
2、字面量繼承
const parent = {value: 2,method() {return this.value + 1;}
};// child 是一個(gè)繼承了 parent 的對(duì)象
const child = {__proto__: parent
};console.log(child.method()); // 3// child ---> parent ---> Object.prototype ---> null
3、構(gòu)造函數(shù)的原型鏈
function Constructor() {}const obj = new Constructor();// obj ---> Constructor.prototype ---> Object.prototype ---> null
4、Object.create
const a = { a: 1 };
// a ---> Object.prototype ---> nullconst b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1(繼承的)
5、Object.setPrototypeOf
const obj = { a: 1 };
const anotherObj = { b: 2 };
Object.setPrototypeOf(obj, anotherObj);
// obj ---> anotherObj ---> Object.prototype ---> null
三、繼承
1、構(gòu)造函數(shù)繼承
- call、apply都可以
- 也可以使用class,本文案例未舉例
const ParentFun = function () {this.name = "張三";
};
const ChildFun = function () {// 繼承父類的屬性和方法;構(gòu)造函數(shù)繼承;// 注意調(diào)用的時(shí)機(jī),會(huì)決定實(shí)例的屬性順序;比如這里的name屬性在age前面ParentFun.call(this);// 運(yùn)行時(shí)this指向childFunc實(shí)例對(duì)象(的內(nèi)存空間);this.age = 20;
};
2、原型鏈繼承
Object.setPrototypeOf(ChildFun.prototype, ParentFun.prototype)
:給目標(biāo)設(shè)置原型鏈的上一級(jí);Object.setPrototypeOf(ChildFun.prototype)
:獲取該目標(biāo)的原型鏈的上一級(jí)Object.create(ParentFun.prototype)
:創(chuàng)建和返回新對(duì)象,設(shè)置該對(duì)象的原型鏈上一級(jí)- 原型鏈擴(kuò)充,每次擴(kuò)充都會(huì)形成上級(jí)和下級(jí)的二元鏈;鏈條可以被設(shè)置成連續(xù)不斷一直到頂層null,也可以設(shè)置成短鏈
const ParentFun = function () {this.name = "張三";
};
const ChildFun = function () {// 繼承父類的屬性和方法;構(gòu)造函數(shù)繼承;// 注意調(diào)用的時(shí)機(jī),會(huì)決定實(shí)例的屬性順序;比如這里的name屬性在age前面ParentFun.call(this);// 運(yùn)行時(shí)this指向childFunc實(shí)例對(duì)象(的內(nèi)存空間);this.age = 20;
};
ParentFun.prototype.getName = function () {return this.name;
};
ChildFun.prototype.getAge = function () {return this.age;
};const transferTemp = (Parent, Child) => {// 空的對(duì)象作為臨時(shí)原型鏈;const Temp = () => {};Temp.prototype = Parent.prototype;Child.prototype = new Temp();Child.prototype.constructor = Child;
};const transferCreat = (Parent, Child) => {// Object.create本身就會(huì)返回一個(gè)空對(duì)象,該對(duì)象的__proto__指向Parent.prototype;Child.prototype = Object.create(Parent.prototype);// 覆蓋prototype以后會(huì)丟失constructor,需要重新賦值;// constructor在一些判斷中可能被用到// prototype在此之前設(shè)置的其他屬性也會(huì)消失(比如getAge)Child.prototype.constructor = Child;
};// 注意原型鏈繼承方式的區(qū)別
// 1
// ChildFun.prototype = new ParentFun();
// 2 廢棄但可用;__proto__ 賦值只會(huì)接受對(duì)象,其他值會(huì)被忽略
// ChildFun.prototype.__proto__ = ParentFun.prototype;
// 3 推薦 安全有效,沒有中轉(zhuǎn)對(duì)象
// Object.setPrototypeOf(ChildFun.prototype, ParentFun.prototype);
// 4 使用中轉(zhuǎn)對(duì)象
// transferTemp(ParentFun, ChildFun);
// 5 使用中轉(zhuǎn)對(duì)象
// transferCreat(ParentFun, ChildFun);
3、組合繼承
const ParentFun = function () {this.name = "張三";
};
const ChildFun = function () {// 繼承父類的屬性和方法;構(gòu)造函數(shù)繼承;// 注意調(diào)用的時(shí)機(jī),會(huì)決定實(shí)例的屬性順序;比如這里的name屬性在age前面ParentFun.call(this);// 運(yùn)行時(shí)this指向childFunc實(shí)例對(duì)象(的內(nèi)存空間);this.age = 20;
};
ParentFun.prototype.getName = function () {return this.name;
};
ChildFun.prototype.getAge = function () {return this.age;
};// 自定義Object.keys方法 用于獲取對(duì)象所有屬性名
Object.prototype.keysCustom = function (obj) {if (typeof obj !== "object" || obj === null) {return;}const result = []; // 用于存儲(chǔ)結(jié)果for (let key in obj) {// hasOwnProperty表示自身的屬性,不包括原型鏈上的屬性if (obj.hasOwnProperty(key)) {// 相當(dāng)于循環(huán)后存儲(chǔ)keyresult.push(key);}}return result;
};Object.setPrototypeOf(ChildFun.prototype, ParentFun.prototype);const childObj = new ChildFun();const keysAll = [];
const keysOwn = [];
for (let key in childObj) {// 自己的屬性和原型鏈上的屬性都會(huì)遍歷出來;// 原型鏈繼承的所有屬性 + Object.prototype 掛載的自定義方法keysAll.push(key);if (childObj.hasOwnProperty(key)) {// 自己的屬性才會(huì)遍歷出來;keysOwn.push(key);}
}
// console.log("Object.keysCustom", keysAll, keysOwn, childObj); // TEST
// 結(jié)果:keysAll = ["name", "age", "getName", "keysCustom"];
// 結(jié)果: keysOwn = ["name", "age"];// childObj ---> ChildFun.prototype ---> ParentFun.prototype ---> Object.prototype ---> null
四、常見鏈條
1、Function
- Function是所有常見構(gòu)造函數(shù)的源頭,甚至他自己也被自己創(chuàng)造
- 只要是構(gòu)造函數(shù)都?xì)wFunction管理,包括自定義的函數(shù)
// Function創(chuàng)造自己
Object.getPrototypeOf(Function) === Function.prototype // true
// 常規(guī)構(gòu)造函數(shù)
Object.getPrototypeOf(Object) === Function.prototype // true
Object.getPrototypeOf(Array) === Function.prototype // true
// 自定義構(gòu)造函數(shù)
const temp =() => {}
Object.getPrototypeOf(temp) === Function.prototype // true
2、Object.prototype
- 只要是對(duì)象都?xì)wObject管理,包括prototype對(duì)象,當(dāng)然有例外:Object.prototype
// 常規(guī)構(gòu)造函數(shù)的prototype;上一級(jí)就是Object.prototype
Object.getPrototypeOf(Function.prototype) === Object.prototype // true
Object.getPrototypeOf(Array.prototype) === Object.prototype // true
// 鏈條頂層被null強(qiáng)制了
Object.getPrototypeOf(Object.prototype) === Object.prototype // false
Object.getPrototypeOf(Object.prototype) === null // true