JS - this指向

一、什么是this

A function's this keyword behaves a little differently in JavaScript compared to other languages. It also has some differences between strict mode and non-strict mode.

从官方文档我们可知

  • this是一个关键字
  • this主要用在函数中
  • this 在strict mode下指向有一些不同

1.1 全局环境

无论是否在strict mode,在全局执行环境中(在任何函数体外部)this 都指向全局对象。(浏览器中window为ECMAscript规定的Global对象)

"use strict"
//在 Node 中
console.log(this) // {}

//在浏览器中
console.log(this) //window
console.log(this === window) //true
this.foo = "foo"
console.log(window.foo) //foo
window.bar = "bar"
console.log(this.bar) //bar
1.1.1执行上下文(Execution Context)

在全局作用域var关键字声明变量和省略声明的变量都会添加为全局对象的属性

var foo = "foo"
bar = "bar"
this.foo  // foo
this.bar  // bar

const 、let 关键字声明的变量有自己的作用域

const foo = "foo"
let bar = "bar"
this.foo  // undefined
this.bar  // undefined

1.2 函数(运行内)环境

在函数内部,this的指向取决于函数被调用的方式。

1.2.1函数简单调用
//非严格模式下  this 的值默认指向全局对象。
function foo() {
  return this
}
// 在Node 中
foo() // Object [global]

//在浏览器中
foo() //window
//严格模式下 this 默认为undefined。
function foo() {
  "use strict"
  return this
}
// 在Node 中
foo() // undefined

//在浏览器中
foo() // undefined
1.2.2 函数作为对象的方法调用

(1) 当函数作为方法被调用时, this 指向调用该方法的对象

var foo = {
  fn:function(){
    return this
  }
}
foo.fn() // foo
var foo = {}
function fn() {
  return this
}
foo.fn = fn
foo.fn() // foo

(2) 链式调用,this指向上一个绑定对象

var bar = {
  fn:function(){
    return this
  }
}
var foo = {
  bar : bar
}
foo.bar.fn() // this ->bar

(3)当函数调用时没有绑定任何对象,隐式丢失

// 隐式丢失
var foo = {
  fn:function(){
    return this
  }
}
var bar = foo.fn 
bar() // window

二、this与箭头函数

2.1 箭头函数中,this与最近作用域的this相同

var foo = {
  fn: function () {
    return () => {
      return this
    }
  },
}
var bar = foo.fn()
bar() // this -> foo

fn函数返回一个匿名箭头函数,箭头函数中的this向上一层级找,此时箭头函数中的this = fn中的this

2.2 对象的方法中的箭头函数

var foo = {
  bar : this,
  fn :() => {
    return this
  }
}
foo.bar // window
foo.fn() //window

此时fn函数虽然作为foo的方法调用,但由于箭头函数向上找作用域this的缘故,箭头函数的this指向window

三、this与匿名函数

this对象是基于函数的运行环境绑定的
因为匿名函数的执行环境有全局性,因此this对象常指向window

var foo = {
  fn: function () {
    return function () {
      return this
    }
  },
}
foo.fn()() // this -> window

为什么匿名函数作用域的this没有访问外部作用域fn中的this呢?
因为函数在调用时会自动取得两个特殊的变量,this和arguments,匿名函数本身也会取得指向window的this,一旦搜得其活动对象即停止.

那么如何访问fn中的this呢

3.1 通过闭包保存

var foo = {
  fn: function () {
    var _this = this
    return function () {
      return _this
    }
  },
}
foo.fn()() // _this -> foo

3.2 通过箭头函数访问外部作用域

var foo = {
  fn: function () {
    return () => {
      return this
    }
  },
}
foo.fn()() // this -> foo

四、this与call()和apply()

可以通过使用函数继承自Function.prototype的call或 apply 方法将 this值绑定到调用中的特定对象。

var foo = {}
var args = []
function bar(...args) {
  return this
}
bar.call(foo,...args) // this -> foo
bar.apply(foo,args) // this -> foo

call和apply的区别为,call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。

五、this与bind()

ECMAScript 5 引入了 Function.prototype.bind()。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。

var obj = {}
function bar (){
  return this
}
var foo = bar.bind(obj)
foo() // this -> obj
obj.foo = foo 
obj.foo() //this -> obj

六、this与getter和setter

当函数在一个 getter 或者 setter 中被调用。用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。

var foo = {}
Object.defineProperty(foo ,'bar',{
  get(){
    return this
  }
})
foo.bar // this -> foo

七、this与构造函数

当一个函数用作构造函数时(使用new关键字),this被绑定到构造的新对象。

function foo(why) {
  this.why = why
}
var bar = new foo("why")
bar.why // -> why

八、this与DOM事件处理函数

绝大部分浏览器,当函数被用作事件处理函数时,它的this指向触发事件的元素

var btn = document.getElementsByClassName("btn")
for (var i = 0; i < btn.length; i++) {
  btn[i].addEventListener('click',()=>{
    return this
  })
}
// this ->btn[i]

总结

非严格模式下,浏览器中

  • 函数外this指向window
  • 函数内this指向取决于调用方式
  • 箭头函数this指向向上一层作用域的this
  • 匿名函数this指向window

你可能感兴趣的:(JS - this指向)