前言
极度投入,深度沉迷,边界清晰
前端小菜鸡一枚,分享的文章纯属个人见解,若有不正确或可待探讨点可随便评论,与各位同学一起学习~
欢送关注
『前端进阶圈』
公众号 ,一起摸索学习前端技术......公众号回复
加群
或扫码
, 即可退出前端交流学习群,长期交流学习......公众号回复
加好友
,即可添加为好友
热点面试题: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");// 判断传入上下文对象是否存在,如果不存在,则设置为 windowif (!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");// 判断传入上下文对象是否存在,如果不存在,则设置为 windowif (!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.createresult.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的第一个参数 也就是例子中的objconsole.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)
往期回顾:
- 热点面试题:Virtual DOM 相干问题?
- 热点面试题:什么是粘包/半包问题,该如何解决?
- 热点面试题:console.log()同异步问题?
- 热点面试题:过程系列问题?
- 热点面试题:Node.js 中的垃圾回收机制?
- 热点面试题:简述 http3.0~http1.0 别离有什么改良?
- JavaScript中的AMD和CMD标准
- Vue数据监听Object.definedProperty()办法的实现
最初:
- 欢送关注
『前端进阶圈』
公众号 ,一起摸索学习前端技术...... - 公众号回复
加群
或扫码
, 即可退出前端交流学习群,长期交流学习...... - 公众号回复
加好友
,即可添加为好友