前端经常要求的手写代码示例

call

  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();
}

你可能感兴趣的:(闲谈,javascript)