干翻this这座大山(二)
前言
在上一篇文章中,我们知道了this的基本指向规则。在这一篇章的内容中我们将继续深入学习this的
一,显式绑定
要想“掰弯”this改变他的指向我们通常有三种方法:利用call
,apply
和bind
1. 用call
和apply
进行显式绑定
大家来看这段代码
var obj = {
a: 1
}
function foo() {
console.log(this.a);
}
foo()
经过上一篇章的学习相信大家已经能秒杀这道题,这不一眼foo独立调用this指向全局嘛,结果显而易见undefined。但是现在如果我想让这个this指向obj我该怎么做呢?这个时候我们的call就登场了~
在JavaScript中,call
是一个内建函数,属于函数原型 (Function.prototype.call
),它允许你调用一个函数,并指定该函数的 this
值(函数运行时上下文中的 this
指向),以及作为单独参数传入的列表。在本题中,在调用foo
函数时,你可以使用点语法和call
方法来指定foo
函数内部this
的指向,通过call
方法的参数来传入你希望this
所引用的对象。那如果需要传参数呢?当foo
函数需要参数x
和y
时,并且你同时还想使用call
方法来指定this
的指向,你可以将需要传递给foo
的参数直接放在call
方法的参数列表中,且这些参数应该放在你想要作为this
的对象之后。,如下
var obj = {
a: 1
}
function foo(x, y) {
console.log(this.a, x + y);
}
foo.call(obj, 2, 3) // 1 5
经过我们.call的修改,this成功的指向了obj且接受了参数。打印出来的结果分别是this指向的a的值1,和x+y的值5。
除了call之外,apply同样也能达到同样的效果,唯一不同的是他们的参数传递方式。apply接收的参数需要用数组装起来,如foo.call(obj, 2, 3)
需改写成foo.apply(obj,[ 2, 3])
的形式。
2.使用bind
进行显式绑定
bind
方法是 JavaScript 中的一个函数实例方法,它用于创建一个新的函数,这个新函数在被调用时,其 this
关键字会被设置为提供的值,同时会创建一个新的函数上下文(返回一个函数体)。
var obj = {
a: 1
}
function foo(x, y) {
console.log(this.a, x + y);
}
var bar = foo.bind(obj,2,3)
bar()
题中 bind
返回的是一个新函数bar,并且这个新函数在被调用时()才会执行原始函数,这个性质由bind的源码决定。值得注意d的是,无论参数在bind()内还是在他返回的函数体bar()内他都能接收且执行,如果两者都传入了参数,则只有bind()内的参数生效。
二,new绑定
要明白构造函数里的this指向我们首先得搞懂new
的底层执行机制,new,他到底做了哪些事情?
在《对象的基本知识,对构造函数的基本认识》一文中我们简要概述了new的作用三部,但在今天学习了原型和this这两篇文章后我们对new又有了新的认识。
new
的作用
new
他到底做了什么?举个例子,对于代码
function Person(){
this.name = 'tao'
}
let p = new Person()
来说,如果没有下面new的构造,this势必会指向全局,
- new第一步在这个函数体内创建一个新的空对象,例obj;
- 设置新对象的
[[Prototype]]
(内部链接),新对象的[[Prototype]]
会被设置为Person.prototype
。 Object.proto = Person.prototype;使得obj的隐式原型等于Person的显示原型; - 构造函数(在这个例子中是
Person
)会被调用,同时传入new
操作符创建的新对象作为this
的上下文。这意味着,构造函数内部有任何对this
的引用,它们都将指向这个新创建的对象。 也可以理解为两步操作:1)在代码执行前new做了一步“掰弯操作”,Person.call(obj),这一步把Person中的所有的this引用都指向了obj;2)执行代码 - 返回新对象。return obj
实际产生的效果等同如下:
function Person() {
//var obj(){
//
// }
// person.call(obj);
// Object.__proto__ = person.prototype;
this.name = 'zhutao'
// return new Person
}
所以这里的答案显而易见, 所以现在我们明白了new 绑定的规则: 通过new创建一个函数,this指向他创建的这个函数。
三,箭头函数中的this
什么是箭头函数
箭头函数是定义函数的一种新方式。箭头函数(Arrow Functions)是ES6(ECMAScript 2015)中引入的一种新的函数定义方式。箭头函数提供了一种更简洁、更直观的语法来编写函数,特别是在处理一些简单的回调函数或者不需要自己this
绑定的场景时非常有用。
对于代码串var bar = () => {}
来说,var定义了一个变量bar,箭头函数语法将其赋值给变量 bar
。他和var bar = function(){}
的表达相同,但是在行为上有所不同。
箭头函数的this
绑定
在JavaScript中,箭头函数(Arrow Functions)有一个特殊的特性,那就是它们不绑定自己的this
值。相反,箭头函数会从自己的作用域链的上一层(词法作用域)中捕获this
值作为自己的this
值。这通常意味着箭头函数中的this
值就是定义它所在的那个上下文中的this
值。
箭头函数体,没有this这个机制,写在他里面的this是他外层非箭头函数的this。不能说箭头函数的this,这句话是错的,因为箭头函数没有this这个机制(没有这个概念)
function foo() {
var bar = () => {
console.log(this);
}
bar()
}
foo()
所以我们来看这串代码,箭头函数里面的this理所应当的指向foo函数。
在本篇的最后让我们再看一道题回顾这两篇所学的知识:
var obj = {
a: 1,
b: function () {
const fn = () => {
console.log(this.a)
}
}
}
obj.b()
请问this指向谁?
首先,b不是独立调用,所以是隐式绑定规则;其次,箭头函数在function b内,所以this在b内。b在obj里面,且b的词法作用域是obj,所以答案显而易见,this指向obj,this.a的值是1。
转载自:https://juejin.cn/post/7369114828076515364