JavaScript this关键字总结

this

前言

this 关键字在绝大多数语言里面都存在(C语言没有此关键字),与其他语言相比,函数的 this 关键字在 JavaScript 中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别。

下面我们来详细的了解一下,JavaScript 中的 this 到底是什么。

定义

this的定义需要去看规范文档,在 ECMAScript 规范中是这样写的:The this keyword evaluates to the value of the ThisBinding of the current execution context.

翻译:
this 关键字的值等于当前上下文 this 绑定的值

全局上下文

在全局执行上下文中(在任何函数体外部)this 都指代全局对象,浏览器的全局对象是 window,node 的全局对象是 global。

// 在浏览器中, window 对象同时也是全局对象:
console.log(this === window); // true

this.name = "yz";
console.log(window.name)  // "yz"
console.log(name)         // "yz"

函数上下文

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

单独函数调用
var name = "window";
function f1() {
  var name = "f1"
  console.log(this.name); // window
}
f1(); // f1()的执行上下文是全局对象,相当于 window.f1()

上述代码不是在严格模式下执行的,所以 this 默认指向 window

在严格模式下,this 将保持他进入执行上下文时的值,所以下面的 this 将会默认为 undefined,因为他没有被执行上下文所定义。

function f2() {
  "use strict"
  console.log(this); // undefined
}
f2(); 
构造函数调用

回顾一下构造函数创建实例的过程:

new操作符调用构造函数创建实例经历下面四个步骤:
1)创建一个新对象
2)将构造函数的作用域赋给新对象(因此this指向了这个新的对象)
3)执行构造函数中的代码(为这个新对象添加属性)
4)返回构造函数

所以当使用new关键字构建一个新的对象,this会绑定到这个新对象。

var name = "window";
function f1() {
  console.log(this.name); // undefined
}
new f1(); // this指向 new 创建的对象,this.name未定义

function f2() {
  this.name = "f2";
}
var fn = new f2();
console.log(fn.name); // "f2"
对象的方法调用
var obj = {
  foo: function(){
    console.log(this === obj) // true
  }
}

obj.foo() 

foo 作为对象 Obj 的方法被 Obj 调用,this 指向的便是 Obj 对象。

call和apply方法

如果要想把 this 的值从一个上下文传到另一个,可以通过使用函数继承自Function.prototype 的 call 或 apply 方法将 this 值绑定到调用中的特定对象。

var obj = {
  name: "obj",
  foo: function(a, b){
    console.log(this.name)
  }
}
var obj2 = {
    name: "obj2"
}
obj.foo() // "obj"
obj.foo.call(obj2) // "obj2"
obj.foo.apply(obj2) // "obj2"

call 和 apply 的区别在于传入参数形式不一样,第一个参数都是绑定的新对象,call 可以传入任意多个参数,apply只能传入两个,第二个参数是数组形式。

function add(c, d) {
  console.log(this.a + this.b + c + d); 
}

var o = {a: 1, b: 3};

// 第一个参数是作为‘this’使用的对象
// 后续参数作为参数传递给函数调用
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

// 第一个参数也是作为‘this’使用的对象
// 第二个参数是一个数组,数组里的元素用作函数调用中的参数
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
bind方法

ECMAScript 5 引入了 Function.prototype.bind。调用fn.bind(obj)会创建一个与fn具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。bind后函数不会执行,只是返回一个改变了this指向的函数副本,而call和apply是直接执行函数。

function fn(){
  return this.name;
}
var obj = {
    name: "obj"
}
var f1 = fn.bind(obj);
console.log(f1()); // "obj"

var obj2 = {
    name: "obj2"
}
var f2 = f1.bind(obj2); // 注意,bind只绑定一次
console.log(f2()); // "obj"
箭头函数

在箭头函数中,this与执行上下文的this保持一致。在全局代码中,它将被设置为全局对象:

var foo = (() => this);
console.log(foo() === window); // true

在其他函数内创建的箭头函数:这些箭头函数的this被设置为执行上下文的:

var obj = {
    foo: function() {
        var x = (() => this);
        return x;
    }
};

// 作为obj对象的一个方法来调用foo,把它的this绑定到objvar fn = obj.foo();
console.log(fn() === obj); // true

// 但是注意,如果你只是引用obj的方法,而没有调用它
var fn2 = obj.foo;
// 那么调用箭头函数后,this指向window
console.log(fn2()() === window); // true
定时器setTimeout和setInterval
var name = "window";
var Obj = {
  name: "obj",
  foo: function() {
    setTimeout(function() {
        console.log(this.name);
    }, 1);
  }
}
Obj.foo(); // "window"

超时调用的代码都是在全局作用域中执行的,因此函数中this的值在非严格模式下指向window对象,在严格模式下是undefined。

注意,如果使用箭头函数的话,this 是会绑定到obj这个上下文,如下:

var name = "window";
var Obj = {
  name: "obj",
  foo: function() {
    setTimeout(() => console.log(this.name), 0);
  }
}
Obj.foo(); // "obj"

总结

1.this 的值就是被调用时上下文环境绑定的值;
2.在全局作用域,this 指向全局对象 (window 或者 global),严格模式下为 undefined;
3.当使用new关键字声明,this指向新建对象;
4.可以使用call(), bind(), apply()来设置 this;
5.箭头函数不会绑定 this,this 是他执行的上下文环境;
6.超时代码都是在全局作用域执行的,thi s指向全局对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值