Objectcreate分析及实现

36次阅读

共计 2349 个字符,预计需要花费 6 分钟才能阅读完成。

[toc]

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

分析

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

// 字面量创建对象
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() 方法创建的对象可以指定其隐式原型为一个函数或者对象。

// 首先自定义一个构造函数并初始化一个实例对象。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

如图:

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

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

实现

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

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__ === paramProto

也可以理解为下面的形式

function _create(paramProto) {
    return {__proto__: paramProto}
}

唠叨一下

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

自定义一个构造函数并且实例化,分别用 1 Object.create()创建 o1、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等方法。

参考

JavaScript 中 new 操作符和 Object.create()的原理
new 运算符、bind、Object.create 实现原理探讨
详解 Object.create(null)和 new 区别


正文完
 0