this详解
# 什么是this
this从寓意上来说就是指代事物本身,可以理解是一种简写this可以指代当前的运行环境。例如:window/ 函数执行上下文等- 更加高深的可以理解为:存在规范中的抽象类型,为了更好的描述语言底层行为逻辑才存在的
 this的精髓在于:谁调用this就会指向谁- 具体的this写法,如下列代码中:
 
console.log(this) // window
const obj = {
  name: 'xxx',
  getName() {
    console.log(this.name) // 对象的name属性的值
  }
}
console.log(obj.getName())
 1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 注意点:
this具体的内容跟执行位置有关,跟定义位置无关(跟作用域正好相反)。之后会举例进行说明。
this在不同的场合,代表的内容不同,接下来一一看下:
# 规范下的this
var value = 1;
var foo = {
  value: 2,
  bar: function () {
    return this.value;
  }
}
//示例1
console.log(foo.bar()); // 2
//示例2
console.log((foo.bar)()); // 2
//示例3
console.log((foo.bar = foo.bar)()); // 1
//示例4 
console.log((false || foo.bar)()); // 1
//示例5
console.log((foo.bar, foo.bar)()); // 1
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
重点在于括号左侧的内容,是否会产生运算,如果产生运算的话,就是undefined,反之就是原来的值
- 上述实例1 以及实例2中 因为最左侧括号的右侧内容,并没有进行运算,所以是原来的值
 - 实例3/ 实例4/ 实例5 通过赋值运算后 当前的this是undefined,但是在全局环境下通过隐式类型转换变换为window
 
# 全局下的this
- 在无显示的调用情况下,this指向全局/ 其实就是所谓的window
 - 严格模式下 this会是undefined
 - 任意函数(XXX)调用时,可以理解为window.XXX
 
- 情况1:
 
console.log(this) // window
 1
- 情况2:
 
setTimeout(function () {
  console.log(this) // window
}, 0)
 1
2
3
2
3
- 情况3:
 
const obj = {
  getName: function () {
    console.log(this)
  }
}
const getName = obj.getName
getName() // window
 1
2
3
4
5
6
7
2
3
4
5
6
7
# 函数下的this
- 谁调用函数,那么this就执行谁
 - 但是箭头函数是一个例外,箭头函数的this指向定义当前调用者的上下文(就是所谓上级上下文的this)
 - 如果是多层调用的话,this指向最右侧调用者本身
 
- 函数中调用:
 
var name = 'lihh1'
const user = {
  name: 'lihh2',
  getName: function () {
    return this.name
  },
  getName1: () => {
    return this.name
  }
}
console.log(user.getName()) // lihh2
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 箭头函数中调用:
 
var name = 'lihh1'
const user = {
  name: 'lihh2',
  getName: function () {
    return this.name
  },
  getName1: () => {
    return this.name
  }
}
console.log(user.getName1()) // lihh1
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 多层对象嵌套调用:
 
const user = {
  name: 'lihh1',
  user: {
    name: 'lihh2',
    user: {
      name: 'lihh3',
      getName: function () {
        return this.name
      }
    }
  }
}
console.log(user.user.user.getName()) // lihh3
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# DOM事件下this
- 如果是通过点击事件触发的话,this指向DOM对象
 
<body>
<button id="btn">点击</button>
<script>
  const btn = document.getElementById('btn')
  btn.onclick = function () {
    console.log(this) // <button id="btn">点击</button>
  }
  btn.click()
</script>
 1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 实例对象中的this
- 通过关键字
 new生成一个实例对象后,如果构造函数的返回值是非引用对象类型,那么此时的this就是实例本身- 通过关键字
 new生成一个实例对象后,如果构造函数返回的是一个引用对象,那么此时的this就是返回的引用对象
- 情况1:无返回引用对象
 
function User() {
  this.name = 'lihh'
}
const u = new User()
console.log(u.name) // lihh
 1
2
3
4
5
6
2
3
4
5
6
- 情况2:返回引用对象
 
function Person() {
  this.name = 'lihh1'
  return {
    name: 'lihh2'
  }
}
const p = new Person()
console.log(p.name) // lihh2
 1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# class中的this
- 通过class生成一个实例对象后,此时的this就是实例本身
 
class Person {
  constructor() {
    this.name = 'lihh'
  }
}
const p = new Person()
console.log(p.name) // lihh
 1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 如何绑定this
- 如果我们在实际的业务中就是想让this指向一个特定的值,我们应该用什么办法呢。请看下列三种办法
 
# call
- 使用关键字
call进行函数调用,第一个参数是将要改变的this,之后参数必须一一进行传递 - 关键字
call调用函数后,函数会立即执行 
function getName(a, b) {
  return [this.name, a, b]
}
const user = {
  name: 'lihh'
}
// call
console.log(getName.call(user, 1, 2)) // [lihh, 1, 2]
 1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# apply
- 使用关键字
apply进行函数调用,第一个参数是将要改变的this,之后的参数是数组的形式赋值给第二个参数 - 关键字
apply调用函数后,函数会立即执行 
function getName(a, b) {
  return [this.name, a, b]
}
const user = {
  name: 'lihh'
}
// apply
console.log(getName.apply(user, [1, 2])) // [lihh,1, 2]
 1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# bind
- 使用关键字
bind进行函数调用,第一个参数是将要改变的this,之后参数进行一一赋值 - 关键字
bind调用函数后,会生成一个新的函数,调用此函数才会执行。而且此时也是可以传递函数 
function getName(a, b) {
  return [this.name, a, b]
}
const user = {
  name: 'lihh'
}
const fn = getName.bind(user, 1)
console.log(fn(2)) // ['lihh', 1, 2]
 1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10