在较新的JavaScript(ES6)和&amp ;;中进行基于原型/原型的继承的最佳实践。打字稿?

时间:2018-03-01 12:03:04

标签: javascript typescript ecmascript-6 prototype prototypal-inheritance

以下是一些讨论Javascript原型继承的问题。代表团,例如:

我想知道当前(2018)建议在Javascript中使用原型/原型继承是什么。

据我所知,较新版本的JavaScript(ES6)和TypeScript都更倾向于传统的基于类的继承。 (我自己在实践中没有使用过ES6或TS。)这个观察是真的吗?

事实上,这个基于类的代码非常简单易懂:

class A { a: "a" }
class B extends A { b: "b" }
let a = new A(), b = new B();

编辑2 :在TypeScript中,它将是:

class A { a = "a" }
class B extends A { b = "b" }
let a = new A(), b = new B();

编辑:事实上,ES6语法更复杂:

class A { constructor() { this.a = "a"; } }
class B extends A { constructor() { super(); b = "b"; } }
let a = new A(), b = new B();

对于使用原型,还有更多选项,实际上我找不到一个同样简单且“很好”的选项。

编辑 我想要实现的是我用原型A创建b作为B的实例,当我动态更改A的属性时,b也会受到影响通过改变:

一个简单的方法是:

var A = { a: "a" }
var B = Object.create(A, {b: {value: "b"}});
var a = Object.create(A), // direct instance of A
    b = Object.create(B); // indirect instance of A
console.log(b.a); // "a"
A.a = "a++"; // change the base prototype (will affect B, a, and b)
console.log(b.a); // "a++"

如果第二个arg也可以是一个具有键值对的简单对象,而不是属性描述符(参见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

,那将会更好

大多数情况下,使用构造函数,例如在https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

function A() { this.a = "a"; }
function B() { this.b = "b"; }
B.prototype = new A();
var a = new A(), b = new B();
console.log(b.a); // "a"
A.a = "a++";
console.log(b.a); // return "a" instead of "a++" as b.a is overwritten in constructor

另外,不太好,因为在这里你不能改变A.a的方式,b.a也被改变,这是IMO原型继承的关键点。也许这个?

function A() {}
A.prototype.a = "a";
function B() {}
B.prototype = Object.create(A.prototype);
B.prototype.b = "b";
var a = new A(), b = new B();
function A() { this.a = "a"; }
function B() { this.b = "b"; }
B.prototype = new A();
var a = new A(), b = new B();
console.log(b.a); // "a"
A.a = "a++";
console.log(b.a); // still "a" instead of "a++"

未给出预期结果。而且,嗯,你不想写这个,对吗?

当然,您可以将创建放在https://stackoverflow.com/a/16872315/1480587所描述的构造函数中,但我认为这对于类语法来说仍然不是那么简单和简单。实际上,我正在寻找类似这样的东西(类似于Kotlin's object declaration):

object A { a: "a" }
object B extends A { b: "b" }
let a = new A(), b = new B();

那么,你会推荐什么?有什么接近吗?

特别是,如果你想使用一些封装并让私有对象成员对克隆对象不可见?

TypeScript在这里提供了一个不错的解决方案吗?

去Kotlin?

或者是否应该通常回到基于类的继承,因为这是其他人正在使用和理解的内容?

4 个答案:

答案 0 :(得分:0)

也许我会玩这样一个简单的辅助函数:

/**
 * Create a new object with `prototype` as its prototype.
 * The (optional) properties will be copied to the newly created object
 * This is similar to Object.create(), however the properties passed is a plain
 * object, not a object with property descriptors,
 * see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
 *
 * @param prototype (object)
 * @param properties (object)
 * @return {prototype}
 */
function clonePrototype(prototype, properties) {
    var pDef = {};
    for(var key in (properties||{})) {
        if (properties.hasOwnProperty(key)) { pDef[key] = {value: properties[key]}; }
    }
    return Object.create(prototype, pDef);
}

这样,我可以做我想做的事:

var a = { a: "a" };
var b = clonePrototype(a, { b: "b" });
console.log(b.a); // "a"
a.a = "a++";
console.log(b.a); // "a++"

....欢迎提出意见和建议。

答案 1 :(得分:0)

  

一个简单的方法是Object.create

然后使用它。对于你想要做的事情似乎已经足够了 - 两个对象,一个继承自另一个。您不需要任何构造函数来进行初始化,因此也没有class语法。

顺便说一下,为了简化,当你不需要自定义属性描述符时,我不会使用Object.create的第二个参数。只是做

var B = Object.create(A);
B.b = "b";

或者,在一个表达式中,

var B = Object.assign(Object.create(A), {
  b: "b",
});

答案 2 :(得分:0)

或者,下划线和lodash提供_.create(),这有助于使用初始化原型创建一个新对象:

var a = { a: "a" };
var b = _.create(a, { b: "b" });
console.log(b.a); // "a"
a.a = "a++";
console.log(b.a); // "a++"

答案 3 :(得分:0)

我刚刚找到了我要找的东西:在ES6中"object literals are extended to support setting the prototype at construction."这是真的简单&方便!!

var obj = {
    // Sets the prototype. "__proto__" or '__proto__' would also work.
    __proto__: theProtoObj,
    // Computed property name does not set prototype or trigger early error for
    // duplicate __proto__ properties.
    ['__proto__']: somethingElse,
    // ...
};