函數的內部屬性,this引用的是函數據以執行的環境對象。也就是說函數的this會指向調用函數的執行環境。數組
function a(){ return this } console.log( a() === window) //true
函數的 this 關鍵字在 JavaScript 中的表現略有不一樣,此外,在嚴格模式和非嚴格模式之間也會有一些差異。閉包
function a(){ 'use strict' return this } console.log( a() === undefined) //true
this作爲函數的關鍵字,指向函數的調用對象。app
大體的指向總結概括爲能夠分爲如下幾種:dom
var name = 'window'; function a(){ return this.name } a() ==='window' //true
var obj = { name:'obj', sayName:function(){ return this.name } } console.log( obj.sayName() === 'obj') //true //稍微改動一下;添加下面代碼。 var sayName = obj.sayName; console.log( sayName() === 'obj') //false //此時,sayName函數裏的this指向了window。 這裏須要明白一點,函數名僅僅是一個包含指針的變量,函數是複雜數據類型,因此函數名就只是一個指針,指向堆中的內存地址!因此sayName此時只是複製了指針地址,因此,上面代碼改寫成下面就很清晰了。 var sayName = function(){ return this.name } var obj = { name:'obj', sayName:sayName } console.log( obj.sayName() === 'obj') //true console.log( sayName() === 'obj') //false
var container3 = document.getElementById('container3') container3.onclick = function(){ //指向節點自己 console.log(this) //<div id="container3">container3</div> }
function A(name){ this.name = name; this.sayName = function(){ console.log(this.name)//指向實例對象 } } var a = new A('aa'); a.sayName(); //aa
var name = 'window' var obj = { name:'obj', fn:function(){ (function (){ console.log(this.name) })() } } obj.fn() //window 普通函數,因爲閉包函數是window執行的,因此this指向window; 箭頭函數的this指向函數建立時的做用域。 var name = 'window' var obj = { name:'obj', fn:function(){ (()=>{ //改爲箭頭函數 console.log(this.name) })() } } obj.fn() 改爲箭頭函數,後能夠看出建立時的做用域是obj.fn函數執行是的做用域,也就是obj
js提供了一些能夠改變函數執行做用域的方法。由於普通函數若是經過上面的寫法來改變this執行時上下文,寫法就太過於麻煩。函數
apply:
fn.apply(thisObj,數組參數)
定義:應用某一個對象的一個方法,用另外一個對象替換當前對象
說明:若是參數不是數組類型的,則會報一個TypeError錯誤。this
call:
fn.call(thisObj, arg1, arg2, argN)
apply與call的惟一區別就是接收參數的格式不一樣。prototype
bind:
fn.bind(thisObj, arg1, arg2, argN)
bind()方法建立一個新的函數,在bind()被調用時,這個新函數的this被bind的第一個參數指定,其他的參數將做爲新函數的參數供調用時使用。指針
apply的實現: Function.prototype.myApply= function(context){ context.fn = this;//1.將函數掛載到傳入的對象 var arg = [...arguments].splice(1)[0];//2.取參數 if(!Array.isArray(arg)) { throw new Error('apply的第二個參數必須是數組') //3.限制參數類型爲數組 } context.fn(arg) //4.執行對象的方法 delete context.fn; //5.移除對象的方法 } var obj = { name:'obj' } function sayName(arr){ console.log(this.name,arr) } sayName.myApply(obj,[1,2,3]) //obj [1, 2, 3]
call實現:與apply的惟一區別就是參數格式不一樣 Function.prototype.myCall= function(context){ context.fn = this;//1.將函數掛載到傳入的對象 var arg = [...arguments].splice(1);//2.取參數 context.fn(...arg) //3.執行對象的方法 delete context.fn; //4.移除對象的方法 } var obj = { name:'obj1' } function sayName(){ console.log(this.name,...arguments) } sayName.myCall(obj,1,2,3,5) //obj1 1,2,3,5
bind在mdn上的實現: Function.prototype.myBind = function(oThis){ if(typeof this !== 'function'){ throw new TypeError('被綁定的對象須要是函數') } var self = this var args = [].slice.call(arguments, 1) fBound = function(){ //this instanceof fBound === true時,說明返回的fBound被當作new的構造函數調用 return self.apply(this instanceof fBound ? this : oThis, args.concat([].slice.call(arguments))) } var func = function(){} //維護原型關係 if(this.prototype){ func.prototype = this.prototype } //使fBound.prototype是func的實例,返回的fBound若做爲new的構造函數,新對象的__proto__就是func的實例 fBound.prototype = new func() return fBound }