关于面试:这些手写代码会了吗少年


观感度:????????????????????

口味:蟹黄豆腐

烹饪工夫:5min

本文已收录在前端食堂同名仓库Github github.com/Geekhyt,欢迎光临食堂,如果感觉酒菜还算可口,赏个 Star 对食堂老板来说是莫大的激励。

从略带银丝的头发和干净利落的步调我察觉到,背后坐着的这个面试官有点深不可测。我像平常一样,筹备花 3 分钟的工夫给面试官来一套昨天晚上精心筹备的自我介绍。我自信且得意的诉说着对过往我的项目所付出的心血,所做的优化获得了怎么的成绩,为公司进步了多少的支出。。。

显然,面试官对我说的数字很感兴趣,嘴角微微上扬,通过了一番细节的探讨和技术的对线后。面试官拿出了一张纸。

手写代码。

重视根底的面试官是靠谱的,为了驯服他,我一边解说着实现原理一边写出了代码。

手写 call

call 和 apply 的区别:call 办法接管的是一个参数列表,apply 办法接管的是一个蕴含多个参数的数组。

  • 1.context 存在就应用 context,否则是 window
  • 2.应用 Object(context)context 转换成对象,并通过 context.fnthis 指向 context
  • 3.循环参数,留神从 1 开始,第 0 个是上下文,前面才是咱们须要的参数
  • 4.将参数字符串 pushargs
  • 5.字符串和数组拼接时,数组会调用 toString 办法,这样能够实现将参数一个个传入,并通过 eval 执行
  • 6.拿到后果返回前,删除掉 fn
Function.prototype.call = function(context) {
    context = context ? Object(context) : window;
    context.fn = this;
    let args = [];
    for (let i = 1; i < arguments.length; i++) {
        args.push('arguments['+ i +']');
    }
    let res = eval('context.fn('+ args +')');
    delete context.fn;
    return res;
}

手写 apply

  • 1.apply 无需循环参数列表,传入的 args 就是数组
  • 2.然而 args 是可选参数,如果不传入的话,间接执行
Function.prototype.apply = function(context, args) {
    context = context ? Object(context) : window;
    context.fn = this;
    if (!args) {
        return context.fn();
    }
    let res = eval('context.fn('+ args +')');
    delete context.fn;
    return res;
}

手写 bind

  • 1.bind 的参数能够在绑定和调用的时候分两次传入
  • 2.bindArgs 是绑定时除了第一个参数以外传入的参数,args 是调用时候传入的参数,将二者拼接后一起传入
  • 3.如果应用 new 运算符结构绑定函数,则会扭转 this 指向,this 指向以后的实例
  • 4.通过 Fn 链接原型,这样 fBound 就能够通过原型链拜访父类 Fn 的属性
Function.prototype.bind = function(context) {
    let that = this;
    let bindArgs = Array.prototype.slice.call(arguments, 1);
    function Fn () {};
    function fBound(params) {
        let args = Array.prototype.slice.call(arguments) ;
        return that.apply(this instanceof fBound ? this : context, bindArgs.concat(args));
    }
    Fn.prototype = this.prototype;
    fBound.prototype = new Fn();
    return fBound;
}

手写 new

  • 1.Constructor 就是 new 时传入的第一个参数,残余的 arguments 是其余的参数
  • 2.应用obj.__proto__ = Constructor.prototype 继承原型上的办法
  • 3.将残余的 arguments 传给 Contructor ,绑定 this 指向为 obj,并执行
  • 4.如果构造函数返回的是援用类型,间接返回该援用类型,否则返回 obj
const myNew = function() {
    let Constructor = Array.prototype.shift.call(arguments);
    let obj = {};
    obj.__proto__ = Constructor.prototype;
    let res = Constructor.apply(obj, arguments);
    return res instanceof Object ? res : obj;
}

手写 instanceOf

  • 1.在 left 的原型链中层层查找,是否有原型等于 prototype
  • 2.确定边界条件,如果 left === null,即找到头没找到返回 falseright === left,即找到返回 true
  • 3.left = left.__proto__,不停的向上查找
const myInstanceof = function(left, right) {
    right = right.prototype;
    left = left.__proto__;
    while (true) {
        if (left === null) {
            return false;
        }
        if (right === left) {
            return true;
        }
        left = left.__proto__;
    }
}

手写 Object.create

  • 新建一个空的构造函数 F ,而后让 F.prototype 指向 obj,最初返回 F 的实例
const myCreate = function (obj) {
  function F() {};
  F.prototype = obj;
  return new F();
}

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理