关于javascript:彻底搞懂-JavaScript-中的-this-指向

7次阅读

共计 6933 个字符,预计需要花费 18 分钟才能阅读完成。

前言


本文将从以下几方面论述 Javascript 中 this 的指向问题。

  • 规范函数中,this的援用值是什么
  • 箭头函数中,this的援用值是什么
  • 应用 new 关键字创建对象时,this的援用值是什么
  • 闭包中应用 this 时,this的援用值什么

规范函数中,this 的援用值是什么

规范函数中,this 援用的是把函数当成办法调用的上下文对象

在规范函数中 this 的值是会依据办法被调用的状况扭转所援用的值

window.identity = "The Window"
let object = {
    identity: 'My Object',
    getIdentityFunc() {console.log(this.identity)
    }
}
object.getIdentityFunc()  // My Object
const getIdentityFunc = object.getIdentityFunc
getIdentityFunc()  // The Window

箭头函数中,this 的援用值是什么

在箭头函数中,this 援用的是定义箭头函数的上下文

由此能够看出箭头函数中的 this 援用值是固定的

window.identity = "The Window"
let object = {
    identity: 'My Object',
    testIdentity: this.identity,
    getIdentityFunc:() => {console.log(this.identity)
    }
}
console.log(object.testIdentity)  // The Window
object.getIdentityFunc()  // The Window

面试的时候我就遇到了这个问题,过后我心想

“在箭头函数中,this 援用的是定义箭头函数的上下文对象”

大家如果认真比拟这两句话能够发现我心里想的多了两个字 (或者说我就是囫囵的看了一遍书,基本没有好好的去了解、去验证),这两个字不多不少让我把this 的援用值认为成 object 这个对象了,所以我认为最初的后果应该是My Object

那么咱们当初来具体的看看这个定义箭头函数的上下文是什么呢?
在我看来,咱们能够把 this 值看成上下文

定义箭头函数的上下文 其实就是 objectthis值呗;那咱们要晓得的其实就是 objectthisidentity 属性是什么呗?

在上方代码的倒数第二行就是为了阐明这个问题,因为属性 testIdentity 的值是 The Window 咱们能得出 objectthis援用值其实是window

因为函数 getIdentityFunc 中的 this 援用值其实是 objectthis,也就是 window。所以函数getIdentityFunc 中的 this.identityThe Window

既然箭头函数中的 this 是固定的,那么相似 call 的函数能扭转 this 的援用值吗

在 JS 中咱们能够应用 callapplybind 办法扭转 this 指向,既然箭头函数的 this 值援用值是固定的,那咱们能应用这几个办法扭转这个援用值吗?

看上面的代码

window.identity = "The Window"
let object = {
    identity: 'My Object',
    getIdentityFunc() {console.log(this.identity)
    }
}
let object1 = {identity: 'My Object1'}
object.getIdentityFunc.call(object1)  // My Object1
window.identity = "The Window"
let object = {
    identity: 'My Object',
    testIdentity: this.identity,
    getIdentityFunc:() => {console.log(this.identity)
    }
}
console.log(object.testIdentity)  // The Window
object.getIdentityFunc()  // The Window
object.getIdentityFunc.call(object)  // The Window

比照这两处代码咱们能发现 call 办法根本无法扭转箭头函数的 this 的援用值。

应用 new 关键字创建对象时,this 的援用值是什么

在实例中 this 的援用值是以后所在的实例

window.identity = "The Window"

function Obj() {
  this.identity = "My Object"

  this.getIdentityFunc = function () {console.log(this.identity)
  }

  this.getIdentityFunc1 = () => {console.log(this.identity)
  }
}

const obj = new Obj()
obj.getIdentityFunc()  // My Object
obj.getIdentityFunc1() // My Object

咱们能够看到两个函数中输入的都是 My ObjectgetIdentityFunc 函数的后果也之前调用的差异不大,因为在这个函数外面 this 的援用值仍然是 obj 这个上下文对象。

然而在函数 getIdentityFunc1 中,尽管都是箭头函数 (和第二个例子的代码做比拟),然而这一次的后果的确My Object,也就是说这一次的this 援用值是对象obj

那么这个状况的起因是什么呢?咱们来回顾一下刚刚第二个例子外面箭头函数的 this 值是等于对象 objectthis值,事实上这一次也是。所以造成这两次后果不同的起因其实是这两次的“函数上下文”不一样了。

  • 第二个例子中 object的函数上下文 this 援用值是window
  • 这次 obj 的函数上下文 this 的援用值是他本人obj

闭包中应用 this 时,this 的援用值什么

在闭包中应用 this 会让代码变简单。如果外部函数没有应用 箭头函数 定义,则 this 对象会在运行时绑定到执行函数的上下文。如果在全局函数中调用,则 this 在非严格模式下等于 window,在严格模式下等于 undefined。如果作为某个对象的办法调用,则 this 等于这个对象。

从这一段话中咱们能够提取出以下几条信息。

  1. 如果闭包的外部函数是应用箭头函数定义的,根本不受影响,咱们只须要依照箭头函数的 this 指向判断办法判断就能够。
  2. 如果在全局函数中调用,则 this 在非严格模式下等于 window,在严格模式下等于 undefined
  3. 如果作为某个对象的办法调用,则 this 等于这个对象

外部函数应用箭头函数定义的,根本不受影响

window.identity = "The Window"
let object = {
  identity: "My Object",
  getIdentityFunc() {const doit = () => {console.log(this.identity)
    }
    return doit
  },
}

object.getIdentityFunc()() // My Object

如果在全局函数中调用,则 this 在非严格模式下等于 window,在严格模式下等于 undefined

window.identity = "The Window"
let object = {
  identity: "My Object",
  getIdentityFunc() {return function () {console.log(this.identity)
    }
  },
}

object.getIdentityFunc()() // The Window

如果作为某个对象的办法调用,则 this 等于这个对象

window.identity = "The Window"
let object = {
  identity: "My Object",
  testIdentity: this.identity,
  getIdentityFunc: () => {console.log(this.identity)
  },
  getIdentityFunc1() {return function () {console.log(this.identity)
    }
  },
  getIdentityFunc2() {function doit() {console.log(this.identity)
    }
    return doit
  },
  getIdentityFunc3() {const doit = () => {console.log(this.identity)
    }
    return doit
  },
}

object.getIdentityFunc() // The Window
object.getIdentityFunc1()() // The Window
object.getIdentityFunc2()() // The Window 
object.getIdentityFunc3()() // My Object

let object1 = {
  identity: "My Object1",
  getIdentityFunc1: object.getIdentityFunc1(),
  getIdentityFunc2: object.getIdentityFunc2(),}

object1.getIdentityFunc1()  // My Object1
object1.getIdentityFunc2()  // My Object1

练习题目

const test = {
  name: "Bill",
  show1: function () {console.log(this.name)
  },
  show2: () => {console.log(this.name)
  },
  show3: () => {function innerFunction() {console.log(this.name)
    }
    innerFunction()},
}

test.show1()
test.show2()
test.show3()

// 参考答案
Bill
undefined
undefined
var name = "window"

var person1 = {
  name: "person1",

  foo1: function () {console.log(this.name)
  },

  foo2: () => console.log(this.name),

  foo3: function () {return function () {console.log(this.name)
    }
  },

  foo4: function () {return () => {console.log(this.name)
    }
  },
}

var person2 = {name: "person2"}

person1.foo1() 
person1.foo1.call(person2)
person1.foo2()
person1.foo2.call(person2)
person1.foo3()()
person1.foo3.call(person2)()
person1.foo3().call(person2)
person1.foo4()()
person1.foo4.call(person2)()
person1.foo4().call(person2)

// 参考答案
person1
person2
window
window
window
window
person2
person1
person2
person1
var name = "window"

function Person(name) {
  this.name = name

  this.foo1 = function () {console.log(this.name)
  }
  this.foo2 = () => console.log(this.name)
  this.foo3 = function () {return function () {console.log(this.name)
    }
  }
  this.foo4 = function () {return () => {console.log(this.name)
    }
  }
}

var person1 = new Person("person1")
var person2 = new Person("person2")
person1.foo1()
person1.foo1.call(person2)
person1.foo2()
person1.foo2.call(person2)
person1.foo3()()
person1.foo3.call(person2)()
person1.foo3().call(person2)
person1.foo4()()
person1.foo4.call(person2)()
person1.foo4().call(person2)

// 参考答案
person1
person2
person1
person1
window
window
person2
person1
person2
person1
window.identity = "The Window"

let object = {
  identity: "My Object",
  testThis: this.identity,
  getIdentityFunc() {console.log(this.identity)
  },
  getIdentityFunc1: () => {console.log(this.identity)
  },
  getIdentityFunc2: () => {function innerFunction() {console.log(this.identity)
    }
    innerFunction()},
  getIdentityFunc3() {return function () {console.log(this.identity)
    }
  },
  getIdentityFunc4() {return () => {console.log(this.identity)
    }
  },
  getIdentityFunc5: () => {return function () {console.log(this.identity)
    }
  },
  getIdentityFunc6: () => {return () => {console.log(this.identity)
    }
  },
  getIdentityFunc7() {console.log(this.identity)
    function innerFunction() {console.log(this)
      console.log(this.identity)
    }
    innerFunction()},
  getIdentityFunc8() {const innerFunction = () => {console.log(this.identity)
    }
    innerFunction()},
}

object.getIdentityFunc() // My Object
let getIdentityFunc = object.getIdentityFunc
getIdentityFunc() // The Window

object.getIdentityFunc1() // The Window
let getIdentityFunc1 = object.getIdentityFunc1
getIdentityFunc1() // The Window

object.getIdentityFunc2() // The Window
let getIdentityFunc2 = object.getIdentityFunc2
getIdentityFunc2() // The Window

object.getIdentityFunc3()() // The Window
let getIdentityFunc3 = object.getIdentityFunc3()
getIdentityFunc3() // The Window

object.getIdentityFunc4()() // My Object
let getIdentityFunc4 = object.getIdentityFunc4()
getIdentityFunc4() // My Object

object.getIdentityFunc5()() // The Window
let getIdentityFunc5 = object.getIdentityFunc5()
getIdentityFunc5() // The Window

object.getIdentityFunc6()() // The Window
let getIdentityFunc6 = object.getIdentityFunc6()
getIdentityFunc6() // The Window

object.getIdentityFunc7()
object.getIdentityFunc8()

// 参考答案

My Object
The Window
The Window
The Window
The Window
The Window
The Window
The Window
My Object
My Object
The Window
The Window
The Window
The Window
The Window
My Object

文章参考文献

  • 《JavaScript 高级程序设计》
  • JavaScript 之彻底搞懂 this 的指向
正文完
 0