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

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

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

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

阮一峯JavaScript教程:this 關鍵字java

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

this

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

蘇雲的博客編程

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

//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()的第一個參數.app

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

看文檔!:
onclick:
PhRWOe.png
addEventListener:
PhRoFI.png
jQuery中:
PhWNtI.png函數

因此上面三個的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"}這個對象

PhfVv8.png

如下來自蘇雲的博客()

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題目

PhfYKU.png

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

第二題:
PhftrF.md.png
答案:D Object

第三題:
PhfLZQ.md.png
答案: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__指向共有屬性對象(我把這個對象叫作模板對象,也叫做原型).這樣共有屬性在內存中只須要存一次!

好比:當咱們造士兵的時候,士兵有共有屬性,有自有屬性,那麼咱們能夠把共有屬性放在一個地方,避免每一次建立士兵都把共有屬性從新建立一次,浪費內存:
P4sau9.png

既然這樣,那麼咱們能夠把製造士兵的過程寫成一個函數.
P4yyaq.png

而後調用便可
P4y6I0.png
直接使用函數就能夠製造一個有特殊的id,可是__proto__指向原型士兵的新士兵

那麼可不能夠直接把這個原型對象放到函數裏,組成一個總體?不行,這樣每次調用這個函數,都會在內存中建立這個臨時對象,那麼和原先的不用原型同樣了
P4yjQe.png

解決方法是,把這個原型變爲函數的一個屬性
P46FW8.png
這種方法省內存且好用.

new()就是剛剛的全部過程
P465p8.png
灰色的代碼就是new()作的封裝,不須要你作的事情
共有屬性被new()統一叫作prototype
P46Xt0.png

new其實就是語法糖!

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

當咱們new的時候咱們作了什麼:

P4cdBj.png

P4cRu4.png

P4c4ER.png

P4cLKe.png

new()的核心就是:

PhLmAf.png

PhL1js.png

new應用舉例:

P4gOzT.png

第一步寫私有屬性,第二步寫共有屬性.
P4gxL4.png
能夠看到這個對象的
1自有屬性,
2__proto__指向的原型對象含有共有屬性.
3constructor指向的構造函數

節選文章

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

5、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的過程就是生產機器按照模板原型對象造出來的新對象的過程!

相關文章
相關標籤/搜索