JS面向對象二:this/原型鏈/new原理

JS面向對象二:this/原型鏈/new原理

阮一峯JavaScript教程:面向對象編程

阮一峯JavaScript教程:實例對象與 new 命令

阮一峯JavaScript教程:this 關鍵字

也可以看看這篇文章周大俠啊 進擊的 JavaScript(六) 之 this先了解一下`this的四種綁定規則和箭頭函數的this綁定

this

這兩篇文章寫的很好 周大俠啊 進擊的 JavaScript(六) 之 this

蘇雲的博客

下面的this分別是什麼?這幾個函數都是回調函數,回調函數this比較特殊,通常是事件原對象

//1.
button1.onclick = function () {
    console.log(this)
}
//2.
button2.addEventListener("click", function () {
    console.log(this)
})
//3.jQuery中
$("ul").on("click", "li", function () {
    console.log(this)
})

this是函數.call()的第一個參數.

那麼在直接調用函數的時候(隱式綁定,沒用call),如何知道call()的第一個參數? 源碼看不到,那就看文檔.

看文檔!: onclick:

addEventListener:

jQuery中:

所以上面三個的this分別是 btutton1元素,button2元素,li元素

$("ul").on("click", "li"/*selector*/, function () {
console.log(this)//代表與selector相匹配的元素(li元素)
})

thiscall()的第一個參數,只有寫onclick,寫addEventListener和寫jQueryon的人想call()哪個東西,就把這個this綁定到哪裏去了,所以要確定this,就要看源碼或者文檔!

例如:

button1.onclick = function () {
    console.log(this)
}
button1.onclick.call({name:"mataotao"})

可以直接觸發onclick事件,傳入{name:"mataotao"},那麼this就是{name:"mataotao"}這個對象

以下來自蘇雲的博客()

6.回調函數的this 回調函數也只不過是函數的一種,實際上這種情況已經包含在了前面提到的情況中。但是由於回調函數的調用者往往不是我們自己,而是回調函數的接收者,即某個庫或框架、甚至是JS運行時環境。這樣一來,回調函數在中的this是什麼就與對方的調用方式有關了,因此變得比較複雜,所以單獨拿出來討論一下。 情況1:沒有明確作用對象的情況下,通常this爲全局對象 例如setTimeout函數的回調函數,它的this就是全局對象。你如果希望自己指定this,可以通過bind函數等方法。 情況2:某個事件的監聽器回調函數,通常this就是事件源對象 例如: button.addEventListener('click', fn) fn的中的this就是事件源button對象。 情況3:某些API會專門提供一個參數,用來指定回調函數中的this 例如,我們可以重新設計一個可以指定thissetTimeout: function setTimeoutExt(cb, period, thisArg) { setTimeout(function() { cb.call(thisArg); }, period); } 另外,在ExtJS中也大量使用了可以指定this的接口。

this題目

答案: 調用B處的console.log().結果是options window(console.log()中console是全局window對象裏的一個方法)

第二題:

答案:D Object

第三題:

答案:Object

原型鏈

我終於明白了原型鏈: 仔細看下面這篇文章,就能明白原型鏈的構造問題: JavaScript 世界萬物誕生記

個人理解: 原型鏈要分爲兩個部分,原型和鏈,原型就是一個實例對象,但是是最基礎的實例對象.這個實例對象可以作爲模板/類,讓其他對象去複製他,複製之後不單單有這個原型的屬性,也可以有自己的屬性.新實現的實例對象.__proto__指向原來的模板實例對象. 而造出來的對象也可以當做模板,再由新的機器去以他爲模板造新對象.由此形成了一條__proto__組成的鏈. 所有的對象都有__proto__屬性,他們就像被鏈子連接在了一起,所以就稱之爲原型鏈

而複製的過程由一個機器來完成.這個機器(比如可以說是Object())的使用方法就是:按照模板實例對象new()一個新對象,新對象被原來的模板對象用__proto__鏈子拴着,新對象可以有自己的新添加的東西. 這個按照模板造新對象的機器.prototype指向原來的模板實例對象.prototype就是原來的模板實例對象拴住複製自己機器的鏈子.

寫成代碼就是:

var obj = new Object({ flag: 10 });

就像前面所說,機器用來製造某一類對象。正因如此,機器可以作爲這類對象的標誌,即面嚮對象語言中(class)的概念。所以機器又被稱爲構造函數。在ES6引入class關鍵字之前,我們常常把構造函數叫做類。說明2:用戶自定義的函數通常既可以作爲普通函數使用,又可以作爲構造函數來製造對象。ES6新增的class語法定義的函數只能作爲構造函數,ES6新增的=>語法定義的箭頭函數只能作爲普通函數

.

__proto__prototype的區別

__proto__是所有對象(包括函數對象)都有的一個屬性(當然只是邏輯上有這麼個概念),當我們說“原型鏈”的時候,就是指對象通過這個屬性互相連接而形成的鏈狀結構原型鏈也就是繼承鏈prototype是隻有函數(準確地說是構造函數)纔有的一個屬性,例如對於對於某個函數Fun。它的意義在於,當你用var obj = new Fun() 得到一個對象obj時,這個obj的原型就是F.prototype。即(new Fun()).__proto__ ===Fun.prototype,見文中第4個圖。No. 1其實就是Object.prototype,No. 2其實就是Function.prototype。我只是爲了強調這兩個對象的重要性,故意這樣說的。不太嚴格地說,前者就是一個空對象類似:{} ,後者就是一個空函數,類似:fubction() {} 。

文中: **No. 1:Object.prototype No. 2:Function.prototype**

還有這幾篇文章也不錯: 「每日一題」什麼是 JS 原型鏈? - 方應杭的文章 - 知

周大俠啊 進擊的 JavaScript 之 (七) 原型鏈

周大俠啊 進擊的 JavaScript (八) 之 繼承

new()

看看這篇文章很清楚: JS 的 new 到底是幹什麼的? - 方應杭的文章 - 知乎

new解決了什麼

以共有屬性對象爲模板new出來的新對象的__proto__指向共有屬性對象(我把這個對象叫做模板對象,也叫作原型).這樣共有屬性在內存中只需要存一次!

比如:當我們造士兵的時候,士兵有共有屬性,有自有屬性,那麼我們可以把共有屬性放在一個地方,避免每一次創建士兵都把共有屬性重新創建一次,浪費內存:

既然這樣,那麼我們可以把製造士兵的過程寫成一個函數.

然後調用即可

直接使用函數就可以製造一個有特殊的id,但是__proto__指向原型士兵的新士兵

那麼可不可以直接把這個原型對象放到函數裏,組成一個整體?不行,這樣每次調用這個函數,都會在內存中創建這個臨時對象,那麼和原先的不用原型一樣了

解決方法是,把這個原型變爲函數的一個屬性

這種方法省內存且好用.

new()就是剛剛的所有過程

灰色的代碼就是new()做的封裝,不需要你做的事情 共有屬性被new()統一叫做prototype

new其實就是語法糖!

注意:.prototype對象最開始就是一個擁有constructor屬性的對象,如果想修改共有屬性,兩種方法:

當我們new的時候我們做了什麼:

new()的核心就是:

new應用舉例:

第一步寫私有屬性,第二步寫共有屬性.

可以看到這個對象的 1自有屬性, 2__proto__指向的原型對象含有共有屬性. 3constructor指向的構造函數

節選文章

也可以看看這篇文章周大俠啊 進擊的 JavaScript(六) 之 this 裏面有new的實現.new與this 下面是節選:

五、new 綁定 如果 使用 new 來創建對象,因爲 後面跟着的是構造函數,所以稱它爲構造器調用。對於this綁定來說,稱爲new綁定。 想知道 構造器調用 中 this 的綁定,就要知道 new 到底做了啥了。 先來個 new 的實現。看不懂不要緊,在後面原型鏈那篇,還會說的。 function New(proto){ //proto 爲傳進來的構造函數 var obj = {}; obj.__proto__ = proto.prototype; proto.apply(obj, Array.prototype.slice.call(argument,1)); //你這要看懂這步就行。這裏把構造函數裏的 this 綁定到了 新的obj 對象上,最後 返回了該新對象,作爲實例對象。 return obj; } 所以在使用 new 來創建實例對象時,new 內部把 構造函數的 this 綁定到 返回的新對象 上了。 function Person(name){ this.name = name; } var c = new Person("zdx"); c.name;

JavaScript 世界萬物誕生記中也提到了new的使用,new的過程就是生產機器按照模板原型對象造出來的新對象的過程!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章