1.看题
先来看几道题目,如果都做对了的话;那么恭喜你,可以跳过这篇文章。省下几分钟时间。
答案在题目后面
//第一题
function whatIsThis1() {
"use strict"
return this
}
function whatIsThis2() {
return this
}
console.log(whatIsThis1() === window);
console.log(whatIsThis2() === window);
//第二题
const that1 = {
whatIsThis: function () {
return this
}
}
const that2 = {
whatIsThis: that1.whatIsThis
}
const identify = that2.whatIsThis;
console.log(that1.whatIsThis() === that1);
console.log(that2.whatIsThis() === that1);
console.log(identify() === that1);
console.log(that1.whatIsThis.call(that2) === that2);
//第三题
function That() {
this.whatIsThis = () => this;
}
const that1 = new That();
const that2 = {
whatIsThis: that1.whatIsThis
}
console.log(that1.whatIsThis() === that1);
console.log(that2.whatIsThis() === that2);
//第四题
function That() {
this.whatIsThis = function(){
return this
}.bind(this)
}
const that1 = new That();
const that2 = {
whatIsThis: that1.whatIsThis
}
console.log(that1.whatIsThis() === that1);
console.log(that2.whatIsThis() === that2);
答案
//第一题
false
true
//第二题
true
false
false
true
//第三题
true
false
//第四题
true
false
2. js中的this是什么
2.1. 在全局上下文中
无论是否处于严格模式,this都指向全局对象,在浏览器环境,即this===window。
2.2. 在函数上下文中
this表示函数上下文,即与函数调用相关联的对象。通常称之为函数上下文。this的值与函数调用方式和定义方式有关
- 在严格模式下,如果执行环境中没有指定this的值,则this===undefined
- 在非严格模式下,this的值与函数调用方式和定义方式有关。下面从函数调用方式开始,来看下this的取值。
3.函数调用方式
3.1.作为函数直接被调用
这是函数最简单直接的调用方式。声明一个函数,然后执行。
function whatIsThis(){
return this
}
whatIsThis()
这种方式没有指定this的值,在严格模式下this===undefined;非严格模式下,则默认指的是全局上下文,在浏览器中即this===window
3.2. 作为方法被调用
函数作为一个对象的属性被调用,此时this绑定的就是该对象。函数内部可以也通过this访问到对象的所有属性。
function whatIsThis(){
return this.name;
}
const that1 = {
name:'that1',
getThis:whatIsThis
}
that1.getThis()
这里新建了一个whatIsThis函数和that1对象,that1的属性getThis是对函数whatIsThis的引用。g通过that1.getThis(),执行的就是 whatIsThis本身。此时,that1也就成了whatIsThis的上下文了。
3.3. 作为构造函数被调用
作为构造函数调用跟3.2作为方法调用类似。
要通过构造函数调用,就需要使用new关键字。
function whatIsThis(){
return this;
}
function That() {
this.getThis = whatIsThis
}
const that = new That();
that.getThis()
这里简单说下new关键字都做了什么事情
- 创建一个空对象
- 创建的对象被作为this参数传递给构造函数,作为构造函数的上下文
- 创建的对象作为返回值返回
以上代码通过构造函数方式new That()调用,每次都会产生一个新的对象,每个对象下都有getThis属性引用whatIsThis。这里that.getThis()就相当于3.2中函数作为对象方法被调用,函数whatIsThis的上下文自然就是调用方法的对象that。
3.4.使用apply和call调用
apply和call都可以显式地为函数绑定特定的函数上下文。两者的区别仅仅是参数不同。第一个参数都是要指定的上下文对象。call剩余参数则是对应函数的一个个参数;apply的第二个参数是函数参数的数组集合。
fn.call(context,arg1,arg2...)
fn.apply(context,[arg1,arg2...])
function whatIsThis(){
console.log(this)
console.log(arguments)
}
const that1={name:'that1'}
const that2={name:'that2'}
whatIsThis.call(that1,1,2)
whatIsThis.apply(that2,[1,2])
call和apply都会显示地把第一个参数作为函数whatIsThis的上下文。
whatIsThis.call(that1,1,2) 会绑定that1作为函数whatIsThis的上下文。
whatIsThis.apply(that2,[1,2]) 则会绑定that2作为函数whatIsThis的上下文。
4.箭头函数和bind
4.1.箭头函数
箭头函数没有单独的this值。箭头函数的this取决于箭头函数声明时的上下文。
const arrowFn = ()=>this
const that1 = {
getThis:arrowFn
}
function That(){
this.getThis = ()=>this
}
const that2 = new That()
that1.getThis()
that2.getThis()
that1对象中的getThis是arrowFn引用,arrowFn声明在全局上下文中,因此that1.getThis()中this===window
that2通过构造函数调用,this被绑定为构造函数新建的对象,这里构造函数新建的对象被that2引用,即this===that2
4.2. bind
bind同样能显示的绑定函数上下文,与call和apply不同的是,bind返回一个重新绑定上下文后的新函数,而不是执行函数。
const that1 ={name:'that1'}
function That(){
this.getThis = function(){return this}
}
const that2 = new That()
that2.getThis
const newGetThis = that2.getThis.bind(that1)
newGetThis()
通过构造函数调用that2.getThis()时,getThis中的this即为that2
而newGetThis中的上下文已经通过bind重新绑定为that2
5.总结
- this表示函数上下文,即与函数调用相关联的对象。this的值与函数调用方式和定义方式有关
- 函数作为函数调用;非严格模式下,this指向全局window对象;严格模式下则指向undefined
- 函数作为方法调用;this通常指向调用的对象
- 函数作为构造函数调用;this指向新创建的对象
- 通过call、apply调用;this指向call、apply的第一个参数
- 箭头函数this取决于声明的时候
- 函数可通过bind返回一个新的函数,返回的函数中this指向bind方法传入的参数