我不允许你还不了解this、call、apply、bind

前言

大家好,我是热爱前端的菜鸟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所在的方法在哪里被调用。

接下来,我们介绍下callapplybind这三个关键字

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到callapply两者的区别了,没错,其实就是第二个参数的传递形式不同,我们先不进行总结,后边还有一个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"

看完上边代码,我们可以发现bindcall参数传递以及调用形式上是完全相同的,唯一区别就是在bind等号的左边可以接收一个新函数(即bind返回的那个函数),而这个函数正是绑定了this上下文的函数

好了,了解完上边三个关键字,我相信你自己都可以做总结了,那我这里还是走完流程吧😊~

总结

对于applycallbind三个关键字

相同点:它们的第一个参数都是函数绑定的上下文(即this的指向)

不同点:

  • callapply:第二个参数传递形式不同,call中的参数需要逐个传,而apply可以以数组的形式传递
  • callbind:第一、二个参数完全相同,不同的是bind会返回一个绑定好上下文的新函数

结语

以上就是本篇的所有内容了,如果文章对于你有点用,请留个赞鼓励一下luckyCover嘿嘿,我们下篇文章见!

相关推荐
RaidenLiu1 分钟前
从 Provider 迈向 Riverpod 3:核心架构与迁移指南
前端·flutter
前端进阶者2 分钟前
electron-vite_18Less和Sass共用样式指定
前端
数字人直播4 分钟前
稳了!青否数字人分享3大精细化AI直播搭建方案!
前端·后端
江城开朗的豌豆7 分钟前
我在项目中这样处理useEffect依赖引用类型,同事直呼内行
前端·javascript·react.js
听风的码10 分钟前
Vue2封装Axios
开发语言·前端·javascript·vue.js
转转技术团队10 分钟前
前端安全防御策略
前端
掘金一周17 分钟前
被老板逼出来的“表格生成器”:一个前端的自救之路| 掘金一周 8.21
前端·人工智能·后端
白嫖叫上我20 分钟前
js如何循环HTMLCollection
javascript
cc_z22 分钟前
vue代码优化
前端·vue.js
卷卷卷土重来23 分钟前
C++单例模式
javascript·c++·单例模式