`Object.create()`分析及实现

[toc]javascript

Object.create()方法的做用:建立一个新对象,使用现有的对象来提供新建立的对象的__proto__(会返回一个新对象,带着指定的原型对象和属性)。html

分析

默认状况下,js中对象的隐式原型__proto__指向其构造函数的显示原型prototype(这里的指向能够理解为属性与值的关系)java

// 字面量建立对象
let obj1 = {}
obj1.__proto__ === Object.prototype; // true

// 内置构造函数建立对象。等价于new Object();
let obj2 = Object();
obj2.__proto__ === Object.prototype; // true

// 自定义构造函数建立实例对象
let Ctr = function(){};
let obj3 = new Ctr();
obj3.__proto__ === Ctr.prototype; // true
复制代码

而通过Object.create()方法建立的对象能够指定其隐式原型为一个函数或者对象。node

// 首先自定义一个构造函数并初始化一个实例对象。
function Base(){
    this.name = 'cuixiaodao'
}
Base.prototype.say = function (){
    console.log(`1:`,1);
}

var base = new Base();


// 建立新对象,指定其隐式原型为Base
var o1 = Object.create(Base);
o1.__proto__ === Base; // true

// 建立新对象,指定其隐式原型为base
var o2 = Object.create(base);
o2.__proto__ === base; // true
复制代码

如图:segmentfault

能够看出,Object.create方法的主要逻辑:建立一个对象,手动设置其隐式原型__proto__属性为传入的参数,让后将这个对象返回。函数

这样看实现过程就比较简单了。不过Object.create()方法还能够接受第二个参数,用来给新建立的对象添加可枚举属性,与Object.defineProperies方法第二个参数用法同样。ui

实现

这里咱们本着弄清Object.create方法主要过程的原则,暂时不考虑第二个参数,对其主要功能作简单实现。this

function _create(paramProto){
     var isObject = (typeof paramProto === 'object') || (typeof paramProto === 'function');
     var isUndefined = typeof paramProto === 'undefined';
     if (isUndefined || !isObject){
         throw new TypeError('Object prototype may only be an Object or null: ' + paramProto)
     }
     
     function F() { }
     F.prototype = paramProto;
     return new F();
}

复制代码

上面最后三行代码,返回了F的实例对象,暂且称为f,那么也就是f.__proto__ === F.prototype,而F.prototype = paramProto,也就作到了f.__proto__ === paramProtospa

也能够理解为下面的形式prototype

function _create(paramProto) {
    return {
        __proto__: paramProto
    }
}
复制代码

唠叨一下

Object.create()参数为对象和函数的区别

自定义一个构造函数而且实例化,分别用1Object.create()建立o一、o2另个对象。

function Base() {
    this.name = 'cuixiaodao'
}
Base.age = '18';
Base.prototype.say = function () {
    console.log(`1:`, 1);
}

let base = new Base();

let o1 = Object.create(Base);
var o2 = Object.create(base);
console.log(`o1:`,o1);
console.log(`o2:`,o2);
复制代码

能够看到o1的隐式原型是Base,而o2隐式原型是baese

o1.__proto__ === Base; // true
o2.__proto__ === base; // true
复制代码

o2能够访问到base上的name属性及base经过__proto__继承来的say方法。

o2.name;  // cuixiaodao
o2.say(); // 1
复制代码

可是o1都访问不到

o1.name;  // 'Base'
o1.say;  // undefined
复制代码

函数自带name属性,也就是函数名,因此这里返回了函数的名称Base。相似的还有length表示函数参数的个数,arguments表明函数接收的全部参数。

主要是由于原型链继承是经过对象的__proto__属性实现的:访问一个对象的属性时,先在基本属性中查找,若是没有,再沿着__proto__这条链向上找,这就是原型链。虽然o1.__proto__ === Base,但因为say方法是定义在Base原型上的,经过o1.__proto__并访问不到,因此是undefined。直接在Base上面定义属性,o1是能够访问到的。

o1.age; // 18
复制代码

Object.crete(null){}

Object.crete(null)会返回一个纯净的对象,不会继承内置ObjecttoStringvalueof等方法。

参考

相关文章
相关标签/搜索