【JavaScript】深入理解this关键字

this,是一个对象,this的值取决于code是怎么执行的。

在开始之前,我们需要理解一下JavaScript运行时环境和JavaScript code是如何执行的。

执行环境

代码行被执行时所处的环境被称为执行环境,JavaScript runtime维护着一个栈,栈里面包含这些执行环境,位于栈顶的执行环境是当前正在执行的环境。this指向的对象随着执行环境的改变而改变。

this指向全局对象

执行环境默认是全局的——意味着,如果代码作为简单函数调用执行,那么this指向全局对象。
在浏览器中,全局对象指window对象。在Node.js环境里,有一个叫做global的特殊对象是全局对象。
例如:

function foo() {
	console.log(“这就叫做简单函数调用”);
	console.log(this===window);
}
foo(); //true
console.log(this === window) //true

立即调用的函数表达式(IIFE)

(function() {
	console.log(“Anonymous function invocation”);
	console.log(this === window);
})();
//true

如果函数是严格模式,那么this的值将会被标记为 undefined。全局对象指向undefined而不是window对象。
例如:

function foo() {
	‘use strict’;
	console.log(“simple function call”);
	console.log(this === window);
}
foo(); //false

严格模式下,全局执行环境中的this值为undefined。

“this”指向一个新实例

当使用new关键字调用函数的时候,这个函数就被作为构造器函数并且返回一个新实例。在这类情况下,this的值指向那个新创建的实例。
比如:

function Persion(fn, ln) {
	this.first_name = fn;
	this.last_name = ln;

	this.displayName = function() {
		console.log(‘Name:${this.first_name} ${this.last_name});
	}
}
let person = new Persion(“John”, “Reed”);
persion.displayName(); //John Reed
let persion2 = new Persion(“Paul”, “Adams”);
persion2.displayName(); //Paul Adams

“this”指向主调对象(父对象)

在JavaScript中,对象的属性可以是方法和简单的值。当对象调用方法时,方法里面的this就指向这个对象。
在本例中,我们将使用到foo方法(在第一个例子中定义的)

function foo() {
	‘use strict’;
	console.log(“Simple function call”);
	console.log(this === window);	
}
let user = {
	count: 10,
	foo:foo,
	foo1: function() {
		console.log(this ===window);
	}
}
user.foo(); //false, 因为现在this指向user对象而不是全局对象
let fun1 = user.foo1;
user.foo1() //false, foo1作为一个对象的方法被调用.

“this”与Call和Apply方法

JavaScript中,函数也是特殊的对象。每个函数都有call,bind,apply方法。这三个方法可以被用来给this设定一个自定义的值。
我们将使用到在解释call使用的之前定义的第二个例子(代码如下):

function Person(fn, ln) {
	this.first_name = fn;
	this.last_name = ln;

	this.displayName = function(){
		console.log(‘Name:${this.first_name} ${this.last_name});
	}
}
let person =  new Person(“John”, “Reed”); 
person.displayName(); // John Reed
let persion2 = new Person(“Paul”, “Adams”);
person2.dispalyName(); // Paul Adams

person.displayName.call(person2); // 在这里我们设置this的值为person2对象
// 打印: Paul Adams

call方法和apply方法唯一的不同是参数传递的方式, 对于apply,第二个参数是参数数组,而对于call,参数被单独传递。

“this” 与 bind方法

bind方法返回一个新方法,this指向传递的第一个参数。我们将使用上面的例子来解释bind方法。

function Person(fn, ln) {
	this.first_name = fn;
	this.last_name = ln;

	this.displayName = function(){
		console.log(‘Name:${this.first_name} ${this.last_name});
	}
}
let person =  new Person(“John”, “Reed”); 
person.displayName(); // John Reed
let persion2 = new Person(“Paul”, “Adams”);
person2.dispalyName(); // Paul Adams

let person2Display = person.displayName.bind(person2); // 创建一个函数,this的值等于person2对象
person2Dispaly(); // 打印: Paul Adams

“this”和宽箭头(Fat-Arrow)函数

在ES6中,引入了一种新方式来定义函数。

let dispalyName = (fn, ln) => {
	console.log('Name:${fn} ${ln}');
	console.log(this === window); // true
};

当宽箭头被使用时, 它并没有为this创建新值。this继续引用它在函数外面引用的同一对象(什么叫在函数外面引用的对象?)。
更新: 解释为什么 => 箭头函数没有this, this会作为变量一直往上级词法作用域查找, 经常导致undefined错误(来自vue.js)

我们来看更多的例子来测试this的知识

function multiply(p, q, callback) {
	callback(p*q); // 译者: 简单函数调用,所以callback方法内的this为全局对象
}
let user = {
	a:2,
	b:3,
	findMultiply: function(){
		multiply(this.a, this.b, function(total) {
			console.log(total);
			console.log(this === window);
		})
	}
}
user.findMultiply();
// 打印 6
// 打印 true

因为callback 在一个乘法函数中被当作简单函数调用来引用, this指向callback方法的执行环境里面的全局对象window

var count =5;
function test() {
	console.log(this.count===5);
}
test() // 打印 true,因为count变量声明发生在全局执行环境中,所以count将成为全局对象的一部分

Summary

所以现在你能理解this的值,通过下面这些简单的规则:

  • 默认情况下,this指向一个全局对象,其对于浏览器是window,对于Nodejs是global
  • 当函数作为对象的属性调用时,this就指向这个父对象
  • 当用new关键字调用函数时,this指向新创建的实例
  • 当使用call和apply方法调用函数时,this指向call或apply方法的第一个参数传递的值

如你所见,this的值有时候是很迷惑的,但是以上的规则能够帮助你理解this的值。

本文为英文article的翻译: Understanding the “this” Keyword in JavaScript
翻译不易,客官点赞/收藏/关注呀,giao~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值