日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

this全面解析, 如何定位this指向,一文总结,再也不怕面试官追问啦

發布時間:2024/9/27 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 this全面解析, 如何定位this指向,一文总结,再也不怕面试官追问啦 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、調用位置

在理解this的綁定過程之前,首先要理解調用位置:調用位置就是函數在代碼中被調用的位置(而不是申明的位置)。只有仔細分析調用位置才能回答這個問題:這個this到底引用的是什么?

function foo() {console.log('foo')// 當前調用棧是: bar// 因此,當前調用位置在bar中 }function bar() {console.log('bar')// foo當前調用位置foo()// 當前調用棧是: bar// 因此,當前調用位置在bar中 }function baz() {console.log('baz')// bar當前調用位置bar()// 當前調用棧是: baz// 因此,當前調用位置是全局作用域 }// baz當前調用位置 // 全局作用域 baz()

二、綁定規則

1、默認綁定(非嚴格模式):獨立函數調用

const a = 2 function foo() {console.log(this.a) } foo() // 2 // foo() 在這里直接食用不帶任何修飾的函數引用進行調用,因此只能使用默認綁定;調用位置為全局作用域,因此this默認綁定到全局作用域。

2、隱式綁定:調用位置是否有上下文,或者說是否被某個對象擁有或者包含

  • 當函數引用有上下文對象時,隱式綁定規則會把函數調用中this綁定到這個上下文對象上。
function foo() {console.log(this.a) } const obj = {a: 2,foo: foo } obj.foo() // 2// 注意: 首先需要注意的是foo()的聲明方式,及其之后是如何北方做引用屬性添加到obj中的。但是無論是直接在obj中定義還是先定義在添加為引用屬性,這個函數嚴格來說都不屬于obj對象。 // 然而,調用位置會使用obj上下文來引用函數,因此你可以說函數被調用時obj對象‘擁有’或‘包含’它。// 當函數引用有上下文對象時,隱式綁定規則會把函數調用中this綁定到這個上下文對象上。

對象屬性引用鏈中只有 最頂層 或者說 最后一層 會影響調用位置

function foo() {console.log(this.a) } const obj1 = {a: 2,foo: obj2 } const obj2 = {a: 42,foo: foo } obj1.obj2.foo() // 42

隱式丟失:一個最常見的this綁定問題就是 被隱式綁定的函數 會丟失綁定對象,也就是說它會引用默認綁定,從而把this綁定到全局對象或者undefined上,取決于是否是嚴格模式。

function foo() {console.log(this.a) } const obj = {a: 2,foo: foo } const bar = obj.foo // 函數別名! const a = '我是全局對象' bar() // -> 我是全局對象 // 雖然bar是obj.foo的一個引用,但是實際上,他引用的是foo函數本身,因此此時的 bar() 相當于 foo(), 是一個不帶任何修飾的函數調用,因此應用了默認綁定 function foo() {console.log(this.a) } function doFoo(fn) {// fn其實引用的是foofn() // <--調用位置! } const obj = {a: 2,foo: foo } const a = '我是全局對象' doFoo(foo) // -> 我是全局對象 // 參數傳遞其實就是一種隱式賦值,因此我們傳入函數時也會被隱式賦值,所以結果和上一個例子一樣 // 如果把函數傳入語言內置的函數而不是自定義的函數,會怎么樣吶?結果是一樣的,沒有區別 function foo() {console.log(this.a) } const obj = {a: 2,foo: foo } const a = '我是全局對象' setTimeout(obj.foo, 100) // -> 我是全局對象// JavaScript環境中內置的setTimeout()函數實現和下面的代碼類似: function setTimeout(fn, delay) {// 等待delay毫秒fn() // <--調用位置! }

3、顯式綁定

function foo() {console.log(this.a) } const obj = {a: 2, } foo.call(obj) // -> 2 // 通過foo.call(...)可以在調用foo時強制把它綁定到obj上// 思考下面代碼輸出什么 const b = '我是全局對象' function foo() {console.log(this.b) } const obj = {b: 2,foo: foo } const bar = function(fn) {fn() } bar.call(obj, foo) // -> 我是全局對象// 顯然,通過這種方式還是無法解決綁定丟失問題

3.1、硬綁定

function foo() {console.log(this.b) } const obj = {b: 2, } const bar = function() {foo.call(obj) } bar() // -> 2 // 硬綁定的bar不能再修改它的this bar.call(window) // -> 2

由于硬綁定是一種非常常用的模式。所以在es5中提供了內置的方法Funtion.prototype.bind
bind(…)會返回一個硬編碼的新函數,它會吧參數設置為this的上下文并調用原始函數

function foo(something) {console.log(this.a, something)return this.a + something } const obj = {a: 2, } const bar = foo.bind(obj) const b = bar(3) // -> 2 3 console.log(b) // -> 5

4、new綁定
使用new來調用函數,或者說發生構造函數調用時,它會自動執行下面的操作:

  • 創建(構造)一個全新的對象
  • 這個新對象會被執行[[原型]]鏈接(將這個對象的_proto_指向其構造函數的原型)
  • 這個新對象會綁定到函數調用(構造函數)的this
  • 如果函數沒有返回其他對象,那么new表達式中的函數調用會自動返回這個新對象
  • function foo(a) {this.a = a } const bar = new foo(2) console.log(bar.a) // -> 2

    三、優先級

    如果某個調用位置同時使用四條規則,那誰的優先級更高呢?
    1、隱式綁定與顯式綁定誰的優先級更高?

    function foo() {console.log(this.a) } const obj1 = {a: 2,foo: foo } const obj2 = {a: 3,foo: foo } obj1.foo() // -> 2 obj2.foo() // -> 3obj1.foo().call(obj2) // -> 3 obj2.foo().call(obj1) // -> 2// 可以看到,顯式綁定優先級高于隱式綁定

    2、隱式綁定與new綁定誰的優先級更高?

    function foo(something) {this.a = something } const obj1 = {foo: foo } const obj2 = {}obj1.foo(2) console.log(obj1.a) // -> 2obj1.foo.call(obj2, 3) console.log(obj2.a) // -> 3const bar = new obj1.foo(4) console.log(obj1.a) // -> 2 console.log(bar.a) // -> 4// 可以看到,new綁定的優先級高于隱式綁定

    3、new綁定與顯式綁定誰的優先級更高?
    new和call/apply無法一起使用,因此無法通過 new foo.call(obj1)來直接進行測試,但是我們可以使用硬綁定來進行測試

    function foo(something) {this.a = something } const obj1 = {} const bar = foo.bind(obj1) bar(2) console.log(obj1.a) // -> 2const baz = new bar(3) console.log(obj1.a) // -> 2 console.log(baz.a) // -> 3// 可以看到,new綁定的優先級高于顯式綁定

    四、判斷this步驟

    現在我們可以根據優先級來判斷函數在某個調用位置引用的式哪條規則:

  • 函數是否在new中調用(new)綁定?如果是的話this綁定的是新創刊的對象。
    const bar = new foo()
  • 函數是否通過call,apply(顯示綁定)或者bind(硬綁定)調用?如果是的話,this綁定的式指定對象。
    const bar = foo.call(obj2)
  • 函數是否在某個上下文對象中調用(隱士綁定)?如果是的話,this綁定的是那個上下文對象
    const bar = obj1.foo()
  • 如果都不是的話,使用默認綁定。如果在嚴格式模式下,就綁定到undefined,否則綁定到全局對象
    const bar = foo()
  • 總結

    以上是生活随笔為你收集整理的this全面解析, 如何定位this指向,一文总结,再也不怕面试官追问啦的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。