摘要:構(gòu)造函數(shù)自身屬性是直接賦值給它的所有,也就是說本身的屬性,不管是直接類型還是引用類型都是分別復(fù)制一份給和,因此修改了的屬性并不會影響到。
最基本的構(gòu)造函數(shù)與實例的關(guān)系:
var Sub = function (color,list) { this.color = color; this.list = list } var sub1 = new Sub("red",[1]); var sub2 = new Sub("green",[2]); sub1.color = "new"; alert(sub1.color);//"new" alert(sub2.color);//"green",說明了sub2.color不會被sub1影響 sub1.list.push(4); alert(sub1.list);//[1,4] alert(sub2.list);//[2],說明引用類型array仍然不會被sub1影響
可以看出構(gòu)造函數(shù)自身的屬性(無論直接類型還是引用類型),都是賦值一份copy給它的所有instance,因此每一個instance 的修改互相不影響。我們繼續(xù)看:
自身屬性和prototype屬性的區(qū)別:
var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10]; //創(chuàng)建Super的instance:①super1;②我們可以把Sub.prototype看成是Super的instance。 var super1 = new Super("red",[1,1,1,1]); var Sub = function () {}; Sub.prototype = new Super("green",[1]);//到這里我們可以看成 Sub.prototype和super1都是Super的instance var sub1 = new Sub(); var sub2 = new Sub(); //修改Super的`自身屬性` Sub.prototype.list.push(4);//不影響兄弟(super1),但會影響自身的instance(sub1,sub2) alert(sub1.list);//[1,4] alert(sub2.list);//[1,4] alert(super1.list);//[1,1,1,1] 構(gòu)造函數(shù)`自身屬性`是直接賦值給它的所有instance,也就是說Super本身的屬性(color,list,不管是直接類型還是引用類型)都是分別復(fù)制一份給super1和Sub.prototype,因此修改了Sub.prototype的屬性(list)并不會影響到super1。反之亦然。 //修改Super的`prototype屬性` Sub.prototype.newList.push(2,2,2,2); sub1.newList;//[10,10,10,10,2,2,2,2] super1.newList;//[10,10,10,10,2,2,2,2];構(gòu)造函數(shù)的prototype里的屬性只是提供一個指針給所有的instance,因此修改了Sub.prototype的屬性(newList:引用類型; 直接類型是無法修改的,只能覆寫)會影響到super1。修改Sub.prototype相當(dāng)于是直接修改Super.prototype屬性,因為它們通過原型鏈引用著同一個屬性。
我們在來理清關(guān)于構(gòu)造函數(shù)自身屬性和prototype屬性與instance之間的關(guān)系,先看圖:
我們來總結(jié)一下:
Sub.prototype 和 super1 都是通過 new Super()產(chǎn)生的,我們把它們兩個叫做兄弟;同理sub1和sub2也是兄弟
自身屬性(圖中a,B):無論是直接類型還是引用類型,兄弟間互不影響,各自擁有一份父函數(shù)的copy。修改只是在自身作用域里修改。比如說③和⑤都是①的實例,都擁有①中所有屬性的copy,修改③的屬性相當(dāng)于在③中修改,不會影響其他人。
var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10]; //創(chuàng)建Super的instance:①super1;②我們可以把Sub.prototype看成是Super的instance。 var super1 = new Super("red",[1,1,1,1]); var Sub = function () {}; Sub.prototype = new Super("green",[1]);//到這里我們可以看成 Sub.prototype和super1都是Super的instance var sub1 = new Sub(); var sub2 = new Sub(); //修改Super的`自身屬性` Sub.prototype.list.push(4);//不影響兄弟(super1),但會影響自身的instance(sub1,sub2),因為對于sub1,sub2來說list是原型屬性而不是自身屬性了,這里理解起來可能有點(diǎn)亂。 alert(sub1.list);//[1,4] alert(sub2.list);//[1,4] alert(super1.list);//[1,1,1,1] 構(gòu)造函數(shù)`自身屬性`是直接賦值給它的所有instance,也就是說Super本身的屬性(color,list,不管是直接類型還是引用類型)都是分別復(fù)制一份給super1和Sub.prototype,因此修改了Sub.prototype的屬性(list)并不會影響到super1。反之亦然。 //覆寫 Sub.prototype.list = [0]; sub1.list;//[0] sub2.list;//[0] super1.list;//[1,1,1,1]
prototype屬性(圖中XXXXX):* 修改:比如說通過⑥去修改①的prototype的屬性——sub1.newList.push(2,2,2,2),那么因為原型屬性是引用而非復(fù)制,因此sub1.newList.push(2,2,2,2) ==> Sub.prototype.newList.push(2,2,2,2) ==> Super.prototype.newList.push(2,2,2,2),也就是sub1會沿著原型鏈一直查找到最終的Super.prototype,在Super.prototype里去修改newList屬性,因此原型鏈上所有引用了改屬性的實例都會被影響。
var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10];//創(chuàng)建Super的instance:①super1;②我們可以把Sub.prototype看成是Super的instance。 var super1 = new Super("red",[1,1,1,1]); var Sub = function () {}; Sub.prototype = new Super("green",[1]);//到這里我們可以看成 Sub.prototype和super1都是Super的instance var sub1 = new Sub(); var sub2 = new Sub(); //修改Super的prototype屬性
Sub.prototype.newList.push(2,2,2,2); sub1.newList;//[10,10,10,10,2,2,2,2] super1.newList;//[10,10,10,10,2,2,2,2];構(gòu)造函數(shù)的prototype里的屬性只是提供一個指針給所有的instance,因此修改了Sub.prototype的屬性(newList:引用類型)會影響到super1。修改Sub.prototype相當(dāng)于是直接修改Super.prototype屬性,因為它們通過原型鏈引用著同一個屬性。
覆寫:假如我們不是修改屬性,而是直接覆寫屬性,那么情況也會不一樣:
1.instance方法重載:
var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10]; //創(chuàng)建Super的instance:①super1;②我們可以把Sub.prototype看成是Super的instance。 var super1 = new Super("red",[1,1,1,1]); var Sub = function () {}; Sub.prototype = new Super("green",[1]);//到這里我們可以看成 Sub.prototype和super1都是Super的instance var sub1 = new Sub(); var sub2 = new Sub(); sub1.newList = [2,2,2,2];//覆寫 sub1.newList;//[2,2,2,2] sub2.newList;//[10,10,10,10] super1.newList;//[10,10,10,10] sub2和super1不受影響,實例覆寫方法只會在sub1自身的作用域里添加此方法,而不會修改到Super.prototype的方法
由于是覆寫而不是修改,因此不會沿著原型鏈查找,而是在當(dāng)前的作用域里添加該屬性,而原來原型鏈上的那個屬性依然還在,不受影響。這就實現(xiàn)了方法的重載。
2.父函數(shù)方法覆寫:假如是在Super.prototype里對newList進(jìn)行覆寫,那么所有引用該屬性的實例都將被影響。
var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10]; //創(chuàng)建Super的instance:①super1;②我們可以把Sub.prototype看成是Super的instance。 var super1 = new Super("red",[1,1,1,1]); var Sub = function () {}; Sub.prototype = new Super("green",[1]);//到這里我們可以看成 Sub.prototype和super1都是Super的instance var sub1 = new Sub(); var sub2 = new Sub(); Super.prototype.newList = [2,2,2,2]; sub1.newList;//[2,2,2,2] sub2.newList;//[2,2,2,2] super1.newList;//[2,2,2,2]
3.完全對prototype覆寫:當(dāng)我們使用XXX.prototype = YYY;對XXX.prototype進(jìn)行完全覆寫時,會徹底改變原型鏈。但是我們應(yīng)該注意一點(diǎn),覆寫前的instance依然保持著對原有prototype的引用,因此原有的prototype中的屬性不會被GC,依然保存在內(nèi)存中,完全覆寫后我們依然可以訪問原來的instance所引用的屬性和方法;而新創(chuàng)建的instance會指向新的prototype,因此無法再訪問覆寫前prototype中的屬性。
var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10]; new Super; var Sub = function () {}; Sub.prototype.sayHello = function(){return "hello"}; var sub1 = new Sub();//完全覆寫Sub.prototype前創(chuàng)建的instance Sub.prototype = new Super("green",[1]);//這里可以理解為對Sub的prototype進(jìn)行完全覆寫,因此會重新創(chuàng)建一個新的prototype指向Super.prototype var sub2 = new Sub();//完全覆寫Sub.prototype后創(chuàng)建的instance //驗證 sub1.__proto__.constructor == Sub;//true。依然引用著原來的原型鏈 sub2.__proto__.constructor == Super;//true。新的instance引用了新的原型鏈 sub1.sayHello();//"hello",依然能訪問原有的屬性,說明還保存在內(nèi)存中。 sub2.sayHello();//"對象不支持sayHello",新的實例無法再引用原有的prototype
到這里整個關(guān)系就理清了,相信還是很多人看不懂,但假如你真的希望學(xué)好javascript,這篇文章足夠你讀10遍,理清原型關(guān)系將是你能否跨上另一個臺階的關(guān)卡,不理清這一層關(guān)系的話,后患無窮。我畫了一張神一樣的圖,看得懂的話基本就能理清原型繼承關(guān)系了。
ps: 圖說明的是覆寫的過程,請區(qū)分覆寫和修改的區(qū)別。(Sub.prototype.list.push(1)是修改,Sub.prototype.list = [1]是覆寫)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/87601.html
摘要:前言作為前端高頻面試題之一,相信很多小伙伴都有遇到過這個問題。 前言 作為前端高頻面試題之一,相信很多小伙伴都有遇到過這個問題。那么你是否清楚完整的了解它呢? 國際慣例,讓我們先拋出問題: 什么是原型、原型鏈 它們有什么特點(diǎn) 它們能做什么 怎么確定它們的關(guān)系 或許你已經(jīng)有答案,或許你開始有點(diǎn)疑惑,無論是 get 新技能或是簡單的溫習(xí)一次,讓我們一起去探究一番吧 如果文章中有出現(xiàn)紕...
摘要:每個原型對象都有一個屬性指向關(guān)聯(lián)的構(gòu)造函數(shù)為了驗證這一說話,舉個例子。 本文共 1475 字,讀完只需 6 分鐘 一、概述 在 JavaScript 中,是一種面向?qū)ο蟮某绦蛟O(shè)計語言,但是 JS 本身是沒有 類 的概念,JS 是靠原型和原型鏈實現(xiàn)對象屬性的繼承。 在理解原型前,需要先知道對象的構(gòu)造函數(shù)是什么,構(gòu)造函數(shù)都有什么特點(diǎn)? 1. 構(gòu)造函數(shù) // 構(gòu)造函數(shù) Person() ...
摘要:這正是我們想要的太棒了毫不意外的,這種繼承的方式被稱為構(gòu)造函數(shù)繼承,在中是一種關(guān)鍵的實現(xiàn)的繼承方法,相信你已經(jīng)很好的掌握了。 你應(yīng)該知道,JavaScript是一門基于原型鏈的語言,而我們今天的主題 -- 繼承就和原型鏈這一概念息息相關(guān)。甚至可以說,所謂的原型鏈就是一條繼承鏈。有些困惑了嗎?接著看下去吧。 一、構(gòu)造函數(shù),原型屬性與實例對象 要搞清楚如何在JavaScript中實現(xiàn)繼承,...
摘要:深入理解原型與繼承看過不少書籍,不少文章,對于原型與繼承的說明基本上讓人不明覺厲,特別是對于習(xí)慣了面向?qū)ο缶幊痰娜藖碚f更難理解,這里我就給大家說說我的理解。 深入理解:JavaScript原型與繼承 看過不少書籍,不少文章,對于原型與繼承的說明基本上讓人不明覺厲,特別是對于習(xí)慣了面向?qū)ο缶幊痰娜藖碚f更難理解,這里我就給大家說說我的理解。 首先JavaScript是一門基于原型編程的語言...
摘要:探索是如何判斷的表達(dá)式如果函數(shù)的顯式原型對象在對象的隱式原型鏈上,返回,否則返回是通過自己產(chǎn)生的實例案例案例重要注意的顯示原型和隱式原型是一樣的。面試題測試題測試題報錯對照下圖理解 原型與原型鏈深入理解(圖解) 原型(prototype) 函數(shù)的 prototype 屬性(圖) 每個函數(shù)都有一個prototype屬性,它默認(rèn)指向一個Object空對象(即稱為:原型對象) 原型對象中有...
閱讀 2866·2021-11-11 10:58
閱讀 1920·2021-10-11 10:59
閱讀 3489·2019-08-29 16:23
閱讀 2324·2019-08-29 11:11
閱讀 2785·2019-08-28 17:59
閱讀 3838·2019-08-27 10:56
閱讀 2049·2019-08-23 18:37
閱讀 3111·2019-08-23 16:53