js函数中this是面试官最喜欢考察的,整理一下常用的this指向的知识点。
一、全局上下文
非严格模式和严格模式中this都是指向顶层对象
| this.myname = 'xyf' console.log(this)
|
二、函数上下文
普通函数
在非严格模式下,普通函数的this指向window
{.line-numbers} | var myname = 'xyf' var sayName = function(){ console.log(this === window) console.log(this.myname) } sayName()
|
这里的sayName()
相当于调用了window.sayName()
。在严格模式下,普通函数的this指向undefined
| 'use strict' var myname = 'xyf' var sayName = function(){ console.log(this === window) console.log(this.myname) } sayName()
|
在ES5中,var会给顶层对象中(浏览器是window)添加属性,而使用let则不会。
| let myname = 'xyf' let sayName = function(){ console.log(this === window) console.log(this.myname) } sayName()
|
谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里
对象中的函数
对象中的函数this指向对象本身
| var myname = 'outside name' var sayName = function(){ console.log(this.myname) }
var person = { myname: 'inside name', sayName: sayName, other: { myname: 'other name', sayName: sayName, } }
person.sayName() person.other.sayName()
|
将对象中的函数赋值成变量,这样又变成普通函数,this指向顶层对象。
| var newSayName = person.sayName; newSayName()
|
谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里
所以,通过上面我们可以看出来,函数的定义位置不影响其this指向,this指向只和调用函数的对象有关。
call、apply、bind改变this指向
通过call、apply、bind可以改变函数this的指向
语法:
| fun.call(thisArg, arg1, arg2, ...) fun.apply(thisArg, [arg1, arg2, ...])
|
thisArg是fun函数在运行时指定的this的值。但是指定的this值不一定就是该函数执行时真正的this值。如果这个函数处于非严格模式下,指定为null和undefined的this值会自动指向全局对象(windows中就是window对象);指定为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象;
| var sayName = function(name1,name2){ console.log(this, name1, name2) }
sayName.call(1, 'a', 'b')
sayName.call(null, 'a', 'b')
sayName.call(undefined, 'a', 'b')
|
apply和call类似。只是参数不一样。它的参数是数组(或者类数组)。
谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里
| sayName.apply(1, ['a', 'b'])
|
严格模式下,指向null和undefined的this值还是指向原来的。
| var sayName = function(name1,name2){ 'use strict' console.log(this, name1, name2) }
sayName.call(null, 'a', 'b')
|
bind和call和apply的调用方式相同,第一个值也是修改this的指向,只不过bind返回一个新的函数。
构造函数调用模式
| function Dog(name){ this.name = name; console.log(this) }
var puppy = new Dog('apple')
|
由此可知,new操作符调用时,this指向生成的新对象。
原型链中的调用模式
| function Dog(name){ this.name = name; }
var puppy = new Dog('apple') Dog.prototype.bark = function(){ console.log(this, this.name) } puppy.bark()
|
箭头函数调用模式
先看箭头函数和普通函数的重要区别:
- 没有自己的this、super、arguments和new.target绑定。
- 不能使用new来调用。
- 没有原型对象。
- 不可以改变this的绑定。
- 形参名称不能重复。
谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里
箭头函数中没有this绑定,必须通过查找作用域链来决定其值。 如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this,否则this的值则被设置为全局对象。 比如:
| var name = 'out' var people = { name: 'xyf', sayName: function(){ var arrowFun = () => { console.log(this.name) } arrowFun() }, arrowSayName: () => { console.log(this.name) } } people.sayName() people.arrowSayName()
|
总结
如果要判断一个运行中函数的 this 绑定, 就需要找到这个函数的直接调用位置。