原型相关
new
function myNew(Fn) {
  let obj = {}
  if(Fn.prototype !== null) {
    // 指向构造函数的原型对象
    obj.__proto__ = Fn.prototype
  }
  let argus = Array.prototype.slice.call(arguments, 1)
  // 以新对象为上下文执行构造函数
  let newObj = Fn.apply(obj, argus)
  // 确保返回一个对象
  if((typeof newObj === 'object' || typeof newObj === 'function') && newObj !== null) {
    return newObj
  } else {
    return obj
  }
}
myNew(Demo, 1, 2, 3) = new Demo(1, 2, 3)
instanceof
function myinstanceof(left, right) {
  let leftProto = left.__proto__;
  let rightProto = right.prototype;
  while (leftProto) {
    if (leftProto === rightProto) {
      return true;
    }
    leftProto = leftProto.__proto__;
  }
  return false;
}
console.log(myinstanceof([], Array));
call/apply
let obj = { name: "jacksonzhou" };
function Fn(id) {
  console.log(id + " " + this.name);
}
// call
Function.prototype.myCall = function (context = window) {
  context.fn = this; // context.fn 在这里即 Fn
  let argus = [...arguments].slice(1);
  let result = context.fn(...argus);
  delete context.fn;
  return result;
};
Fn.myCall(obj, 1);
// apply
Function.prototype.myApply = function (context, arr) {
  context = context ? Object(context) : window;
  context.fn = this;
  let result;
  if (!arr) {
    result = context.fn();
  } else {
    result = context.fn(...arr);
  }
  delete context.fn;
  return result;
};
Fn.myApply(obj, [1]);
bind
Function.prototype.mybind = function (context) {
  let self = this; // 保存当前函数
  let argvs1 = Array.prototype.slice.call(arguments, 1); // 获取第一个函数参数数组
  return function () {
    let argvs = argvs1.concat(Array.prototype.slice.call(arguments)); // 获取第二个函数参数数组
    return self.apply(context, argvs);
  };
};
print.mybind(obj, "cat")(3);
class
其实 es6 的 class 就是一个语法糖,是基于 js 构造函数和原型去实现的
function createClass(Constructor, protoProps, staticProps) {
  if (protoProps) {
    Object.defineProperties(Constructor.prototype, protoProps);
  }
  if (staticProps) {
    Object.defineProperties(Constructor, staticProps);
  }
  return Constructor;
}
function Animal(name) {
  // 实例属性赋值
  this.name = name;
}
// 在构造函数的原型对象上挂载实例方法
createClass(
  Animal,
  {
    getName: {
      value: function getName() {
        console.log("调用实例方法,获取实例属性", this.name);
        return this.name;
      },
    },
  },
  {
    getParentName: {
      // 在构造函数上挂载静态属性和方法
      value: function getParentName() {
        console.log("调用静态方法,获取静态属性", this.parentName);
        return this.parentName;
      },
    },
    parentName: {
      value: "Animal",
    },
  }
);
let animal1 = new Animal("animal1");
// 调用实例方法
animal1.getName();
// 调用静态方法
Animal.getParentName();
继承(extends)
extends 本质上是基于寄生式组合继承来实现的
- new 一个实例时,调用父类构造函数,继承实例属性
- 通过原型链继承父类实例方法
- 设置子类的 proto = 父类,让子类可以调用父类静态属性和方法
// 已知 Animal 这个父类
function _inherits(child, parent) {
  let proto = Object.create(parent.prototype);
  proto.constructor = child;
  child.prototype = proto;
}
function Cat(name) {
  // 调用父类的构造函数,继承实例属性
  Animal.call(this, name);
}
// 继承父类实例方法
_inherits(Cat, Animal);
// 设置子类的 __proto__ = 父类,让子类可以调用父类静态属性和方法
Object.setPrototypeOf(Cat, Animal);
let cat = new Cat("jack");
cat.getName();
console.log(Cat.parentName);