关于Object.create的那丶事

关于Object.create的那丶事

语法

Object.create(proto, [propertiesObject])

参数

proto

新创建对象的原型对象

propertiesObject

可选。设置要添加到新创建对象上的属性。propertiesObject的属性名是新增属性的名字,属性值是新增属性的描述符,对应Object.defineProperties()的第二个参数

例子

var root = {rootProp: 'foo'}
var obj = Object.create(root, {
    objProp: {
        configurable: true, 
        enumerable: true, 
        wriable: true, 
        value: 'bar'}
    }
)
关于Object.create的那丶事_第1张图片
image

Object.create的主要用途是实现继承

function Point (components) {
    console.log('Point constructor called')
    this.components = components
}

Point.prototype.getDimension = function () {
    return this.components.length
}

Point.prototype.getLength = function () {
    let sum = 0, components = this.components
    for (let i = 0; i < components.length; i++) {
        sum += components[i] ** 2
    }
    return Math.sqrt(sum)
}

function Point2D (x, y) {
    Point.call(this, [x, y])
}

Point2D.prototype = new Point()
Point2D.prototype.getXY = function () {
    let {components} = this
    return {
        x: components[0],
        y: components[1]
    }
}

var p = new Point2D(3, 4)
console.log(p, p.getLength(), p instanceof Point)
// Point constructor called
// Point constructor called
// Point2D {components: Array(2)}components: (2) [3, 4]__proto__: Point 5 true

"Point constructor called"被打印了2次说明构造函数Point被调用了2次,原因是第22行代码使用了new实现继承,而new操作符会调用构造函数,导致额外的构造函数调用

解决方法是使用Object.create来实现继承

function Point (components) {
    console.log('Point constructor called')
    this.components = components
}

Point.prototype.getDimension = function () {
    return this.components.length
}

Point.prototype.getLength = function () {
    let sum = 0, components = this.components
    for (let i = 0; i < components.length; i++) {
        sum += components[i] ** 2
    }
    return Math.sqrt(sum)
}

function Point2D (x, y) {
    Point.call(this, [x, y])
}

// Point2D.prototype = new Point()
Point2D.prototype = Object.create(Point.prototype)
Point2D.prototype.getXY = function () {
    let {components} = this
    return {
        x: components[0],
        y: components[1]
    }
}

var p = new Point2D(3, 4)
console.log(p, p.getLength(), p instanceof Point)
// Point constructor called
// Point2D {components: Array(2)} 5 true

polyfill

自己动手实现一个Object.create:

function clone (o) {
    function F(){}
    F.prototype = o
    return new F()
}

Object.setPrototypeOf

​ Object.setPrototypeOf可以替代Object.create

​ 但是由于现代 JavaScript 引擎优化属性访问所带来的特性的关系,更改对象的 [[Prototype]]在各个浏览器和 JavaScript 引擎上都是一个很慢的操作。这不仅仅限于 obj.proto = ... 语句上的时间花费,而且可能会延伸到可以访问[[Prototype]]被更改的对象的代码。如果你关心性能,你应该避免设置一个对象的 [[Prototype]]。使用 Object.create()来创建带有你想要的[[Prototype]]的新对象。

// Point2D.prototype = Object.create(Point.prototype)
Object.setPrototypeOf(Point2D.prototype, Point.prototype)

如何创建没有原型的对象

通过设置构造函数的prototype实现原型继承的时候,除了根对象Object.prototype,任何对象都有一个内部属性[[Prototype]]

那么我们如何创建没有原型的对象呢?通过Object.create(null)就可以实现。

let obj = Object.create(null)    // obj没有原型对象

你可能感兴趣的:(关于Object.create的那丶事)