原型和原型鏈

構(gòu)造函數(shù)(new運(yùn)算符)

function Foo(name,age){
    // this = {};  默認(rèn)有這一行漩勤,創(chuàng)建一個(gè)空對(duì)象
    this.name = name;
    this.age = age;
    this.class = 'class-1';
    // return this;  // 默認(rèn)有這一行焕妙,可寫可不寫(建議不寫)
}
var foo = new Foo('zhangsan',20);
// var foo2 = new Foo('lucy',22);  // 可創(chuàng)建多個(gè)對(duì)象
  1. 一個(gè)新對(duì)象被創(chuàng)建盯腌。它繼承自Foo.prototype践剂。
    分析:new Foo('zhangsan',20)的時(shí)候鬼譬,創(chuàng)建了一個(gè)新對(duì)象(空對(duì)象),這個(gè)對(duì)象繼承了構(gòu)造函數(shù)Foo的原型對(duì)象(也就是Foo.prototype)

  2. 構(gòu)造函數(shù)Foo被執(zhí)行逊脯。執(zhí)行的時(shí)候优质,相應(yīng)的參數(shù)會(huì)被傳入,同時(shí)上下文(this)會(huì)被指定為這個(gè)新實(shí)例军洼。在不傳遞任何參數(shù)的情況下巩螃,new foo相當(dāng)于new foo()。
    分析:構(gòu)造函數(shù)Foo被執(zhí)行匕争,參數(shù)'zhangsan',20被傳入避乏,this指向了新的實(shí)例foo。所以通過構(gòu)造函數(shù)中的this.name = name甘桑,新實(shí)例foo的屬性name被設(shè)置為'zhangsan'拍皮。

  3. 如果構(gòu)造函數(shù)返回了一個(gè)“對(duì)象”歹叮,那么這個(gè)對(duì)象會(huì)取代整個(gè)new出來的結(jié)果。
    如果構(gòu)造函數(shù)沒有返回對(duì)象春缕,那么new出來的結(jié)果為經(jīng)過步驟1和步驟2創(chuàng)建并執(zhí)行后的對(duì)象盗胀,這是我們最常用的情況艘蹋。
    分析:返回步驟1和步驟2創(chuàng)建并執(zhí)行后的對(duì)象給實(shí)例
    補(bǔ)充:在構(gòu)造函數(shù)里返回一個(gè)對(duì)象有什么意義嗎锄贼,應(yīng)用在哪里?
    回答:比如做權(quán)限管理的時(shí)候女阀,符合條件的返回正常的實(shí)例宅荤,非法的可以傳過去另一個(gè)對(duì)象,但是對(duì)于用戶來說拿到的都是一個(gè)對(duì)象

注意:約定俗成浸策,構(gòu)造函數(shù)以大寫字母開頭

構(gòu)造函數(shù)(new運(yùn)算符) - 擴(kuò)展

  1. var a = {};其實(shí)是var a = new Object();的語法糖
    下面兩種方式是一樣的冯键。
var a = {name:'zhangsan'};
var b = new Object({name:'zhangsan'});
  1. var a = [];其實(shí)是var a = new Array();的語法糖
    下面兩種方式是一樣的。
var a = [1,2,3];
var b = new Array(1,2,3);
  1. function Foo(){...}其實(shí)是var Foo = new Function(){...}
  2. 使用instanceOf判斷一個(gè)函數(shù)是否是一個(gè)變量的的構(gòu)造函數(shù)
var a = {name:'zhangsan'};
var b = [1,2,3];
function Foo1(){
    console.log('hello 1');
}
console.log(a instanceof Object);       // true
console.log(b instanceof Array);        // true
console.log(Foo1 instanceof Function);  // true

創(chuàng)建對(duì)象有幾種方法

第一種方法:使用字面量庸汗,或者new Object創(chuàng)建對(duì)象
// 字面量方式創(chuàng)建對(duì)象
var object1 = {name:'object1'};    

// 使用new Object創(chuàng)建對(duì)象惫确,以下兩種方式是一樣的
var object2 = new Object({name:'object2'});    
var object3 = new Object();
object3.name = 'object3';

console.log(object1);  // {name: "object1"}
console.log(object2);  // {name: "object2"}
第二種方法:使用顯式的構(gòu)造函數(shù)創(chuàng)建對(duì)象
var M = function(name){
    this.name = name
}
var object3 = new M('object3');

console.log(object3);  // {name: "object3"}
第三種方法:使用Object.create創(chuàng)建對(duì)象
var P = {name:'object4'};
var object4 = Object.create(P);

console.log(object4);  // {}
console.log(object4.name);  // "name"

咦?這里object4的顯示結(jié)果怎么是空對(duì)象蚯舱?object4.name的顯示結(jié)果卻又是"name"了改化?
這里先留作懸念,在文章的最后解釋這個(gè)現(xiàn)象枉昏。

原型規(guī)則

  1. 所有的引用類型(數(shù)組陈肛,對(duì)象,函數(shù))兄裂,都具有對(duì)象特性句旱,即可自由擴(kuò)展屬性。
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn() {}; fn.a = 100;

console.log(obj.a); // 100
console.log(arr.a); // 100
console.log(fn.a);  // 100
  1. 所有的引用類型(數(shù)組晰奖,對(duì)象谈撒,函數(shù)),都有一個(gè)__proto__屬性(原型對(duì)象/隱式原型)匾南,屬性值是一個(gè)普通對(duì)象港华。
  2. 所有的函數(shù),都有一個(gè)prototype屬性(原型對(duì)象/顯式原型)午衰,屬性值是一個(gè)普通對(duì)象立宜。
  3. 所有的引用類型(數(shù)組,對(duì)象臊岸,函數(shù))橙数,__proto__屬性,就是它的構(gòu)造函數(shù)的prototype屬性帅戒。
console.log(obj.__proto__ === Object.prototype);    // true
  1. 當(dāng)試圖得到一個(gè)對(duì)象的某個(gè)屬性時(shí)灯帮,如果這個(gè)對(duì)象本身沒有這個(gè)屬性崖技,那么會(huì)去它的原型對(duì)象中尋找。
// 構(gòu)造函數(shù)
function Foo(name){
    this.name = name;
}
Foo.prototype.alertName = function (){
    alert(this.name);
}

// 創(chuàng)建實(shí)例
var foo = new Foo('zhangsan');
foo.printName = function (){
    console.log(this.name);
}

foo.printName();    // Console中顯示'zhangsan'
foo.alertName();    // 彈出框中顯示'zhangsan'

知識(shí)點(diǎn):實(shí)例的屬性钟哥,原型對(duì)象迎献,構(gòu)造函數(shù)中的this指向的都是實(shí)例本身。

原型規(guī)則 - 擴(kuò)展

微信圖片_20181128112525.png

示例代碼:

var M = function(name){
    this.name = name
}
var object3 = new M('object3');
1.構(gòu)造函數(shù)與實(shí)例的關(guān)系

通過new 構(gòu)造函數(shù)的方式腻贰,可以創(chuàng)建一個(gè)對(duì)象實(shí)例
在示例代碼中object3就是一個(gè)對(duì)象實(shí)例

2.構(gòu)造函數(shù)與原型對(duì)象的關(guān)系

每個(gè)函數(shù)都有prototype屬性吁恍,構(gòu)造函數(shù)也是函數(shù),所以也有prototype屬性播演。
在聲明構(gòu)造函數(shù)的時(shí)候(就是我們?cè)趯慺unction a(){...}的時(shí)候)冀瓦,JS引擎會(huì)給這個(gè)構(gòu)造函數(shù)自動(dòng)增加一個(gè)prototype屬性。這個(gè)prototype屬性會(huì)自動(dòng)初始化一個(gè)空對(duì)象写烤,也就是說prototype的值是一個(gè)對(duì)象(原型對(duì)象)翼闽。

console.log(M.prototype);  // {}

prototype的英文解釋:原型,雛形

3.原型對(duì)象與構(gòu)造函數(shù)的關(guān)系

原型對(duì)象怎么區(qū)分自己是被哪個(gè)構(gòu)造函數(shù)所引用呢洲炊?
原型對(duì)象中會(huì)有一個(gè)構(gòu)造器感局,默認(rèn)是聲明的函數(shù)會(huì)引用自己。

console.log(M.prototype.constructor===M);  // true

constructor的英文解釋:構(gòu)造器

4.實(shí)例與原型對(duì)象的關(guān)系

實(shí)例的proto屬性暂衡,和構(gòu)造函數(shù)的prototype屬性询微,完全是同一個(gè)東西。

console.log(object3.__proto__===M.prototype);  // true

原型鏈

示例代碼:

var M = function(name){
    this.name = name
}
M.prototype.say = function(){
    console.log('say hi');
}

var object3 = new M('object3');
var object5 = new M('boject5');

console.log(object3.say());  // "say hi"
console.log(object5.say());  // "say hi"

可以看出來古徒,在構(gòu)造函數(shù)的原型對(duì)象上拓提,增加屬性和方法,那么這個(gè)構(gòu)造函數(shù)的實(shí)例都可以共用這些屬性和方法隧膘。

原型鏈的基本原理:
任何一個(gè)實(shí)例對(duì)象代态,可以通過原型鏈找到原型對(duì)象。而原型對(duì)象上所有的屬性和方法都是對(duì)實(shí)例共享的疹吃,這就是原型鏈的基本原理

JS引擎對(duì)JS對(duì)象的分析方式:
在訪問一個(gè)對(duì)象實(shí)例的屬性或方法時(shí)蹦疑,如果在實(shí)例本身沒有找到這個(gè)屬性或方法,會(huì)往上在實(shí)例的原型對(duì)象(實(shí)例.__proto__)上查找這個(gè)屬性或方法萨驶。
如果還沒有找到這個(gè)屬性或方法歉摧,會(huì)再往上在原型對(duì)象的原型對(duì)象(原型對(duì)象.__proto__ ,也可以說是:實(shí)例.__proto__.__proto__)上查找這個(gè)屬性或方法腔呜。
依次類推叁温,直到找到Object.prototype,如果還沒有找到核畴,那么就會(huì)提示這個(gè)屬性或方法沒有找到膝但。

知識(shí)點(diǎn)

  • 只有函數(shù)有prototype屬性,對(duì)象是沒有的
  • 函數(shù)也是一個(gè)對(duì)象谤草,所以函數(shù)也會(huì)有__proto__屬性
    M.__proto__===Function.prototype的結(jié)果是true(這里的M是以上示例代碼中的構(gòu)造函數(shù)M)
    可以理解為:M的構(gòu)造函數(shù)是Function
    也可以理解:M函數(shù)是Function函數(shù)的實(shí)例

instanceof的原理

instanceof用來判斷某個(gè)對(duì)象是否是某個(gè)構(gòu)造函數(shù)的實(shí)例跟束。
f instanceof Foo的判斷邏輯是莺奸,f的__proto__一層層往上,能否對(duì)應(yīng)到Foo.prototype

示例代碼:

var M = function(name){
    this.name = name
}
var object3 = new M('object3');

console.log(object3 instanceof M);  // true
console.log(object3 instanceof Object);  // true

分析:
Object構(gòu)造了M冀宴,M構(gòu)造了object3灭贷,這構(gòu)成了一條原型鏈。
用instanceof來判斷的時(shí)候略贮,只要在這條原型鏈上甚疟,返回結(jié)果都是true。
這是不夠嚴(yán)謹(jǐn)?shù)呐偎啵驗(yàn)槲覀儫o法用instanceof來判斷object3的直接構(gòu)造函數(shù)是哪個(gè)古拴。

那該怎么知道object3的直接構(gòu)造函數(shù)是哪個(gè)呢箩帚?這是需要用到constructor了真友。

console.log(object3.__proto__.constructor===M);  // true
console.log(object3.__proto__.constructor===Object);  // false

關(guān)于使用Object.create創(chuàng)建對(duì)象的分析

回顧一下文章開頭提到的現(xiàn)象,以下方式創(chuàng)建的object4紧帕,直接顯示的話是一個(gè)空對(duì)象盔然,然而用object4.name取值是"object4"。

var P = {name:'object4'};
var object4 = Object.create(P);

console.log(object4);  // {}
console.log(object4.name);  // "name"

console.log(object4.__proto__===P);  // true

分析:
首先是嗜,解釋下Object.create(P)的意思愈案。Object.create(P)會(huì)創(chuàng)建一個(gè)空對(duì)象,而這個(gè)空對(duì)象的原型對(duì)象鹅搪,就是參數(shù)P站绪。
所以,object4 = Object.create(P);會(huì)把對(duì)象P作為新對(duì)象的原型對(duì)象丽柿,然后把這個(gè)新對(duì)象賦給對(duì)象object4恢准。
object4本身是不具備這個(gè)屬性的,而通過原型鏈?zhǔn)悄茉L問object3.name的甫题。

常見問題

  • 如何判斷一個(gè)變量是否是數(shù)組馁筐?
var a = [1,2,3];
var b = 10;
console.log(a instanceof Array);    // true
console.log(b instanceof Array);    // false
  • 寫一個(gè)原型鏈繼承的例子
    <div id="box">before</div>

    <script type="text/javascript">
        // 構(gòu)造函數(shù)
        function Elem(id){
            this.elem = document.getElementById(id);
        }

        // 設(shè)置原型對(duì)象的屬性
        Elem.prototype.html = function(val){
            if(val){
                this.elem.innerHTML = val;
                return this;
            }else{
                return this.elem.innerHTML;
            }
        }

        Elem.prototype.on = function(type,fn){
            this.elem.addEventListener(type,fn);
            return this;
        }

        // 實(shí)例化對(duì)象
        let elem = new Elem('box');

        // 操作
        elem.html('after').on('click',function(){
            alert('message:after');
        })
    </script>

操作結(jié)果:
頁面顯示"after",且點(diǎn)擊"after"會(huì)有彈出框坠非,彈出框中的內(nèi)容是"message:after"

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末敏沉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子炎码,更是在濱河造成了極大的恐慌盟迟,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件潦闲,死亡現(xiàn)場(chǎng)離奇詭異攒菠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)矫钓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門要尔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舍杜,“玉大人,你說我怎么就攤上這事赵辕〖燃ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵还惠,是天一觀的道長(zhǎng)饲握。 經(jīng)常有香客問我,道長(zhǎng)蚕键,這世上最難降的妖魔是什么救欧? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮锣光,結(jié)果婚禮上笆怠,老公的妹妹穿的比我還像新娘。我一直安慰自己誊爹,他們只是感情好蹬刷,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著频丘,像睡著了一般办成。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上搂漠,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天迂卢,我揣著相機(jī)與錄音,去河邊找鬼桐汤。 笑死而克,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的惊科。 我是一名探鬼主播拍摇,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼馆截!你這毒婦竟也來了充活?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤蜡娶,失蹤者是張志新(化名)和其女友劉穎混卵,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窖张,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡幕随,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宿接。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赘淮。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辕录,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出梢卸,到底是詐尸還是另有隱情走诞,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布蛤高,位于F島的核電站蚣旱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏戴陡。R本人自食惡果不足惜塞绿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望恤批。 院中可真熱鬧异吻,春花似錦、人聲如沸开皿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赋荆。三九已至,卻和暖如春懊昨,著一層夾襖步出監(jiān)牢的瞬間窄潭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國打工酵颁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嫉你,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓躏惋,卻偏偏與公主長(zhǎng)得像幽污,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子簿姨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353