JS面试中你不知道的call apply bind方法及使用场景详解

面试

面试官 :说一下 call apply bind 的三者区别吧?

我:啊.....这。

三者区别

call

我们先来看看 call call 函数接收两个参数

@params1 需要指向this

@params2 需要携带的参数

就拿这段代码 来说 我调用 foo 函数 的时候 想去 执行obj 中的 eat函数 怎么办?

默认 我的 foo 里面什么页面有 怎么可能会打印 吃饭呢?this默认指向 window ,window 对象中 没有 eat 方法不应该 报错 not defind 吗?

let obj = {
 eat: function (args) {
 console.log("吃饭", args);
 }
}
function foo(...args) {
 this.eat(args)
}

你可以这样 , 此时调用的时候 foo 的函数 this 就指向了 obj 但是只是这一次调用哦 ,下次 this 是指向 window

console.log(foo.call(obj, 123, 456)); / / 吃饭 [ 123, 456 ]

调用结果 : 传入 this 和 参数 立即执行函数

apply.

@params1 需要指向this

@params2 需要携带的参数 传入的参数数据类型为 Array

let obj = {
 eat: function (args) {
 console.log("吃饭", args);
 }
}
function foo(...args) {
 this.eat(args)
}
console.log(foo.apply(obj, [1, 2, 3])); // 吃饭 [1,2,3 ]

调用结果 : 传入 this 和 参数,立即执行

bind

@params1 需要指向this

@params2 需要携带的参数

let obj = {
 eat: function (args) {
 console.log("吃饭", args);
 }
}
function foo(...args) {
 this.eat(args)
}
console.log(foo.bind(obj, 1, 2, 3)()); //吃饭 [ 1, 2, 3 ]

调用结果 : 传入 this 和 参数 返回一个 新的函数,不会立即执行

总结

call 函数 传入绑定 this的对象 ,携第二个参数以 参数列表形式传入 并会立即执行

apply 函数 传入绑定 this的对象 第二个参数以 数组的形式 传入 并会立即执行

bind 函数 传入绑定 this的对象 第二个参数以 数组或参数列表的形式传入 不会立即执行函数会返回一个新的函数 自由调用

应用场景

利用call 实现 构造函数原型继承

function Person(name, age, friends) {
 this.friends = friends
 this.name = name
 this.age = age
}
Person.prototype.eat = function () {
 console.log(`${this.name}在吃饭`);
}
Person.prototype.running = function () {
 console.log(`${this.name}去跑步了`);
}
function Student(study, name, age, friedns) {
 Person.call(this, name, age, friedns)
 this.study = study
}
function Teacher(plaseLoveStudent) {
 this.plaseLoveStudent = plaseLoveStudent
}
//继承 person 
Student.prototype = new Person()
const stu = new Student('语文', "张三", 18, ['王安石'])
const stu2 = new Student('数学', "李四", 18, ['哈利波特'])
const tec = new Teacher("王安怡")
console.log(stu === stu2);
console.log(stu);
console.log(stu.friends);
console.log(stu2.friends);

简单实现

call

实现思路 :

1:在Function 原型身上添加一个方法。

2:mycall 接受 两个参数 一个是绑定的 this,还有就是 参数列表

3:保存调用者,其实这里更严谨一点还需要判断调用者的 类型

4:判断传入的thisArgs 是不是 undefined 或者 null 如果是 则 this指向 window 否则将 绑定的 this封装成 一个对象

5:然后将 函数本身保存在 上面封装好的对象中

6:调用并传入args

7:完成实现 this指向的改变

Function.prototype.mycall = function (thisArgs, ...args) {
 /**
 * 
 * 保存this(当前调用者)
 * 
 */
 const newFunc = this
 // 在当前调用者 this身上 保存 调用者
 thisArgs = (thisArgs !== undefined && thisArgs !== null) ? Object(thisArgs) : window
 thisArgs.func = newFunc
 thisArgs.func(...args)
}

apply

apply 就不说了 实现思路是一样的 只不过传入的参数不一样做一个判断就行了

Function.prototype.myapply = function (thisArgs, argArray) {
 if (!(argArray instanceof Array)) {
 throw '参数类型限定为 Array'
 }
 else {
 const func = this
 thisArgs = (thisArgs !== undefined && thisArgs !== null) ? Object(thisArgs) : window
 thisArgs.fn = func
 thisArgs.fn(argArray)
 }
}

bind

bind 跟 apply call 有一些区别

bind 会返回一个新的函数 , 所以我们在内部需要自己定义一个 函数 给返回出去, 并且,可能出现 返回新函数调用时 继续传入参数 所以我们需要将参数合并

Function.prototype.mybind = function (thisArgs, ...argArray) {
 const oldFunc = this
 console.log(this);
 thisArgs = (thisArgs !== undefined && thisArgs !== null) ? Object(thisArgs) : window
 function proxyFn(...args) {
 thisArgs.func = oldFunc
 const funcCallResult = thisArgs.func([...argArray, ...args]) // 合并两次的 参数
 delete thisArgs.func
 return funcCallResult
 }
 return proxyFn
}
作者:前端小张同学

%s 个评论

要回复文章请先登录注册