较新的 JavaScript (ES6) 和 TypeScript 中原型/基于原型的继承的最佳实践?
Best practices for prototypal / prototype-based inheritance in newer JavaScript (ES6) & TypeScript?
这里有几个讨论 Javascript 原型继承和委托的旧问题,例如:
- Benefits of prototypal inheritance over classical?
- classical inheritance vs prototypal inheritance in javascript
我想知道 当前 (2018) 的建议是在 Javascript.
中使用原型/原型继承
据我了解,较新版本的 JavaScript (ES6) 和 TypeScript 都更倾向于传统的基于 class 的继承。 (我自己还没有在实践中使用 ES6 或 TS。)这个观察是真的吗?
其实这个基于class的代码真的很简单易懂:
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();
关于使用prototypes,还有更多的选择,其实我还没有找到一个同样简单和"nice".
编辑:我想要实现的是,我创建 b 作为 B 的实例,原型 A 的方式是当我动态更改 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++"
如果第二个参数也可以是具有键值对的简单对象,而不是 属性 描述符(参见 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
此外,不太好,因为在这里您不能以 b.a 也被更改的方式更改 A.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++"
没有给出预期的结果。而且,好吧,你不想写这个,对吧?
当然可以按照 but I think this is still not equally nice and simple to the class syntax. Actually, I'm looking for something like this (similar to Kotlin's object declaration):
的描述,将创建放在构造函数中
object A { a: "a" }
object B extends A { b: "b" }
let a = new A(), b = new B();
那么,你会推荐什么?有什么接近的吗?
特别是,如果您想使用一些封装并让私有对象成员对克隆对象不可见?
TypeScript 在这里提供了一个很好的解决方案吗?
选择 Kotlin?
或者一般应该回到基于 class 的继承,因为其他人都在使用和理解这种继承方式?
也许我会玩这样一个简单的辅助函数:
/**
* 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++"
.....欢迎提出意见和建议。
A simple approach is Object.create
那就用吧。这似乎足以满足您想要做的事情——两个对象,一个相互继承。您不需要任何构造函数来进行初始化,因此也没有 class
语法。
顺便说一句,为了简化,当您不需要自定义 属性 描述符时,我不会使用 Object.create
的第二个参数。就这样
var B = Object.create(A);
B.b = "b";
或者,在一个表达式中,
var B = Object.assign(Object.create(A), {
b: "b",
});
或者,下划线和 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++"
我刚刚找到了我要找的东西:在 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,
// ...
};
这里有几个讨论 Javascript 原型继承和委托的旧问题,例如:
- Benefits of prototypal inheritance over classical?
- classical inheritance vs prototypal inheritance in javascript
我想知道 当前 (2018) 的建议是在 Javascript.
中使用原型/原型继承据我了解,较新版本的 JavaScript (ES6) 和 TypeScript 都更倾向于传统的基于 class 的继承。 (我自己还没有在实践中使用 ES6 或 TS。)这个观察是真的吗?
其实这个基于class的代码真的很简单易懂:
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();
关于使用prototypes,还有更多的选择,其实我还没有找到一个同样简单和"nice".
编辑:我想要实现的是,我创建 b 作为 B 的实例,原型 A 的方式是当我动态更改 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++"
如果第二个参数也可以是具有键值对的简单对象,而不是 属性 描述符(参见 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
此外,不太好,因为在这里您不能以 b.a 也被更改的方式更改 A.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++"
没有给出预期的结果。而且,好吧,你不想写这个,对吧?
当然可以按照 but I think this is still not equally nice and simple to the class syntax. Actually, I'm looking for something like this (similar to Kotlin's object declaration):
的描述,将创建放在构造函数中object A { a: "a" }
object B extends A { b: "b" }
let a = new A(), b = new B();
那么,你会推荐什么?有什么接近的吗?
特别是,如果您想使用一些封装并让私有对象成员对克隆对象不可见?
TypeScript 在这里提供了一个很好的解决方案吗?
选择 Kotlin?
或者一般应该回到基于 class 的继承,因为其他人都在使用和理解这种继承方式?
也许我会玩这样一个简单的辅助函数:
/**
* 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++"
.....欢迎提出意见和建议。
A simple approach is
Object.create
那就用吧。这似乎足以满足您想要做的事情——两个对象,一个相互继承。您不需要任何构造函数来进行初始化,因此也没有 class
语法。
顺便说一句,为了简化,当您不需要自定义 属性 描述符时,我不会使用 Object.create
的第二个参数。就这样
var B = Object.create(A);
B.b = "b";
或者,在一个表达式中,
var B = Object.assign(Object.create(A), {
b: "b",
});
或者,下划线和 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++"
我刚刚找到了我要找的东西:在 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,
// ...
};