您好,登錄后才能下訂單哦!
這篇文章主要介紹Javascript的原型和原型鏈?zhǔn)鞘裁匆馑?,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
想要介紹原型,就不得不提為什么我們要使用原型,在js早期,我們創(chuàng)建一個(gè)對(duì)象,比較流行的做法是使用對(duì)象字面量去創(chuàng)建一個(gè)對(duì)象,例如:
const person = { name: "wywy", age: 21, hobby: "聽周杰倫" }
用這種方式去創(chuàng)建對(duì)象,雖然簡(jiǎn)潔明了,但是我們?nèi)绻枰笈康膭?chuàng)建這一類的對(duì)象,就像person這個(gè)對(duì)象,我們可能需要去創(chuàng)建多個(gè)不同的人,那么每一次都需要去聲明創(chuàng)建,這樣工作量是巨大的,為了解決這個(gè)問題我們引入了工廠函數(shù)的概念。
什么是工廠函數(shù),顧名思義就可以把工廠函數(shù)看作是一個(gè)流水線的工廠,這個(gè)工廠的作用就是批量生產(chǎn)person對(duì)象,就像下面這樣:
function createPerson(name,age,hobby){ const obj = {}; obj.name = name; obj.age = age; obj.hobby = hobby; return obj; } const person1 = createPerson("zs", 23, "滑板"); const person2 = createPerson("ls", 22, "聽歌"); console.log(person1); console.log(person2);
function CreatePerson(name, age, hobby) { this.name = name; this.age = age; this.hobby = hobby; } const person1 = new CreatePerson("zs", 23, "滑板"); const person2 = new CreatePerson("ls", 22, "聽歌"); console.log(person1); console.log(person2);
function CreatePerson(name, age, hobby) { this.name = name; this.age = age; this.hobby = hobby; // 添加一個(gè)方法 this.sayHi = function() { console.log("你好,我叫" + this.name) } } const person1 = new CreatePerson("zs", 23, "滑板"); const person2 = new CreatePerson("ls", 22, "聽歌"); console.log(person1); console.log(person2);
但是我們發(fā)現(xiàn)這樣做無疑為每一個(gè)實(shí)例對(duì)象都添加了一個(gè) sayHi 方法,而且每個(gè)實(shí)例上的方法都不相等,但我們的目的是讓每個(gè)實(shí)例都有這么一個(gè)功能就好了,不必創(chuàng)建這么多的 sayHi 方法而去浪費(fèi)內(nèi)存空間。說的直白一點(diǎn),比如家里有五個(gè)孩子,每個(gè)孩子都想玩 switch 游戲,那么家長(zhǎng)要給每個(gè)孩子買一臺(tái) switch 嗎?當(dāng)然家里有礦的當(dāng)我沒說,一般家庭是不是就買一臺(tái),然后哪個(gè)孩子想玩就管家長(zhǎng)去要就行了是不是。
同樣的,代碼就是對(duì)現(xiàn)實(shí)生活的抽象,那么我們是不是也可以這樣做,把方法添加到這些實(shí)例都擁有的一個(gè)爸爸是不是就好了,而仔細(xì)想想在 new 的五步中第二步是不是做了這么一件事,沒錯(cuò)他就是 js 中的原型。這個(gè)原型就是這些實(shí)例的爸爸。
說了這么多我們總算要講原形了!!!
通過上面的講解我們似乎對(duì)原型的作用有了大致的理解,就是把實(shí)例對(duì)象上需要用到的共有方法添加到原型上,而實(shí)例對(duì)象的自己的私有屬性寫在構(gòu)造函數(shù)內(nèi)部。
接下來我們對(duì)構(gòu)造函數(shù)進(jìn)行再一次改造:
function CreatePerson(name, age, hobby) { this.name = name; this.age = age; this.hobby = hobby; // 添加一個(gè)方法 this.sayHi = function() { console.log("你好,我叫" + this.name) } } const person1 = new CreatePerson("zs", 23, "滑板"); const person2 = new CreatePerson("ls", 22, "聽歌"); console.log(person1); console.log(person2);
首先向大家說明一點(diǎn)我并沒有按著定義一個(gè)構(gòu)造函數(shù),然后在構(gòu)造函數(shù)的原型上添加 sayHi 方法,接著使用 new 創(chuàng)建實(shí)例的順序來寫代碼。而是先 new 創(chuàng)建了實(shí)例,然后再在原型上添加方法,這樣的目的是想告訴大家,原型是具有動(dòng)態(tài)性的,即你先創(chuàng)建了實(shí)例,在實(shí)例之后給原型添加了方法那么實(shí)例依然是可以訪問的。而且可以看到通過比較 person1 和 person2 的 sayHi 方法我們發(fā)現(xiàn)這是同一個(gè)方法。這樣我們完美的解決了構(gòu)造函數(shù)的問題。
首先清楚兩個(gè)概念:
引用類型,都具有對(duì)象特性,即可自由擴(kuò)展屬性。(引用類型:Object、Array、Function、Date、RegExp)
每個(gè)函數(shù)
function都有一個(gè)顯示原型prototype
,每個(gè)實(shí)例對(duì)象
都有一個(gè)隱式原型__proto__
function Fn() { // 內(nèi)部語(yǔ)句:this.prototype = {} } // 1、每個(gè)函數(shù)function都有一個(gè)prototype,即顯示原型(屬性) console.log(Fn.prototype); // 2、每個(gè)實(shí)例對(duì)象都有一個(gè)__proto__,可稱為隱式原型(屬性) var fn = new Fn(); // 內(nèi)部語(yǔ)句: this.__proto__ = Fn.prototype console.log(fn.__proto__);
兩個(gè)準(zhǔn)則:
在設(shè)計(jì)js原型原型鏈的時(shí)候遵循以下兩個(gè)準(zhǔn)則:
準(zhǔn)則一: 原型對(duì)象(即Fn.prototype)的 constructor 指向構(gòu)造函數(shù)本身。
準(zhǔn)則二: 實(shí)例對(duì)象(即 fn )的__proto__ 指向其構(gòu)造函數(shù)的顯示原型。
function Fn() {} var fn = new Fn(); // 原型對(duì)象的 constructor 指向構(gòu)造函數(shù)本身 console.log(Fn.prototype.constructor === Fn); // true // 對(duì)象的隱式原型的值為其對(duì)應(yīng)構(gòu)造函數(shù)的顯示原型的值 console.log(Fn.prototype === fn.__proto__); // true
理解Function與Object特例
每個(gè)函數(shù)都是 Function 的實(shí)例,所以每個(gè)函數(shù)既有顯示原型又有隱式原型,所有函數(shù)的隱式原型指向 Function.prototype; 構(gòu)造器Function的構(gòu)造器是它自身。
// function Foo() {} 相當(dāng)于 var Foo = new Function() // Function = new Function() => Function.__proto__ = Function.prototype // Object 作為構(gòu)造函數(shù)時(shí),其 __proto__ 內(nèi)部屬性值指向 Function.prototype // Object.__proto__ = Function.prototype // Function.constructor=== Function;//true
Object構(gòu)造函數(shù)創(chuàng)建一個(gè)對(duì)象包裝器。JavaScript中的所有對(duì)象都來自 Object,所有對(duì)象都是Object的實(shí)例;所有對(duì)象從Object.prototype繼承方法和屬性,盡管它們可能被覆蓋。
// Fn的原型對(duì)象(Fn.prototype)也來自O(shè)bject,故Fn.prototype.__proto__ = Object.prototype function Fn() {}
原型鏈:
讀取某個(gè)對(duì)象的屬性時(shí),會(huì)自動(dòng)找到原型鏈中查找。
1、現(xiàn)在自身屬性中查找,找到返回
2、找不到則繼續(xù)沿著__proto__這條鏈向上查找,找到返回
3、如果最終沒有找到。返回undefined設(shè)置對(duì)象的屬性值時(shí),不會(huì)查找原型鏈,如果當(dāng)前對(duì)象中沒有此屬性,直接添加此屬性并設(shè)置其值方法一般定義在原型中,屬性一般通過構(gòu)造函數(shù)定義在對(duì)象本身
原型鏈就是一個(gè)過程,原型是原型鏈這個(gè)過程中的一個(gè)單位,貫穿整個(gè)原型鏈
圖解
//練習(xí)題1 function A(){ } A.prototype.n = 1; var b = new A(); A.prototype = { n:2, m:3 } var c = new A(); console.log(b.n,b.m,c.n,c.m) // 1 undefined 2 3
// 測(cè)試題2 var F = function() { }; Object.prototype.a = function() { console.log('a()'); }; Function.prototype.b = function() { console.log('b()'); }; var f = new F(); f.a(); // a() f.b(); // 報(bào)錯(cuò):Uncaught TypeError: f.b is not a function F.a(); // a() F.b(); // b()
原型、原型鏈的意義與使用場(chǎng)景:
原型對(duì)象的作用,是用來存放實(shí)例中共有的那部分屬性、方法、可以大大減少內(nèi)存消耗。
以上是“Javascript的原型和原型鏈?zhǔn)鞘裁匆馑肌边@篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。