this全面解析

本文深入探讨JavaScript中this的四种绑定规则:默认绑定、隐式绑定、显式绑定和new绑定,以及它们的优先级。通过实例解析调用位置、上下文对象和函数调用方式如何影响this的指向,并特别讨论了箭头函数的词法作用域。
摘要由CSDN通过智能技术生成

一、调用位置

先看看什么是调用栈和调用位置

function baz() {
	// 当前调用栈是baz
	// 因此,当前调用位置是全局作用域
	console.log("baz")
	bar()
}
function bar() {
	// 当前调用栈是baz -> bar
	// 因此,当前调用位置在baz中
	console.log("bar")
	foo()
}
function foo() {
	// 当前调用栈是baz -> bar -> foo
	// 因此,调用位置在bar中
}
baz() // <- baz的调用位置

二、绑定规则

1.默认绑定

最常见的函数调用类型:独立函数调用,可以看作是无法应用其他规则时的默认规则

function foo() {
	console.log(this.a)
}
var a = 2
foo(); // 2

var 声明了一个全局变量a,理解为全局对象的一个属性,foo调用时,this指向全局对象
但是如果使用了严格模式

function foo() {
	"use strict"
	console.log(this.a)
}
var a = 2
foo(); //TypeError: this is undefined

值得注意的是,foo只有运行在非严格模式下,默认绑定才是全局对象;但是在严格模式下调用不会影响默认绑定

function foo() {
	console.log(this.a)
}
var a = 2
(function(){
	"use strict"
	foo() // 2
})()

2.隐式绑定

另一条需要考虑的是调用位置是否有上下文对象

function foo() {
	console.log(this.a)
}
var obj = {
	a: 2,
	foo: foo
}
obj.foo(); // 2

obj调用它,所以this指向obj
this.a === obj.a

function foo() {
	console.log(this.a)
}
var obj2 = {
	a: 42,
	foo: foo
}
var obj1 = {
	a: 2,
	obj2: obj2
}
obj1.obj2.foo(); // 42

obj2调用它,所以this指向obj2
this.a === obj2.a

被隐式绑定的函数会丢失默认绑定对象,也就是说他会应用默认绑定。从而把this绑定到全局对象或者undefined上

function foo() {
	console.log(this.a)
}
var obj = {
	a: 2,
	foo: foo
}
var bar = obj.foo; //函数别名
var a = 'global'
bar(); // 'global'

实际上bar是对obj.foo的一个引用,但是obj.foo引用的还是foo函数本身,因此应用了默认绑定

还有一种情况发生在回调函数里面

function foo() {
	console.log(this.a)
}
function doFun(fn) {
	fn()
}
var obj = {
	a: 2
	foo: foo
}
var a = 'global'
doFun(obj.foo) // 'global'

参数传递其实就是一种隐式赋值,因此我们传入函数时也会被隐式赋值

3.显式绑定

1.硬绑定

function foo() {
	console.log(this.a)
}
var obj = {
	a: 2
}
var bar = function() {
	foo.call(obj)
}
bar() // 2
setTimeout(bar, 200); // 2

硬绑定的典型应用场景就是创建一个包裹函数,负责接收参数并返回值

function foo(something) {
	console.log(this.a, something)
	return this.a + something
}
var obj = {
	a: 2
}
var bar = function() {
	return foo.apply(obj, arguments)
}
var b = bar(3) //2  3
console.log(b) //5

另一种方法是创建一个可以重复使用的辅助函数:

function foo(something) {
	console.log(this.a, something)
	return this.a + something
}
// 简单的辅助函数
function bind(fn, obj) {
	return function() {
		return fn.apply(obj, arguments)
	}
}
var obj = {
	a: 2
}
var bar = bind(foo, obj)
var b = bar(3) //2  3
console.log(b) //5

ES5有内置的方法Function.prototype.bind,用法如下:

function foo(something) {
	console.log(this.a, something)
	return this.a + something
}
var obj = {
	a: 2
}
var bar = foo.bind(obj) 
var b = bar(3)//2 3
console.log(b)//5

2.API调用上下文
第三方库的许多函数,以及JavaScript语言的宿主环境中许多新的内置函数,都提供了一个可选的参数,通常被成为上下文,其作用和bind一样,确保你的回调函数使用指定的this

function foo(e) {
	console.log(e, this.id)
}
var obj = {
 id: 'awesome'
}
[1,2,3].forEach(foo, obj); // 1 awesome 2 awesome 3 awesome

4.new绑定

这是第四条也是最后一条绑定规则
使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
1.创建一个全新的对象
2.这个对象会被执行prototype连接
3.这个新对象会绑定到函数调用this
4.如果这个函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

function foo() {
	this.a = a
}
var bar = new foo()
console.log(bar.a) //2

三、优先级

了解了函数调用中this绑定的四条规则,我们需要找到函数的调用位置并判断应当适用哪条规则,如果某个调用位置适应多条规则,就出现了一个优先级的问题
默认绑定是优先级最低的,看看隐式绑定和显是绑定之间的优先级

function foo() {
	console.log(this.a)
}
var obj1 = {
	a: 2
	foo: foo
}
var obj2 = {
	a:3
	foo: foo
}
obj1.foo() //2
obj2.foo() //3
obj1.foo.call(obj2) //3
obj2.foo.call(obj1) //2

可以看到显是绑定优先级比隐式绑定高
现在需要比较new绑定和隐式绑定的优先级谁高谁低

function foo(something) {
	this.a = something
}
var obj1 = {
	foo: foo
}
var obj2 = {}
obj1.foo(2) 
console.log(obj1.a) //2

obj1.foo.call(obj2, 3)
console.log(obj2.a) //3

var bar = new obj1.foo(4)
console.log(obj1.a) //2
console.log(bar.a) //4

可见new绑定比隐式绑定优先级高
那么new绑定跟显是绑定谁优先级更高呢
new和call apply无法一起使用,但是我们可以用bind

function foo(something) {
	this.a = something
}
var obj1 = {}
var bar = foo.bind(obj1)
bar(2)
console.log(obj1.a) //2

var baz = new bar(3)
console.log(obj1.a) //2
console.log(baz.a) //3

4.this词法

前面介绍的四条规则已经可以包含所有正常的函数。但是ES6中介绍了一种无法使用这些规则的特殊函数:箭头函数。
先看看箭头函数的词法作用域:

function foo() {
	return (a) => {
		console.log(this.a)
	}
}
var obj1 = {
	a: 2
}
var obj2 = {
	a: 3
}
var bar = foo.call(obj1);
bar.call(obj2); // 2

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值