Skip to main content

原型相关

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 = window) {
context.fn = this; // context.fn 在这里即 Fn
let argus = [...arguments].slice(1);
let result = context.fn(...argus);
delete context.fn;
return results;
};

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 本质上是基于寄生式组合继承来实现的

  1. new 一个实例时,调用父类构造函数,继承实例属性
  2. 通过原型链继承父类实例方法
  3. 设置子类的 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);