再看js的call和apply的作用与区别
2020-06-30 本文已影响0人
yunshengz
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.
个人学习参考链接