前言
大家好,我是热爱前端的菜鸟luckyCover。
this
this是JavaScript语言的一个
关键字,它是函数运行时,内部产生的一个对象,这个对象只能在函数内部使用
javascript
function test() {
this.x = 1;
}
上边函数运行时,函数内部会自动有一个this对象可以使用。
那么this的值是什么呢?也就是我们常说的this的指向。
函数在不同场合下,this有不同的值。总的来说,this就是函数运行时所在的环境对象。
分以下几种情况:
情况一:纯粹的函数调用
这是最通常的写法,属于全局调用,因此this就代表了全局对象。
javascript
let x = 1;
function test() {
console.log(this.x);
};
test(); //1
情况二:作为对象的函数调用
函数还可以作为某个对象的方法调用,这时候this就指这个上级对象。
javascript
function test() {
console.log(this.x);
};
let obj = {};
obj.x = 1;
obj.m = test;
m(); //1
情况三:作为构造函数调用
所谓构造函数,其实就是new这个函数会产生一个新对象。如果这个函数使用new调用,this就指向这个新创建的对象。
javascript
function test() {
this.x = 1;
};
const obj = new test();
console.log(obj.x); //1
运行结果为1,为了证明此时的this不是全局对象,我们对代码做如下变动:
javascript
let x = 2
function test() {
this.x = 1;
};
const obj = new test();
console.log(x); //2
运行的结果没有变,证明全局变量x的值根本没变。
情况四:apply调用
apply()是函数中的一个方法,作用是改变函数的调用对象。它的第一个参数就表示改变调用这个函数的对象。因此,这时候this的指向就是接收的第一个参数。
javascript
let x = 0;
function test() {
console.log(this.x);
};
const obj = {};
obj.x = 1;
obj.m = test;
obj.m.apply(); //0
apply()参数为空,默认调用全局对象。因此这时的运行结果为0,证明this指向的是全局对象。
如果把最后一行代码修改为:
javascript
obj.m.apply(obj); //1
运行结果就变为1了,证明此时this指向对象obj。
根据上边四种情况,我们可以简单总结一下this指向了。
判断this关键字的引用(即指向)是谁的唯一方法就是看this所在的方法在哪里被调用。
接下来,我们介绍下call、apply、bind这三个关键字
call
call是每个函数都有的一个方法,它允许你在调用某个函数的时候为其指定上下文。
比如下边这段代码:
javascript
function greet() {
alert(`Hello, my name is ${this.name}`);
};
const user = {
name: 'Tyler',
age: 27
};
greet(); //直接调用,此时this指向的是window,由于window上没有name属性,会输出undefined
根据上边的总结,我们都知道为了判断this的引用必须查看这个函数的调用位置。现在就引出一个问题,上面这段js代码中,如果直接调用greet()函数,那么此时的this指向的是全局对象window,然而现在我们要让greet()方法的调用对象是user,也就是让this指向user。这时候就可以用call方法了。
下面的代码可以实现在调用greet()方法时使用user做上下文。
javascript
greet.call(user);
概况一下call属性:call是每个函数都有的一个属性,传递给它的第一个参数会作为调用函数时的上下文。换句话说,this会指向传递给它的第一个参数。
apply
apply函数和call函数唯一的不同就是函数的第二个参数。
我们先来看看以.call调用的例子:
javascript
function greet(lang1, lang2, lang3) {
alert(`Hello, my name is ${this.name} and I know ${lang1}, ${lang2}, and ${lang3}`)
};
const user = {
name: 'Tyler',
age: 27
};
const languages = ['JavaScript', 'Ruby', 'Python'];
greet.call(user, languages[0], languages[1], languages[2]);
使用call方法调用奏效,它显示了如何将参数传递给.call调用的函数。不过,这样传递参数显然比较麻烦。如果我们需要传10个参数,那得一个一个在后边传递。幸运的是,apply()方法可以让我们以数组的形式传递参数,并且会自动将其展开。
将上边代码改为使用.apply来调用:
javascript
const languages = ['JavaScript', 'Ruby', 'Python']
greet.apply(user, languages);
相信看到这里的你已经get到call和apply两者的区别了,没错,其实就是第二个参数的传递形式不同,我们先不进行总结,后边还有一个bind没看,看完你就能归纳出它们的异同点了。
bind
bind属性和call完全相同,它不会立即调用函数,而是返回一个能在以后调用的函数。看下这段代码:
javascript
function greet(lang1, lang2, lang3) {
alert(`Hello, my name is ${this.name} and I know ${lang1}, ${lang2}, and ${lang3}`)
};
const user = {
name: 'Tyler',
age: 27
};
const language = ['JavaScript', 'Ruby', 'Python'];
const newFn = greet.bind(user, languages[0], languages[1], languages[2]);
newFn(); //"Hello, my name is Tyler and I know JavaScript, Ruby, and Python"
看完上边代码,我们可以发现bind和call在参数传递以及调用形式上是完全相同的,唯一区别就是在bind等号的左边可以接收一个新函数(即bind返回的那个函数),而这个函数正是绑定了this上下文的函数。
好了,了解完上边三个关键字,我相信你自己都可以做总结了,那我这里还是走完流程吧😊~
总结
对于apply、call、bind三个关键字
相同点:它们的第一个参数都是函数绑定的上下文(即this的指向)
不同点:
call和apply:第二个参数传递形式不同,call中的参数需要逐个传,而apply可以以数组的形式传递。call和bind:第一、二个参数完全相同,不同的是bind会返回一个绑定好上下文的新函数。
结语
以上就是本篇的所有内容了,如果文章对于你有点用,请留个赞鼓励一下luckyCover嘿嘿,我们下篇文章见!