代碼一:數組
this.number = 10 function a() { this.number = 20 } a.prototype.init = () => console.log(this.number) const test = new a() // 構造函數生成一個獨立新對象 test.init() // 10
解析:之因此輸出10,能夠把 arrow function(箭頭函數) 裏的 this 和 arguments 關鍵字理解爲函數做用域裏的變量(由於自身沒有),他訪問變量沿着做用域鏈向上找而不是直接訪問對象屬性走原型鏈,代碼中的init上頭的做用域就是window,因此他的this指向window.閉包
注:能夠試試把上例代碼中的箭頭函數換成普通匿名函數(輸出就是直接走原型鏈訪問對象屬性,number = 20)app
代碼二:函數
this.number = 10 function a(){ //閉包函數 return { show: () => console.log(this.number) } } a().show() // 10 函數a的this的指向window a.call({number: 20}).show() // 20 call改變了函數a的this指向,箭頭函數的做用域指向改變後的函數做用域 a.call({number: 30}).show() // 30
解析:閉包函數裏return出的箭頭函數被調用的時候會一直引用外層函數的變量this或者arguments,因此外層函數this指向被改變,return出的箭頭函數裏的this也改變了.this
this的指向可理解爲兩大類:spa
1:test();==test.call(window,參數);//直接調用函數,this指向windowprototype
2:obj.test(); == obj.test.call(obj,參數);//函數做爲對象的方法被調用,this指向該對象code
注:this指向是在被調用時分配的對象
代碼三:blog
function a() { this.say = function() { console.log(1) } } a.prototype.say = function() { console.log(2) } var test = new a() test.say() // 1
只有函數有prototype,對象對應_proto_,prototype能夠對主函數進行擴充,但不會覆蓋主函數內的方法(若是主函數裏沒有此對象屬性就在原型鏈裏查找)。
簡單一句話~js中訪問變量沿着做用域鏈向上走(this),直接訪問對象上的屬性沿着原型鏈往下走~(都是就近查找哦)
對call和apply作補充:
相同點:都是爲了改變對象this指向,參數二不一樣:call是傳進單個參數,apply是數組形式
apply能夠接受一個數組或者類數組對象,console.log(...arguments) === console.log.apply(this,arguments)