重写内置的NEW和Object.create

163 阅读2分钟
function Dog(name) {
    this.name = name;
}
Dog.prototype.bark = function () {
    console.log('wangwang');
}
Dog.prototype.sayName = function () {
    console.log('my name is ' + this.name);
}

function _new() {
    //=>完成你的代码   
}
let sanmao = _new(Dog, '三毛');
sanmao.bark(); //=>"wangwang"
sanmao.sayName(); //=>"my name is 三毛"
console.log(sanmao instanceof Dog); //=>true

上面的题是让手写出来一个new实现的方法

那要实现这个功能,就要知道new都有哪些步骤

1.首先需要创建一个对象,并且让这个对象的原型链指向传进来的类的原型

创建一个实例对象(对象.__proto__===类.prototype)
    let obj = {};
    obj.__proto__ = Func.prototype;
    但是这种方法IE浏览器不支持,也可以用下面这种方法
    Object.create(xxx)创建一个空对象,并会把xxx作为当前对象的原型链指向,
    也就是创建一个Func这个类的实例,符合我们的目标
    let obj = Object.create(Func.prototype);
    这种方法IE6、7、8不支持

所以要想全面的兼容,就需要自己手写

/*
 * 重写Object.create:创建某个类的空实例
 */
Object.create = function create(prototype) {
    function f() {}
    让这个f函数的原型等于prototype(也就是Func的原型),相当于是f属于Func的实例
    与内置的Object.create效果一样
    f.prototype = prototype;
    return new f();
};
  1. 把类当做普通函数执行(THIS指向的是实例对象)
let result = Func.call(obj, ...args);

3.看一下函数执行是否存在返回值,不存在或者返回的是值类型,则默认返回实例,如果返回的是引用数据类型则返回的不是实例而且自己写的引用类型值

if (result !== null && /^(object|function)$/.test(typeof result)) {
        return result;
    }
    return obj;

结合起来写就是这样子啦!

/*
 * _new:创建摸一个类的实例
 * params:
 *    Func创建实例的这个类
 *    剩余的参数都是给Func这个函数传递的实参
 */
function _new(Func, ...args) {
    // 1.创建一个实例对象(对象.__proto__===类.prototype)
    // let obj = {};
    // obj.__proto__ = Func.prototype;这种方法IE浏览器不支持
 
    // Object.create(xxx)创建一个空对象,并且会把xxx作为当前对象的原型链指向
    let obj = Object.create(Func.prototype);这种方法IE6、7、8不支持
    //所以我们可以自己手写一个Object.create,在上面的方法中
    
    // 2.把类当做普通函数执行(THIS指向的是实例对象)
    let result = Func.call(obj, ...args);
 
    // 3.看一下函数执行是否存在返回值,不存在或者返回的是值类型,则默认返回实例,如果返回的是引用数据类型则返回的不是实例而且自己写的引用类型值
    if (result !== null && /^(object|function)$/.test(typeof result)) {
        return result;
    }
    return obj;
}

我们单来说下Object.create()这个方法

如果我们往里传个null呢

var obj = Object.create(null);

这就相当于把obj.__proto__去掉了,浏览器断开了内置的原型链查找(破坏了原始的机制),它的共有属性里是"No properties"

var obj = Object.create({}); //=>这样不会破坏内置的原型链查找机制

而对于原型链来说,重新赋值也会改变原始的机制

obj.__proto__ = Array.prototype;

这仅仅是给obj设置了一个私有的属性__proto__

console.log(obj.slice);
// 私有属性中没有slice  =>undefined