热点面试题:JS 中 call, apply, bind 概念、用法、区别及实现?
2023/2/23 0:27:18
本文主要是介绍热点面试题:JS 中 call, apply, bind 概念、用法、区别及实现?,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
极度投入,深度沉浸,边界清晰
前端小菜鸡一枚,分享的文章纯属个人见解,若有不正确或可待讨论点可随意评论,与各位同学一起学习~
热点面试题:JS 中 call, apply, bind 概念、用法、区别及实现?
概念:
function.call(thisArg, arg1, arg2, ...)
function.apply(thisArg, [arg1, arg2, ...])
function.bind(thisArg, arg1, arg2, ...)
- 三者都是改变
this
指向,通过一个参数或多个参数来调用一个函数的。
用法:
let obj = { name: "哈哈", sayName: function () { console.log("sayName", this.name); return this.name; }, eat: function (food1, food2) { console.log("eat", food1, food2); }, }; let obj2 = { name: "是的", }; obj.sayName.call(obj2); // sayName 是的 obj.eat.call(obj2, "鱼", "肉"); // eat 鱼 肉 obj.eat.apply(obj2, ["鱼", "肉"]); // e at 鱼 肉 obj.eat.bind(obj2, "鱼", "肉"); // 不会调用,需要一个结果来接收 let res = obj.eat.bind(obj2, "鱼", "肉"); res(); // eat 鱼 肉
区别:
- call 与 bind 的区别?
call
会直接调用,而bind
会创建一个新的函数作为一个返回值进行调用, 而其余参数将作为新函数的参数,供调用时使用
- call 与 apply 的区别?
- 主要区别在第二个参数中,
call
接受的是一个参数列表,也就是一个个参数,而apply
接受的是一个包含多个参数的数组
- 主要区别在第二个参数中,
实现:
function.call(thisArg, arg1, arg2, ...)
Function.prototype.myCall = function (context, ...args) { // 条件判断,判断当前调用的对象是否为函数, if (Object.prototype.toString.call(this).slice(8, -1) != "Function") throw new Error("type error"); // 判断传入上下文对象是否存在,如果不存在,则设置为 window if (!context || context === null) context = window; // 创建唯一的 key 值,作为构建的 context 内部方法名 let fn = Symbol(); // 将 this 指向调用的 call 函数 context[fn] = this; // 执行函数并返回结果 === 把自身作为传入的 context 的方法进行调用 return context[fn](...args); }; let obj = { name: "哈哈", sayName: function () { console.log("sayName", this.name); return this.name; }, eat: function (food1, food2) { console.log("eat", food1, food2); }, }; let obj2 = { name: "是的", }; obj.sayName.myCall(obj2);
function.apply(thisArg, [arg1, arg2, ...])
Function.prototype.MyApply = function (context, args) { // 条件判断,判断当前调用的对象是否为函数, if (Object.prototype.toString.call(this).slice(8, -1) != "Function") throw new Error("type error"); // 判断传入上下文对象是否存在,如果不存在,则设置为 window if (!context || context === null) context = window; // 创建唯一的 key 值,作为构建的 context 内部方法名 let fn = Symbol(); // 将 this 指向调用的 call 函数 context[fn] = this; // 执行函数并返回结果 === 把自身作为传入的 context 的方法进行调用 return context[fn](...args); }; let obj = { name: "哈哈", sayName: function () { console.log("sayName", this.name); return this.name; }, eat: function (food1, food2) { console.log("eat", food1, food2); }, }; let obj2 = { name: "是的", }; obj.sayName.MyApply(obj2, []);
function.bind(thisArg, arg1, arg2, ...)
Function.prototype.myBind = function (context, ...args) { if (!context || context === null) { context = window; } // 创造唯一的key值 作为我们构造的context内部方法名 let fn = Symbol(); context[fn] = this; let _this = this; // bind情况要复杂一点 const result = function (...innerArgs) { // 第一种情况: 若是将 bind 绑定之后的函数当作构造函数,通过 new 操作符使用,则不绑定传入的 this,而是将 this 指向实例化出来的对象 // 此时由于new操作符作用 this指向result实例对象 而result又继承自传入的_this 根据原型链知识可得出以下结论 // this.__proto__ === result.prototype //this instanceof result =>true // this.__proto__.__proto__ === result.prototype.__proto__ === _this.prototype; //this instanceof _this =>true if (this instanceof _this === true) { // 此时this指向指向result的实例 这时候不需要改变this指向 this[fn] = _this; this[fn](...[...args, ...innerArgs]); //这里使用es6的方法让bind支持参数合并 } else { // 如果只是作为普通函数调用 那就很简单了 直接改变this指向为传入的context context[fn](...[...args, ...innerArgs]); } }; // 如果绑定的是构造函数 那么需要继承构造函数原型属性和方法 // 实现继承的方式: 使用Object.create result.prototype = Object.create(this.prototype); return result; }; //用法如下 function Person(name, age) { console.log(name); //'我是参数传进来的name' console.log(age); //'我是参数传进来的age' console.log(this); //构造函数this指向实例对象 } // 构造函数原型的方法 Person.prototype.say = function () { console.log(123); }; let obj = { objName: "我是obj传进来的name", objAge: "我是obj传进来的age", }; // 普通函数 function normalFun(name, age) { console.log(name); //'我是参数传进来的name' console.log(age); //'我是参数传进来的age' console.log(this); //普通函数this指向绑定bind的第一个参数 也就是例子中的obj console.log(this.objName); //'我是obj传进来的name' console.log(this.objAge); //'我是obj传进来的age' } // 先测试作为构造函数调用 let bindFun = Person.myBind(obj, "我是参数传进来的name"); let a = new bindFun("我是参数传进来的age"); a.say(); //123 // 再测试作为普通函数调用 // let bindFun = normalFun.myBind(obj, '我是参数传进来的name') // bindFun('我是参数传进来的age')
文章特殊字符描述:
- 问题标注
Q:(question)
- 答案标注
R:(result)
- 注意事项标准:
A:(attention matters)
- 详情描述标注:
D:(detail info)
- 总结标注:
S:(summary)
- 分析标注:
Ana:(analysis)
- 提示标注:
T:(tips)
这篇关于热点面试题:JS 中 call, apply, bind 概念、用法、区别及实现?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-26React入门教程:从零开始搭建你的第一个React应用
- 2024-12-25Vue2入门教程:轻松掌握前端开发基础
- 2024-12-25Vue3入门指南:快速搭建你的第一个Vue3项目
- 2024-12-25JS基础知识入门教程
- 2024-12-25React基础知识详解:从入门到初级应用
- 2024-12-25Vue3基础知识详解与实战指南
- 2024-12-25Vue3学习:从入门到初步掌握
- 2024-12-25Vue3入门:新手必读的简单教程
- 2024-12-23【JS逆向百例】爱疯官网登录逆向分析
- 2024-12-21Vue3教程:新手入门到实践应用