this 是 JavaScript 语言的一个关键字。会随着执行环境的变化而变化。
-
在全局环境下,
this始终指向的是全局对象window,无论是否在严格模式下 -
普通函数内部的this(默认绑定)
// 非严格模式 function fn1() { return this } fn1() // window // 严格模式下 function fn1() { 'use strict'; // 使用严格模式 return this } fn1() // undefined嵌套函数中的this指向
var name = 'Mike' var obj = { name: 'Kobe', fn1: function() { console.log(this.name) function fn2() { console.log(this.name) } return fn2 }} // Kobe // Mike所以,非严格模式下this指向window,严格模式下是undefined
**对于多层嵌套的对象,匿名函数或者普通函数指向的依然是window,**所以fn2的name应该是window的
var name = 'Mike' var obj = { name: 'Kobe', fn1: function() { console.log(this.name) } } var fn = obj.fn1 fn() // Mike新建了变量fn,直接等于fn1这个函数,所以this的指向是window。对于使用变量给函数变名是相当于把this指向了window。
-
构造函数中的指向
function Person2(name) { this.name = name } var person2 = new Person2('Mike') person2.name // Mike构造函数中的this与被创建的新对象绑定
function Person(name) { this.name = name } Person.prototype.getName = function() { return this.name } var Kobe = new Person('kobe') // kobe构造函数的也是指向新创建的实例
-
显式绑定(通过call,bind,apply的方式显式改变this指向)
var obj = { name: 'Kobe', fn1: function(){ console.log(this.name) console.log(argument) } } var param = {name: 'Mike'} obj.fn1.call(param, 1, 2) // Mike Arguments(3) [1, 2, 3] obj.fn1.apply(param, [1, 2]) // // Mike Arguments(3) [1, 2, 3]如果将
null或者undefined传入,值都会被忽略,应用的还是默认绑定var foo = { name: 'Kobe' } var name = 'Mike' function fn1() { console.log(this.name) } foo.call(null) // Mike -
箭头函数
var name = 'Kobe' var obj = { name: 'Mike', fn1: function() { console.log(this.name) } fn2: () => { console.log(this.name) } } obj.fn1() // 'Mike' obj.fn2() // 'Kobe'fn2箭头函数,指向作用域上一层是obj,所以打印出来的是window下面的name。箭头函数体内的this对象,指向的是外层作用域(离被调用函数最近的对象)
下面是一些练习题可供我们回顾复习一下
-
题目一
var name = 'Kobe' function fn1() { console.log(this.name) } (function() { 'use strict' fn1() }) // Kobe
因为在调用fn1函数的依然是window,所以能正确打印出Kobe。但如果是this.fn1()就会报错,在里面严格模式,使用的this会是undefined
-
题目二
var obj = { name: 'Kobe', getName: function() { console.log('getName: ', this.name) return function() { console.log('fn: ', this.name) } } } var name = 'window' var obj1 = { name: 'Mike' } obj()() // getName: Kobe fn: window obj.getName.call(obj1)() // getName: 'Mike' fn: window obj.getName().call(obj1)() // getName: 'Kobe' fn: Mike
通过call来改变this的指向
-
题目三
var name = 'Kobe' function Person(name) { this.name = name this.obj = { name: 'obj' fn1: function() { return function() { console.log(this.name) } }, fn2: function() { return () => { console.log(this.name) } } } } var p1 = new Person('p1') var p2 = new Person('p2') p1.obj.fn1()() // 'Kobe' p1.obj.fn1.call(p2)() // 'Kobe' p1.obj.fn1().call(p2) // 'p2' p1.obj.fn2()() // 'obj' p1.obj.fn2.call(p2)() // 'p2' p1.obj.fn2().call(p2) // 'obj'
匿名函数指向的是window,可以通过call去修改this指向。箭头函数是没有this,所以无法修改this指向。只能根据上层函数的this指向来决定。
总结一下
- 函数如果是在new中调用,this绑定的是新创建的对象
- 匿名函数的this指向永远是window
- 在某个上下文对象中调用,this绑定的是上下文对象
- 默认绑定的是window,严格模式下绑定到的是undefined
- 如果传入undefined和null作为this的绑定对象传入,值会被忽略
- 如若是箭头函数的话,this指向继承的外层代码this
- 隐式绑定丢失的原因:把函数当作参数传递或者使用变量给函数起别名