Object.create属于那种见的很少用的更少的API,平时也就在阅读源码时会发现有在使用,但是JS设计这个API的初衷真的是这样吗?让人诟病的IE浏览器都在IE9中兼容性了Object.create的使用,可能你对IE9没什么概念,又比如谷歌浏览器在2010-2-25已经兼容了Object.create,已经过去10多年了~~~
如果Object.create真的是落伍的、糟糕的API,为什么ECMA规范没有去删除和更新他喃?其实Object.create创建对象的方式才是正宗的JS原型模式,无论是ES6的class语法糖,还是构造函数,其实都是为了让其他语言的开发者能快速入门JS而设计,也就是在JS原型模式上面包裹一层,而object.create才能体现原型模式的精髓
Object.create的功能
来自MDN的功能介绍:
Object.create()方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)
- 创建新对象
- 现有的对象作为新对象的原型对象
看过JS不能没有原型模式的XDM,应该知道JS的继承使用的是原型继承,原型继承的本质就是:克隆对象得到新对象,把对象作为新对象的原型
对比Object.create实现的功能,是不是发现非常满足原型继承喃?这也就是为什么会在开头说(object.create才能体现原型模式的精髓)的原因了~~
可能你会疑问?通过字面量、构造函数创建对象就不好,只通过object.create创建对象可以吗?
显然不是这样的,更多时候都不会选择object.create创建对象,而是选择字面量和构造函数创建对象,之所以说object.create是精髓,是因为通过字面量和构造函数创建对象,底层实现都是类似于object.create
object.create的使用
object.create(o: object | null, properties: object ): object
通过功能介绍就可以推测出,会传入一个对象作为新建对象的原型,返回值是新建的对象
- proto(必填):成为新对象的原型对象;该参数值可以是null、对象
- properties(可选):该参数对象的属性(添加的属性是其自身可枚举的属性,而不是对象原型链上的属性)会添加到新对象上;(遵循Object.defineProperties第二个参数的配置)
先看看最常见的用法
let obj = Object.create({
sex: "男"
})
是不是和你想的一样喃,传入的对象成为新对象的原型对象
let properties = {
name: {
value: "李白",
enumerable: true,
writable: true,
configurable: true
}
}
let obj = Object.create({
sex: "男"
}, properties)
properties就是属性名称和对应的属性描述符的集合对象
这里要介绍一个比较特殊的的写法
let obj = Object.create(null)
可以先猜一猜obj对象长什么样~~~
这好像不是空对象,但是又是空对象,对照一下平时看到的空对象let obj = {}
对比发现,Object.create(null)创建的空对象不仅没有属性和方法,还没有Object.prototype原型对象
let obj = Object.create(null)
obj.toString() //Uncaught TypeError: obj.toString is not a function
obj对象连访问toString 方法的资格都没有,那创建他的意义在哪里喃?
意义就是他不会使用Object.prototype对象上的所有方法和属性,如果Object.prototype被修改,会影响到所有原型链上有Object.prototype的对象,也就是几乎所有对象,但是唯独不会影响到obj对象,因为obj对象原型链是空的,所以不会受到影响,因为没有所以纯净~~~
如果你想你创建的空对象,不被原型链影响,那Object.create(null)就是你的不二选择~~~
Object.create、字面量、构造创建函数的区别
Object.create原理
首先实现一个Object.create的简单版本,这是网上广为流传的版本
const mYcreate = function (proto, prototyObject = undefined) {
function F() {}
F.prototype = proto // 设置原型
const obj = new F() // 创建新对象
if (propertyObject !== undefined) {
Object.defineProperties(obj, propertyObject) // 设置新对象属性
}
return obj
}
前面介绍过,Object.create是原型模式的精髓,是因为他采用了克隆的思想
function F() {}
F.prototype = proto // 设置原型
const obj = new F() // 创建新对象
很简单的几句代码,其实个人感觉通过构造函数实现克隆很不严谨
// 浏览器除了`Object.create`能创建纯净的空对象,没有其他方式创建了,这里意想一想就可以,嘿嘿
let obj = { } // 纯净洁的空对象(意想)
obj.__proto__ = proto // 设置原型
这才符合原型模式创建一个新对象,是通过克隆已有对象产生新对象,而不是什么实例构造函数
字面量创建对象原理
let obj = { }
let obj = { } // 纯净的空对象(意想)
obj.__proto__ = Object.prototype // 设置原型
是不是感觉和使用Object.create(Object.prototype)效果一样的喃?
构造函数创建对象原理
又是网上的现成代码,偷懒了~~~
function myNew(Constructor) {
// 1.从 Object.prototype 上克隆一个空的对象
var person = new Object();
// 2.取出构造函数
var constructor = [].shift.call(arguments);
// 3.继承构造函数的原型
person._proto_ = constructor.prototype;
// 4.为新建的对象调用构造函数,生成内部属性
let ret = constructor.apply(person, arguments);
// 5.返回对象
return typeof ret === 'object' ? ret : person;
}
直接取其精髓
function myNew(Constructor) {
var person = { }; // 纯净的空对象(意想)
var constructor = [].shift.call(arguments);
person._proto_ = constructor.prototype; // 设置原型
let ret = constructor.apply(person, arguments);
return typeof ret === 'object' ? ret : person; // 返回对象
}
是不是创建对象的过程Object.create是一样的
这里我又要强势宣布**object.create 是原型模式的精髓**
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天,点击查看活动详情