以下是一些讨论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?
或者是否应该通常回到基于类的继承,因为这是其他人正在使用和理解的内容?
答案 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,
// ...
};