介绍
call函数 apply函数 bind函数的用法
作用
都是用于改变函数的this指向
用法
- call函数
可以接收很多个参数 但是第一个参数一定是this
指向的那个对象 后面的参数都可以用参数逗号进行分割
- 代码示例
let obj = {
name: 'jack',
age: 12,
}
function show(a, b) {
console.log(this.name); // jack
console.log(a); // mary
console.log(b); // bob
}
show.call(obj, 'mary', 'bob');
复制代码
- apply函数
接收两个参数 第一个参数是this
指向的那个对象 第二个参数是一个数组 也就是apply所有的参数都需要放到数组中
- 代码示例
let obj = {
name: 'jack',
age: 12,
}
function show(a, b) {
console.log(this.name); // jack
console.log(a); // mary
console.log(b); // bob
}
show.call(obj, ['mary', 'bob']);
复制代码
- bind函数
和call接收参数的用法一样 但是它会返回一个新的函数 只有调用这个函数 才会被执行
- 代码示例
let obj = {
name: 'jack',
age: 12,
}
function show(a, b) {
console.log(this.name); // jack
console.log(a); // mary
console.log(b); // bob
}
let show1 = show.bind(obj, 'mary', 'bob');
// 如果这里没有执行 show1 这个函数 则不会输出任何东西
show1();
复制代码
call函数的手写实现
代码示例
Function.prototype.mycall = function(o){
if(typeof o !== 'object' || o === null){
throw new Error('请传入对象参数');
}
if(typeof this !== 'function'){
throw new Error('要是一个函数');
}
let s1 = Symbol();
o.s1 = this;
let args = [...arguments].slice(1);
let result = o.s1(...args);
delete o.s1;
return result;
}
复制代码
分析
- 1 this的指向问题
在这里 我们将传入的对象里面新增了一个s1
的属性 因为怕属性值会有可能会和传入对象里面的其他属性值重复的现象 所以这里我们使用了Symbol
则对象就会有一个独一无二的属性 然后将this
赋给了这个属性 在这里this
的指向就是谁调用这个函数 则this
的指向就是谁 而当我们去调用myCal
l这个方法的时候 谁调用这个方法 则这个mycall
函数的this指向就是谁
let obj = {
name: 'jack',
age: 12,
}
function show(a, b) {
console.log(this.name); // jack
console.log(a); // mary
console.log(b); // bob
}
show.mycall(obj, 'mary', 'bob');
复制代码
如这个代码 是show
函数去调用了mycall
这个函数 则this指向就是这个show
函数 那么当我们去执行o.s1()
的时候 实际上就是在调用show这个函数且因为是o
这个对象去调用的 则在show
函数中 它的this
指向就是o
- 2
result
(函数的返回值问题)
然后有可能show
这个函数有返回值 所以我们使用了result
这个值来接收 并且返回这个返回值
- 3 关于对象的
s1
属性问题
最后我们删除了o
的s1
属性 是因为本身o
这个对象就没有这个属性 是我们自己给它强加上去的 所以最后用完了 就要将其进行删除
apply函数的手写实现
因为和call
函数的实现是一样的思路 只不过 在传参方面有些不同 所以这里就直接写了 不分析了
代码示例
Function.prototype.mycall = function(o){
if(typeof o !== 'object' || o === null){
throw new Error('请传入对象参数');
}
if(typeof this !== 'function'){
throw new Error('要是一个函数');
}
if(!Array.isArray(arguments[1])){
throw new Error('第二个参数请传入一个数组')
}
let s1 = Symbol();
o.s1 = this;
let result = o.s1(...arguments[1]);;
delete o.s1;
return result;
}
复制代码
在这里 不能和上面一样直接从第1项开始切割 因为在apply函数中 第二个参数必须是数组 后面再传参 就会被忽略 如果第二个参数不是数组 就会报错
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END