Глубокое понимание Object.create

внешний интерфейс Babel

Прежде чем углубляться в детали, давайте рассмотрим пример наследования реализации ES6.

class Point {
    static NAME='point';

    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
  
    outPoint(){
        console.log('point:'+this.x+this.y);
    }
}

class ColorPoint extends Point {
    static COLOR_NAME='ColorPoint';

    constructor(x, y, color) {
        super(x, y);    
        this.color = color;
    }

    outColorPoint(){
        console.log('ColorPoint:'+this.x+this.y+this.color);
    }
}

Теперь конвертируйте его в es5 через babel;

'use strict';

var _createClass = function() {
    function defineProperties(target, props) {
        for (var i = 0; i < props.length; i++) {
            var descriptor = props[i];
            descriptor.enumerable = descriptor.enumerable || false;
            descriptor.configurable = true;
            if ("value" in descriptor) descriptor.writable = true;
            Object.defineProperty(target, descriptor.key, descriptor);
        }
    }
    return function(Constructor, protoProps, staticProps) {
        if (protoProps) defineProperties(Constructor.prototype, protoProps);
        if (staticProps) defineProperties(Constructor, staticProps);
        return Constructor;
    };
} ();

function _possibleConstructorReturn(self, call) {
    if (!self) {
        throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }
    return call && (typeof call === "object" || typeof call === "function") ? call: self;
}

function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

function _classCallCheck(instance, Constructor) {
    if (! (instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}

var Point = function() {
    function Point(x, y) {
        _classCallCheck(this, Point);

        this.x = x;
        this.y = y;
    }

    _createClass(Point, [{
        key: 'outPoint',
        value: function outPoint() {
            console.log('point:' + this.x + this.y);
        }
    }]);

    return Point;
} ();

Point.NAME = 'point';

var ColorPoint = function(_Point) {
    _inherits(ColorPoint, _Point);

    function ColorPoint(x, y, color) {
        _classCallCheck(this, ColorPoint);

        var _this = _possibleConstructorReturn(this, (ColorPoint.__proto__ || Object.getPrototypeOf(ColorPoint)).call(this, x, y));

        _this.color = color;
        return _this;
    }

    _createClass(ColorPoint, [{
        key: 'outColorPoint',
        value: function outColorPoint() {
            console.log('ColorPoint:' + this.x + this.y + this.color);
        }
    }]);

    return ColorPoint;
} (Point);

ColorPoint.COLOR_NAME = 'ColorPoint';

Это все еще выглядит грязно, мы упрощаем код, удаляем проверочную информацию, используем прототип вместо _createClass и упрощаем код

'use strict';
function _inherits(subClass, superClass) {
    subClass.prototype = Object.create(superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    subClass.__proto__ = superClass;
}
var Point = function(x, y) {
    this.x = x;
    this.y = y;
}
Point.prototype.outPoint = function outPoint() {
    console.log('point:' + this.x + this.y);
}

Point.NAME = 'point';

var ColorPoint = function(_Point) {
    _inherits(ColorPoint, _Point);

    function ColorPoint(x, y, color) {
        ColorPoint.__proto__.call(this,x,y);
        this.color = color;
    }
    ColorPoint.prototype.outColorPoint = function() {
        console.log('ColorPoint:' + this.x + this.y + this.color);
    }
    return ColorPoint;
} (Point);

ColorPoint.COLOR_NAME = 'ColorPoint';    

Упрощенный код можно увидетьМетод _inherits предназначен для реализации наследования объекта-прототипа родительского класса,Конструктор родительского класса применяется к ColorPoint.__proto__Точка, используйтеColorPoint.__proto__.call(this,x,y), используйте call для наследования свойств в конструкторе родительского класса

Давай поговоримObject.create

function _inherits(subClass, superClass) {
    subClass.prototype = Object.create(superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    subClass.__proto__ = superClass;
}

Используя объект-экземпляр, сгенерируйте другой объект-экземпляр!


В приведенном выше кодеObject.createметод сAОбъект является прототипом, который генерируетBобъект.BнаследоватьAВсе свойства и методы .

Фактически,Object.createможно заменить следующим кодом.

Object.create = function (obj) {
    function F() {}
    F.prototype = obj;
    return new F();
  };

Приведенный выше код показывает, чтоObject.createСуть метода заключается в создании пустого конструктораF, тогда пустьF.prototypeсвойство указывает на объект параметраobj, который, наконец, возвращаетF, чтобы экземпляр наследовалobjхарактеристики.

или

Object.create = function (obj) {
    var B={};
    Object.setPrototypeOf(B,obj);
    return B;  
};

более интуитивный

Object.create = function (obj) {
    var B={};
    B.__proto__=obj;
    return B;  
};

Если вы хотите сгенерировать свойство, которое не наследует никакие свойства (например, отсутствиеtoStringа такжеvalueOfметод), вы можете использоватьObject.createПараметры установлены наnull.

var obj = Object.create(null);

object.createНовый объект, сгенерированный методом, динамически наследует прототип. Любой метод, добавленный или измененный в прототипе, немедленно отражается в новом объекте.

var obj1 = { p: 1 };
var obj2 = Object.create(obj1);

obj1.p = 2;
obj2.p // 2

В приведенном выше коде измените прототип объектаobj1Влияет на объекты экземпляраobj2.

Второй параметр Object.create

Помимо прототипа объекта,Object.createМетод также может принимать второй параметр. Этот параметр является объектом описания свойства, и описываемое им свойство объекта будет добавлено к экземпляру объекта как свойство самого объекта.

var obj = Object.create({}, {
  p1: {
    value: 123,
    enumerable: true,
    configurable: true,
    writable: true,
  },
  p2: {
    value: 'abc',
    enumerable: true,
    configurable: true,
    writable: true,
  }
});

// 等同于
var obj = Object.create({});
obj.p1 = 123;
obj.p2 = 'abc';

После понимания Object.create вы сможете легко понять код наследования ES6 в ES5!