this作為js中的常用引用,區(qū)別與詞法作用域,有自己一套的規(guī)則
this的綁定規(guī)則
函數(shù)在執(zhí)行過程中的調(diào)用位置決定了this的綁定對象,因此需要確定調(diào)用的位置,才能準(zhǔn)確判斷this綁定的對象是誰。
-
默認(rèn)綁定
當(dāng)函數(shù)獨立調(diào)用的時候默認(rèn)綁定的this 指向為全局對象,當(dāng)在函數(shù)內(nèi)部使用嚴(yán)格模式
use strict時,this為undefine。function foo() { console.log(this.a) } function bar() { 'use strict'; console.log(this.a) } const a = 1 foo() // -> 1 注意:在node環(huán)境中為 undefined bar() // -> TypeError: this is undefined-
在node環(huán)境中
this的 在默認(rèn)綁定情況下 為Object [global], 無法向上查詢到在全局下賦值的屬性。// node 環(huán)境中 function foo() { console.log(this.a) } const a = 1 foo() // -> undefined this.a = 1 console.log(this.a) // -> 1
-
隱式綁定
-
通過將函數(shù)引用進一個對象的屬性,通過對象調(diào)用函數(shù)的形式實現(xiàn)
function foo() { console.log(this.a) } const obj = { a: 1, foo: foo } const a = 'global a' obj.foo() // -> 1 // 可能會存在this 丟失,轉(zhuǎn)而進行默認(rèn)綁定(同默認(rèn)綁定) // 1. 當(dāng)進行再次引用的時候 var bar = obj.foo // 定義bar 指向foo函數(shù) bar() // -> global a // 2. 當(dāng)將函數(shù)作為參數(shù)傳遞的時候 setTimeout(obj.foo, 1000) // -> global a
-
-
顯示綁定
-
通過
apply, call , bind進行顯示的綁定this對象function foo(){ console.log(this.a) } const obj = { a : 1 } // foo.call(obj, 可變參數(shù)) foo.call(obj) // -> 1 // foo.apply(obj, 數(shù)組) foo.apply(obj) // => 1 const bar = foo.bind(obj) bar() // 1
-
-
new綁定
-
JavaScript 中構(gòu)造函數(shù)知識一些使用
new操作符時被調(diào)用的函數(shù),并不屬于某個類,也不會實例化一個類。new調(diào)用某個函數(shù)的時候做了以下事情:- 創(chuàng)建一個全新的對象
- 這個新的對象會被執(zhí)行
[[Proptype]]連接 - 這個新的對象會綁定到函數(shù)調(diào)用的
this - 如果該函數(shù)沒有返回對象,那么new 表達(dá)式中的函數(shù)調(diào)用會自動返回這個新的對象
function foo(a) { this.a = a } var bar = foo(1) console.log(bar.a) // -> 1
-
this綁定中的優(yōu)先級
- 函數(shù)中如果存在
new綁定,如果是的話,this綁定的就是新創(chuàng)建的對象。 - 函數(shù)中如果存在
call, apply,bind的綁定,this綁定的是指定的對象。 - 函數(shù)中如果存在某個對象中的引用,并被該對象調(diào)用(隱式綁定),this綁定的是那個對象。
- 如果以上都不是的話,則使用默認(rèn)綁定,如果在嚴(yán)格模式下,則綁定到
undefined - 需要注意的是,在node環(huán)境中,默認(rèn)綁定總是不盡人意的。
特殊場景下的this
-
當(dāng)使用顯示綁定的時候,如果傳入的綁定對象為
null或者undefined, 那么函數(shù)中的this會作為默認(rèn)綁定指向全局foo() { console.log(this.a) } const obj = { a:1 } const a = 'global a' foo.call(null) // -> global a -
當(dāng)使用
new包裹 顯示綁定的時候,顯示綁定的對象會失效, 這時候的this會綁定到新創(chuàng)建的對象上,一般用這種寫法來:- 創(chuàng)建柯里化函數(shù)。
- 展開一個數(shù)組,當(dāng)參數(shù)傳入函數(shù)。
function foo(p1, p2) { this.a = p1 + p2 } var obj = { a : 'a' } // 函數(shù)的柯里化 //const bar = foo.bind(obj, 'p1') const bar = foo.bind(null, 'p1') const baz = new bar('p2') // new 后 上一行代碼中的obj 會被新的baz上下文所替代,所以可以直接寫null console.log(baz.a) // -> 'p1p2' // 展開數(shù)組 foo.apply(null, ['p1', 'p2'])函數(shù)的柯里化就是通過
bind預(yù)先設(shè)置一些參數(shù),然后在通過函數(shù)調(diào)用傳遞另外一些參數(shù),這里模擬一下函數(shù)的原理:function curry(fn) { const outArgs = Array.prototype.slice.call(arguments, 1) return function() { const innerArgs = Array.prototype.slice.call(arguments) const finalArgs = outArgs.concat(innerArgs) return fn.apply(null, finalArgs) } } 當(dāng)使用
fn.apply(null, args)的時候,因為null的存在會是的函數(shù)中的this指向全局變量,可能會出現(xiàn)不可估計的后果(比如對全局進行操作修改之類的)。這個時候建議 使用空對象替換null,因此上面的代碼修改如下:
function foo(p1, p2) {
console.log('p1:' + p1 + '; p2:' + p2)
}
// 創(chuàng)建空對象 同{} 相比, 不包含Object.prototype
const ? = Object.create(null)
// 函數(shù)的柯里化
const bar = foo.bind(?, 'p1')
bar('p2')
// 展開數(shù)組
foo.apply(?, ['p1', 'p2'])
當(dāng)然,也可以重寫
Prototype中的bind方法進行定制this, 當(dāng)使用的是全局或者undefined的時候,可以讓this指向傳遞進來的對象-
當(dāng)使用箭頭函數(shù)的時候,不會遵循上面的使用規(guī)則,而是根據(jù) 詞法作用域來決定this, 準(zhǔn)確的說法是 箭頭函數(shù)會繼承外層函數(shù)調(diào)用的
this綁定function foo() { setTimeout(()=> { console.log(this.a) // 這里的this是foo作用域下的this }, 1000) // => 等同于 const self = this setTimeout(function() { console.log(this.a) }, 1000) } var obj = { a : 1 } foo.call(obj) // 1
以上是我對JavaScript中的this用法的理解與總結(jié),希望能幫到大家,如果能夠幫到您,希望不吝點個贊哦;如果哪里寫的不對或者缺失,還望告知~~