摘要:相當(dāng)于在用原型繼承編寫復(fù)雜代碼前理解原型繼承模型十分重要。同時(shí),還要清楚代碼中原型鏈的長(zhǎng)度,并在必要時(shí)結(jié)束原型鏈,以避免可能存在的性能問題。
至于繼承,js的繼承與java這種傳統(tǒng)的繼承不一樣.js是基于原型鏈的繼承.
在javascript里面,每個(gè)對(duì)象都有一個(gè)prototype屬性,指向它的原型對(duì)象.這個(gè)原型對(duì)象里面同時(shí)還有自己的原型,原型一環(huán)扣一環(huán),直到某個(gè)對(duì)象的原型為null,這一級(jí)一級(jí)的鏈結(jié)構(gòu)就是原型結(jié)構(gòu).
js的原型鏈繼承
繼承屬性
js屬性查找:由于js原型鏈的存在,當(dāng)查找一個(gè)對(duì)象屬性時(shí)候,不只是在對(duì)象上查找,還會(huì)沿著該js對(duì)象的原型鏈往上查找,知道找到一個(gè)匹配的屬性或者查找到原型鏈末尾.當(dāng)然如果js對(duì)象上與其原型的對(duì)象上都有同名的屬性,我們遵循該屬性的作用域就近原則(術(shù)語(yǔ)叫做"屬性遮蔽").
var Ele = function(){ this.a = 1; this.b = 2; } var Obj = function(){ this.c = 3; this.b = 4; } Ele.prototype = new Obj(); var ele1 = new Ele(); console.log(ele1.a);//1 console.log(ele1.b);// 2 console.log(ele1.c);// 3 console.log(ele1.d);//undefined
繼承方法
在 JavaScript 里,任何函數(shù)都可以添加到對(duì)象上作為對(duì)象的屬性/方法。函數(shù)的繼承與其他的屬性繼承沒有差別,包括上面的“屬性遮蔽”(這種情況相當(dāng)于其他語(yǔ)言(java)的方法重寫)。
var student= { age : 20, name: "cp", sayhi : function(){ console.log("hi"); } } var s1 = Object.create(student); //一種創(chuàng)建對(duì)象的方法,后面會(huì)寫博客介紹.s1.prototype是student s1.name = "kobe"; console.log( s1.name ); // "kobe" console.log( s1.age ); // 20 console.log( s1.sayhi() ); // hi
多種方法創(chuàng)建對(duì)象及生產(chǎn)原型鏈
普通對(duì)象字面量創(chuàng)建對(duì)象
var o = { a: 1 }; console.log(o.hasOwnProperty("a")); //true // o這個(gè)對(duì)象繼承了Object.prototype上面的所有屬性 // 所以可以這樣使用 o.hasOwnProperty("a").判斷一個(gè)對(duì)象是否還有一個(gè)屬性 // hasOwnProperty 是Object.prototype的自身屬性。 // Object.prototype的原型為null。 // 原型鏈如下: // o ---> Object.prototype ---> null var a = ["yo", "whadup", "?"]; // 數(shù)組的實(shí)例對(duì)象都繼承于Array.prototype // (indexOf, forEach等方法都是從它繼承而來(lái)). // 原型鏈如下: // a ---> Array.prototype ---> Object.prototype ---> null function f(){ return 2; } // 函數(shù)都繼承于Function.prototype // (call, bind等方法都是從它繼承而來(lái)): // f ---> Function.prototype ---> Object.prototype ---> null - 使用構(gòu)造函數(shù)(構(gòu)造器)創(chuàng)建對(duì)象 `function Student() { this.job = "讀書"; this.tag = "年輕"; } function BoyStudent() { this.sex = "boy"; } BoyStudent.prototype = new Student(); var xiaoMing = new BoyStudent(); console.log(xiaoMing.sex); //boy console.log(xiaoMing.tag); //年輕 // xiaoMing是生成的對(duì)象,他的自身屬性有"sex". // 在BoyStudent被實(shí)例化時(shí),BoyStudent.[[Prototype]]指向了Student.prototype.
使用Object.create()創(chuàng)建對(duì)象,新對(duì)象的原型就是調(diào)用 create 方法時(shí)傳入的第一個(gè)參數(shù):
var a = {a: 1}; // a ---> Object.prototype ---> null var b = Object.create(a); // b ---> a ---> Object.prototype ---> null console.log(b.a); // 1 (繼承而來(lái)) var c = Object.create(b); // c ---> b ---> a ---> Object.prototype ---> null var d = Object.create(null); // d ---> null console.log(d.hasOwnProperty); // undefined, 因?yàn)閐沒有繼承Object.prototype
使用 class 關(guān)鍵字
ECMAScript6 引入了一套新的關(guān)鍵字用來(lái)實(shí)現(xiàn) class。使用基于類語(yǔ)言的開發(fā)人員會(huì)對(duì)這些結(jié)構(gòu)感到熟悉,但它們是不一樣的。 JavaScript 仍然是基于原型的,這點(diǎn)一直不變。這些新的關(guān)鍵字包括 class, constructor, static, extends, 和 super.(跟java的關(guān)鍵字一樣,構(gòu)造器,靜態(tài),繼承,超類)
"use strict"; //類 Person class Person(){ constructor(name , age){ this.name = name; this.age = age; }; } // 類Girl繼承Person class Girl extends Person(){ constructor(name , age){ super(name , age); } getinfo(){ return this.name + "," + this.age; } } var girl = new Girl("kobe",20);
原型繼承的性能
在原型鏈上查找屬性比較耗時(shí),對(duì)性能有副作用,盡量避免,這在性能要求苛刻的情況下很重要。另外,訪問不存在的屬性時(shí)會(huì)遍歷整個(gè)原型鏈,浪費(fèi)資源。
遍歷對(duì)象的屬性時(shí),原型鏈上的每個(gè)可枚舉屬性都會(huì)被枚舉出來(lái)。
檢測(cè)對(duì)象的屬性是定義在自身上還是在原型鏈上,有必要使用 hasOwnProperty 方法,所有繼承自 Object.proptotype 的對(duì)象都包含這個(gè)方法,返回布爾值,是 JavaScript 中唯一一個(gè)只涉及對(duì)象自身屬性而不會(huì)遍歷原型鏈的方法。
注意:僅僅通過判斷值是否為 undefined 還不足以檢測(cè)一個(gè)屬性是否存在,一個(gè)屬性可能存在而其值恰好為 undefined。
關(guān)于原生對(duì)象的原型擴(kuò)展
理論上我們不應(yīng)該去擴(kuò)展Object.prototype,或者其他內(nèi)置對(duì)象的原型,像Array.prototype等。
我們?nèi)U(kuò)展內(nèi)置對(duì)象原型的唯一理由是引入新的 JavaScript 引擎的某些新特性,比如 Array.forEach。
理解prototype與Object.getPrototypeOf區(qū)別
function A(a){ this.varA = a; } // 以上函數(shù) A 的定義中,既然 A.prototype.varA 總是會(huì)被 this.varA 遮蔽, // 那么將 varA 加入到原型(prototype)中的目的是什么? A.prototype = { varA : null, // 既然它沒有任何作用,干嘛不將 varA 從原型(prototype)去掉? // 也許作為一種在隱藏類中優(yōu)化分配空間的考慮? // https://developers.google.com/speed/articles/optimizing-javascript#Initializing instance variables // 將會(huì)驗(yàn)證如果 varA 在每個(gè)實(shí)例不被特別初始化會(huì)是什么情況。 doSomething : function(){ // ... } }
當(dāng)你 var a1 = new A();js內(nèi)部就會(huì)設(shè)置a1.[[prototype]] == A.prototype .
如果你再 var a2 = new A();那么 a1.doSomething 事實(shí)上會(huì)指向Object.getPrototypeOf(a1).doSomething,
它就是你在 A.prototype.doSomething 中定義的內(nèi)容。
比如:Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething。
prototype 是用于類型的,而 Object.getPrototypeOf() 是用于實(shí)例的(instances),兩者功能一致。
var Fx = function(){}; var fx = new Fx();
相當(dāng)于
var fx = new Object(); fx[[prototype]] = Fx.prototype; Fx.call(fx);
在用原型繼承編寫復(fù)雜代碼前理解原型繼承模型十分重要。同時(shí),還要清楚代碼中原型鏈的長(zhǎng)度,并在必要時(shí)結(jié)束原型鏈,以避免可能存在的性能問題。此外,除非為了兼容新 JavaScript 特性,否則,永遠(yuǎn)不要擴(kuò)展原生的對(duì)象原型。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/80968.html
摘要:原型對(duì)象是由創(chuàng)建的,因此原型對(duì)象的構(gòu)造函數(shù)是構(gòu)造函數(shù)也可以是稱為對(duì)象,原型對(duì)象也就繼承了其生父構(gòu)造函數(shù)中的數(shù)據(jù),也同時(shí)繼承了原型對(duì)象的數(shù)據(jù)。當(dāng)然這條原型鏈中的數(shù)據(jù),會(huì)被還是還是這類構(gòu)造函數(shù)繼承,但是不會(huì)被這些繼承,他們不處于同一個(gè)鏈條上。 js中,F(xiàn)unction的本質(zhì)是什么?Object的本質(zhì)又是什么?js中有幾條原型鏈? showImg(https://segmentfault.c...
摘要:是完全的面向?qū)ο笳Z(yǔ)言,它們通過類的形式組織函數(shù)和變量,使之不能脫離對(duì)象存在。而在基于原型的面向?qū)ο蠓绞街?,?duì)象則是依靠構(gòu)造器利用原型構(gòu)造出來(lái)的。 JavaScript 函數(shù)式腳本語(yǔ)言特性以及其看似隨意的編寫風(fēng)格,導(dǎo)致長(zhǎng)期以來(lái)人們對(duì)這一門語(yǔ)言的誤解,即認(rèn)為 JavaScript 不是一門面向?qū)ο蟮恼Z(yǔ)言,或者只是部分具備一些面向?qū)ο蟮奶卣鳌1疚膶⒒貧w面向?qū)ο蟊疽?,從?duì)語(yǔ)言感悟的角度闡述為什...
摘要:創(chuàng)建自定義的構(gòu)造函數(shù)之后,其原型對(duì)象只會(huì)取得屬性,其他方法都是從繼承來(lái)的。優(yōu)缺點(diǎn)寄生式繼承在主要考慮對(duì)象而不是創(chuàng)建自定義類型和構(gòu)造函數(shù)時(shí),是十分有用的。 原文鏈接:https://kongchenglc.coding.me... 1.原型鏈 ??js的繼承機(jī)制不同于傳統(tǒng)的面向?qū)ο笳Z(yǔ)言,采用原型鏈實(shí)現(xiàn)繼承,基本思想是利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。理解原型鏈必須先理...
摘要:原型鏈與繼承當(dāng)談到繼承時(shí),只有一種結(jié)構(gòu)對(duì)象。如果對(duì)該圖不怎么理解,不要著急,繼續(xù)往下看基于原型鏈的繼承對(duì)象是動(dòng)態(tài)的屬性包指其自己的屬性。當(dāng)使用操作符來(lái)作用這個(gè)函數(shù)時(shí),它就可以被稱為構(gòu)造方法構(gòu)造函數(shù)。 原型鏈與繼承 當(dāng)談到繼承時(shí),JavaScript 只有一種結(jié)構(gòu):對(duì)象。每個(gè)實(shí)例對(duì)象(object )都有一個(gè)私有屬性(稱之為proto)指向它的原型對(duì)象(prototype)。該原型對(duì)象也...
摘要:對(duì)象詳解對(duì)象深度剖析,深度理解對(duì)象這算是醞釀很久的一篇文章了。用空構(gòu)造函數(shù)設(shè)置類名每個(gè)對(duì)象都共享相同屬性每個(gè)對(duì)象共享一個(gè)方法版本,省內(nèi)存。 js對(duì)象詳解(JavaScript對(duì)象深度剖析,深度理解js對(duì)象) 這算是醞釀很久的一篇文章了。 JavaScript作為一個(gè)基于對(duì)象(沒有類的概念)的語(yǔ)言,從入門到精通到放棄一直會(huì)被對(duì)象這個(gè)問題圍繞。 平時(shí)發(fā)的文章基本都是開發(fā)中遇到的問題和對(duì)...
閱讀 2415·2021-10-14 09:43
閱讀 2444·2021-09-09 09:34
閱讀 1608·2019-08-30 12:57
閱讀 1208·2019-08-29 14:16
閱讀 728·2019-08-26 12:13
閱讀 3209·2019-08-26 11:45
閱讀 2292·2019-08-23 16:18
閱讀 2670·2019-08-23 15:27