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