美文网首页
再看js的call和apply的作用与区别

再看js的call和apply的作用与区别

作者: yunshengz | 来源:发表于2020-06-30 10:36 被阅读0次

call和apply的共同作用都是改变函数的this的指向问题,即改变当前函数运行时的作用域(上下文)。JavaScript的函数存在'定义上下文'和'运行上下文'及上下文是可以改变的。

call和apply其实是一个东西,区别只是参数的不同,call是apply的语法糖。

eg:

const name = 'zhao';
const age = 18;

const objA = {
    name: 'qian',
    age: 20,
    fnA() {
       return `name is ${this.name}, age is ${this.age}.`
    },
    fnB(arg1, arg2) {
        return `name is ${this.name}, arg1 is ${arg1}, arg2 is ${arg2}.`
    }
}

const objB = {
    name: 'sun'
}

当不是用call和apply,直接运行函数

// 读取的是当前方法所在对象objA的属性name和age
objA.fnA() // name is qian, age is 20.

当使用call和apply不传参数时,this指向window

// 当前的运行作用域在window,读取的name和age就是在window中直接声明的了,而不再是在objA中声明的name和age。
objA.fnA.call() // name is zhao, age is 18.
objA.fnA.apply() // name is zhao, age is 18

传一个参数时,传入的参数即是当前函数的作用域

// 当前的运行作用域在objB,读取的name是objB中声明的,而objB中没有声明age,所以age的值时undefined。
objA.fnA.call(objB) // name is sun,age is undefined.
objA.fnA.apply(objB) // name is sun,age is undefined.

当传入多个参数时,call和apply的区别就显现出来了

// 当前的运行作用域在objB,读取的name是objB中声明的,而objB中没有声明age,所以age的值时undefined。
objA.fnB.call(objB, 'didi', 'douban') // name is sun, arg1 is didi, arg2 is douban.
objA.fnB.apply(objB, ['didi', 'douban']) // name is sun,arg1 is didi, arg2 is douban.

由上面的直接代码对比可以看出来,call和apply在运行结果上并没有什么差别,差别主要体现在传入参数的不同;call接受的是连续传参,apply接受的是数组传参

call的简单实现

// 模拟call方法
var obj = {
    name: 'lee'
}

function showName() {
    console.log(this.name);
}

Function.prototype._call = function(context) {
    /* 如果call方法中没有传入参数(执行环境对象),默认是window(执行环境) */
    var context = context || window;
    /* 用传递过来的对象,添加一个方法,方法名可以随意定(最后会删除) */
    /* this指向的是_call方法执行时的环境,如fun._call()时,_call函数中的这个this指向的就是fun */
    context.fn = this;
    context.fn(); // 执行fn
    delete context.fn // 删除fn
}

showName._call(obj);

关于bind
bind的传参方式和call一样,不同之处是apply和call方法调用之后会立即执行,而bind方法调用之后会返回一个新函数,并不会立即执行,需要手动执行。

const objA = {
    name: 'qian',
    age: 20,
    fnA() {
       return `name is ${this.name}, age is ${this.age}.`
    }
}

const objB = {
    name: 'sun'
}

objA.fnA.bind(objB)(); // name is sun, age is undefined.

个人学习参考链接

call 和apply的作用与区别

深入理解call()与apply()方法

如何理解和熟练运用 JS 中的 call 及 apply?

相关文章

网友评论

      本文标题:再看js的call和apply的作用与区别

      本文链接:https://www.haomeiwen.com/subject/uxbtqktx.html