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元素) })
this
是call()
的第一個參數,只有寫onclick
,寫addEventListener
和寫jQuery
中on
的人想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
例如,我們可以重新設計一個可以指定this
的setTimeout
: 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 原型鏈? - 方應杭的文章 - 知
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的過程就是生產機器按照模板原型對象造出來的新對象的過程!