[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()
参数为对象和函数的区别
自定义一个构造函数并且实例化,分别用1Object.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)
会返回一个纯净的对象,不会继承内置Object
的toString
、valueof
等方法。
参考
JavaScript中new操作符和Object.create()的原理
new运算符、bind、Object.create实现原理探讨
详解Object.create(null)和new区别
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。