关于js中的this,你知道多少?

关于this

this关键字是javascript中最复杂的机制之一。它是一个很特别的关键字,被自动定义在所有函数的作用域中。

1、为什么要使用this

function foo() {
	return this.age
}
function bar() {
	const c = `小明今年${foo.call(this)}岁了` // ${}为es6模板字符串用法
}
var obj1 = {age: 16}
foo.call(obj1)  // 16
bar.call(obj1)  // 小明今年16岁了
function foo(context) {
	return context.age
}
function bar(context) {
	const c = `小明今年${foo(context.age)}岁了` // ${}为es6模板字符串用法
}
var obj1 = {age: 16}
foo(obj1)  // 16
bar(obj1)  // 小明今年16岁了

上面两段代码,一个是用了this,一个没有用this,如果没有用this,那就需要给 foo() 和 bar() 显示的传入上下文对象context。这样也会存在一个问题,当你的业务场景越来越复杂时,显示传递上下文会让代码变得越来越混乱,使用this可以很好的避免这种情况。

2、this是什么

要了解this到底是什么样的一种机制,我们首先得抛开“this”字面上的意思。
this是在函数运行时进行绑定的,并不是在编写时绑定的,它的上下文取决于函数被调用时的各种条件。this的绑定和函数申明的位置没有任何的关系,只取决于函数的调用方式。

3、调用位置

const obj = {
	a: 1,
	foo: function() {
		const b = 2
		console.log(this)
	}
}
obj.foo()

我们看这段代码,foo()是obj对象中的一个方法,我们在这个方法中打印this,看看this指向谁?如果按照this字面的意思上看,this肯定是指向foo()这个函数,但是根据我们上面说的内容,这个答案肯定是错误的。
关于js中的this,你知道多少?_第1张图片
上面是浏览器的打印结果,this实际上指向的是obj这个对象的作用域。这也证明了上面讲的,this的上下文取决于函数被调用的各种条件。

4、绑定规则

this的绑定规则有四种,分别是:默认绑定、隐式绑定、显式绑定和new绑定。

1) 默认绑定

function foo() {
	console.log(this)
}
foo()

在代码中,foo() 是直接进行调用的,因此只能使用 默认绑定,无法应用其他规则。
默认绑定情况下,this是被绑定到全局对象下的。
关于js中的this,你知道多少?_第2张图片
上面是foo()函数在浏览器控制台打印出的结果,this被绑定到window对象下。
在node控制台下打印的是nodejs的global对象,如下图:
关于js中的this,你知道多少?_第3张图片
默认绑定情况下需要注意的是,在严格模式下,全局对象无法使用默认绑定,因此this会绑定到undefined。如下:

function foo() {
	"use strict"
	console.log(this)
}
foo() // TypeError: this is undefined

2) 隐式绑定

const obj = {
	a: 1,
	foo: function() {
		console.log(this.a)
	}
}
obj.foo() // 1

上面代码中foo()函数被包含在了obj对象中,那么这种方式我们就可以说是this被隐式的绑定到了obj对象中,这时候通过this就可以访问obj对象中的属性。
但是,隐式绑定会存在一个问题,就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定。
我们看下面一段代码:

const obj = { 
	a: 2, 
	foo: function(){
		console.log(this.a)
	} 
}
const bar = obj.foo
bar()

如果按照上述隐式绑定的规则,那打印结果应该是2,但事实上并不是如此,
关于js中的this,你知道多少?_第4张图片
我们看控制台打印的信息,是undefined。为什么会出现这种情况呢?
虽然 bar 是 obj.foo 的一个引用,但是实际上,它引用的是 foo 函数本身,因此此时的 bar() 其实是一个不带任何修饰的函数调用,因此应用了默认绑定。

3) 显式绑定
上面我们说的隐式绑定是通过在一个对象内部包含一个函数的属性,并通过这个属性去间接的引用这个函数,从而把this间接的绑定到这个对象上。
那显式绑定就是和隐式绑定相反,直接指定this的绑定对象。显示绑定有两种方式:call和apply
1、call

function foo(){
	console.log(this.a)
}
const obj = {
	a: 1
}
foo.call(obj)

通过 foo.call(…),我们可以在调用 foo 时强制把它的 this 绑定到 obj 上。
2、apply
apply的使用方式和call类似。
call和apply的区别在于,call可以接收多个参数,apply只能接收2个参数。
4) new绑定
使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。

  1. 创建(或者说构造)一个全新的对象。
  2. 这个新对象会被执行 [[ 原型 ]] 连接。
  3. 这个新对象会绑定到函数调用的 this。
  4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
function foo(a) {
	this.a = a; 
}
const bar = new foo(2); 
console.log( bar.a ); // 2

使用 new 来调用 foo(…) 时,我们会构造一个新对象并把它绑定到 foo(…) 调用中的 this 上。new 是最后一种可以影响函数调用时 this 绑定行为的方法,我们称之为 new 绑定。

本文结束

本文参考《你不知道的javascript》一书。

你可能感兴趣的:(javascript)