在 Javascript 中扩展原型 - 好方法?
Extending prototypes in Javascript - good way?
我想验证在扩展原型时我使用的方法是否正确 - 假设 "extend" 是正确的词。
这个主题得到了很多克隆。我仍在努力正确理解这个话题...
目的是:
- 编写干净和良好的代码。
- 避免使用框架,如果可能的话 Javascript。
- 获得有关不扭曲 JS 以获得 class 启用行为的干净框架的建议。
这是我的沙箱的父级原型:
function Parent(){
}
Parent.prototype = {
"init":function(){
this.name = "anon";
},
"initWithParameters":function(parameters){
this.name = parameters.name ? parameters.name : "anon";
},
"talk": function(){
console.log('Parent is: ' + this.name);
}
}
现在是 Child 原型 - 它添加了 "position" 属性 并重新定义了行为:
function Child(){
Parent.call(this);
}
Child.prototype = new Parent;
Child.prototype.constructor = Child;
Child.prototype.init = function(){
Parent.prototype.call(this);
this.setPosition(0, 0);
}
Child.prototype.initWithParameters = function(parameters){
Parent.prototype.initWithParameters.call(this, parameters);
if(!this.position){
this.position = {x:0, y:0};
}
this.setPosition(parameters.pos.x, parameters.pos.y);
}
Child.prototype.setPosition = function(x, y){
this.position.x = x;
this.position.y = y;
}
Child.prototype.talk = function(){
console.log('Child is: ' + this.name + ' and location is: ' + this.position.x + ', ' + this.position.y);
}
这是一个好习惯吗?是否没有 shorthand 来避免在覆盖 属性 时写 "Child.prototype." (可能使用文字,就像写的 Parent 原型一样)。
我知道 J. Resig 的 Class/extend 方法。但我宁愿使用 Javascript 作为原型语言,而不是让它作为 "class-like behaving class-less OO language".
感谢您的帮助:-)
您的方法是一种很好的纯 JavaScript 方法。每次小费 "Child.prototype" 的唯一方法是将其放入参考变量中。
喜欢:
var children = Child.prototype;
children.init = function(){ /*/someoverridecode*/}
但你还在做这背后的Child.prototype。你也可以定义一个函数来为你做这件事,见下划线的绑定,也许它适合你的需要。
干杯
我可能会因为这个建议而大吃一惊,因为有几篇文章可以反对我的示例中的某些做法,但这对我有用并且适用于看起来干净的代码,保持一致,缩小得很好,在严格模式,兼容IE8
我也喜欢使用原型方法(而不是随处可见的所有 'extend' 或 'apply' 样式)。
我这样写我的类。是的,它看起来很像一种你不想要的 OOP 语言,但它仍然遵循原型模型,同时与其他熟悉的语言有相似之处,这使得项目更容易导航。
这是我喜欢的风格 :) 我并不是说它是最好的,但它很容易阅读。
(function(ns) {
var Class = ns.ClassName = function() {
};
Class.prototype = new baseClass();
Class.constructor = Class;
var _public = Class.prototype;
var _private = _public._ = {};
Class.aClassProperty = "aValue";
Class.aClassMethod = function(params) {
}
_public.aMethod = function(params) {
_private.myMethod.call(this, "aParam");
Class.aClassMethod("aParam");
}
_private.myMethod = function(params) {
}
})({});
编辑:
我继续将您的示例转换为这种样式,只是为了向您展示它的外观:
var namespace = {};
(function(ns) {
var Class = ns.Parent = function() {
};
var _public = Class.prototype;
var _private = _public._ = {};
_public.init = function() {
this.name = "anon";
}
_public.initWithParameters = function(parameters) {
this.name = parameters.name ? parameters.name : "anon";
}
_public.talk = function() {
console.log('Parent is: ' + this.name);
}
})(namespace);
(function(ns) {
var Class = ns.Child = function() {
this.position = {x:0, y:0};
};
Class.prototype = new ns.Parent();
Class.constructor = Class;
var _public = Class.prototype;
var _private = _public._ = {};
_public.init = function() {
_public.init.call(this);
this.setPosition(0, 0);
}
_public.initWithParameters = function(parameters) {
_public.initWithParameters.call(this, parameters);
this.setPosition(parameters.pos.x, parameters.pos.y);
}
_public.setPosition = function(x, y) {
this.position.x = x;
this.position.y = y;
}
_public.talk = function() {
console.log('Child is: ' + this.name + ' and location is: ' + this.position.x + ', ' + this.position.y);
}
})(namespace);
一般来说,您的方法会奏效,但更好的方法是替换:
Child.prototype = new Parent;
与:
Child.prototype = Object.create(Parent.prototype);
这样您就不需要调用 new Parent
,这有点反模式。您也可以直接定义新属性,如下所示:
Child.prototype = Object.create(Parent.prototype, {
setPosition: {
value: function() {
//... etc
},
writable: true,
enumerable: true,
configurable: true
}
});
希望对您有所帮助。
这些是我常用的方法:
使用辅助函数:
/**
* A clone of the Node.js util.inherits() function. This will require
* browser support for the ES5 Object.create() method.
*
* @param {Function} ctor
* The child constructor.
* @param {Function} superCtor
* The parent constructor.
*/
function inherits (ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false
}
});
};
那么你可以简单地做:
function ChildClass() {
inherits(this, ParentClass);
// If you want to call parent's constructor:
this.super_.apply(this, arguments);
}
使用 Lodash 扩展原型
_.assign(ChildClass.prototype, {
value: key
});
或者给ES6一个机会!
class ParentClass {
constructor() {
var date = new Date();
var hours = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();
this.initializeTime = hours + ':' + minutes + ':' + seconds;
}
}
class ChildClass extends ParentsClass {
constructor() {
super();
console.log(this.initializeTime);
}
}
来自 2019 年 google。
从latest MDN documentation开始,扩展原型的方法是:
function MyClass() {
SuperClass.call(this);
}
// inherit one class
MyClass.prototype = Object.create(SuperClass.prototype);
// mixin another
Object.assign(MyClass.prototype, {
//... you own prototype ...
});
// re-assign constructor
MyClass.prototype.constructor = MyClass;
我的示例展示了几件事:私有变量、parant 和 child 构造函数的相同解析参数、重写 .toString() 函数尝试:""+this
。 :)
带文档的完整示例:
输出:
构造函数参数
MM = new Parent("val of arg1", "val of arg2");
Child1 = new childInterface("1", "2");
Child2 = new child2Interface("a", "b");
console.log(MM + "args:", MM.arg1, MM.arg2);
// Parentargs: val of arg1 val of arg2
console.log(Child1 + "args:", Child1.arg1, Child1.arg2);
// childInterfaceargs: 1 2
console.log(Child2 + "args:", Child2.arg1, Child2.arg2);
// child2Interfaceargs: a b
扩展 child 中的函数 class
MM.init();
// Parent: default ouput
Child1.init();
// childInterface: new output
Child2.init();
// child2Interface: default ouput
增量变量
MM.increment();
// Parent: increment 1
Child1.increment();
// childInterface: increment 1
Child2.increment();
// child2Interface: increment 1
Child2.increment();
// child2Interface: increment 2
MM.increment();
// Parent: increment 2
console.log("p", "c1", "c2");
// p c1 c2
console.log(MM.value, " " + Child1.value, " " + Child2.value);
// 2 1 2
私有变量
MM.getHidden();
// Parent: hidden (private var) is true
MM.setHidden(false);
// Parent: hidden (private var) set to false
Child2.getHidden();
// child2Interface: hidden (private var) is true
MM.setHidden(true);
// Parent: hidden (private var) set to true
Child2.setHidden(false);
// child2Interface: hidden (private var) set to false
MM.getHidden();
// Parent: hidden (private var) is true
Child1.getHidden();
// childInterface: hidden (private var) is true
Child2.getHidden();
// child2Interface: hidden (private var) is false
保护变量
function Parent() {
//...
Object.defineProperty(this, "_id", { value: 312 });
};
console.log(MM._id); // 312
MM._id = "lol";
console.log(MM._id); // 312
/**
* Class interface for Parent
*
* @class
*/
function Parent() {
this.parseArguments(...arguments);
/**
* hidden variable
*
* @type {Boolean}
* @private
*/
var hidden = true;
/**
* Get hidden
*/
this.getHidden = () => {
console.log(this + ": hidden (private var) is", hidden);
}
/**
* Set hidden
*
* @param {Boolean} state New value of hidden
*/
this.setHidden = (state) => {
console.log(this + ": hidden (private var) set to", !!state);
hidden = state;
}
Object.defineProperty(this, "_id", { value: "312" });
}
Object.defineProperty(Parent.prototype, "nameString", { value: "Parent" });
/**
* Parse arguments
*/
Parent.prototype.parseArguments = function(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
};
/**
* Get className with `class.toString()`
*/
Parent.prototype.toString = function() {
return this.nameString;
};
/**
* Initialize middleware
*/
Parent.prototype.init = function() {
console.log(this + ": default ouput");
};
/**
* Increment value
*/
Parent.prototype.increment = function() {
this.value = (this.value) ? this.value + 1 : 1;
console.log(this + ": increment", this.value);
};
/**
* Class interface for Child
*
* @class
*/
function childInterface() {
this.parseArguments(...arguments);
}
// extend
childInterface.prototype = new Parent();
Object.defineProperty(childInterface.prototype, "nameString", { value: "childInterface" });
/**
* Initialize middleware (rewrite default)
*/
childInterface.prototype.init = function(chatClient) {
console.log(this + ": new output");
};
/**
* Class interface for Child2
*
* @class
*/
function child2Interface() {
this.parseArguments(...arguments);
}
// extend
child2Interface.prototype = new Parent();
Object.defineProperty(child2Interface.prototype, "nameString", { value: "child2Interface" });
//---------------------------------------------------------
//---------------------------------------------------------
MM = new Parent("val of arg1", "val of arg2");
Child1 = new childInterface("1", "2");
Child2 = new child2Interface("a", "b");
console.log(MM + " args:", MM.arg1, MM.arg2);
console.log(Child1 + " args:", Child1.arg1, Child1.arg2);
console.log(Child2 + " args:", Child2.arg1, Child2.arg2);
console.log(" ");
MM.init();
Child1.init();
Child2.init();
console.log(" ");
MM.increment();
Child1.increment();
Child2.increment();
Child2.increment();
MM.increment();
console.log("p", "c1", "c2");
console.log(MM.value, " " + Child1.value, " " + Child2.value);
console.log(" ");
MM.getHidden();
MM.setHidden(false);
Child2.getHidden();
MM.setHidden(true);
console.log(" ");
Child2.setHidden(false);
MM.getHidden();
Child1.getHidden();
Child2.getHidden();
console.log(MM._id);
MM._id = "lol";
console.log(MM._id);
我一般都是这样做的。我现在使用 class
运算符,但在 ES3 中仍然有一个很好的方法。
使用 Node.js 实用程序
Node.js 包括一个 utility function 用于 这件事。
const { inherits } = require('util');
function SuperClass () {
this.fromSuperClass = 1;
}
function ExtendingClass () {
this.fromExtendingClass = 1;
}
inherits(ExtendingClass, SuperClass);
const extending = new ExtendingClass();
this.fromSuperClass; // -> 1
this.fromExtendingClass; // -> 1
以上有it's fair share of problems。它没有建立原型链,因此它被认为 与 class
运算符在语义上不兼容。
使用 Object.create
API
否则,您可以使用Object.create
。
function Person () {
this.person = true;
}
function CoolPerson () {
Person.call(this);
this.cool = true;
}
CoolPerson.prototype = Object.create(Person);
CoolPerson.prototype.constructor = CoolPerson;
使用 "helper function"
请注意,在上面的例子中使用了Object.create
API,如果你不在[=20=中调用Person
("super class") ](扩展 class),在实例化 Person
.
时将不会应用实例属性(和可选的初始化)
如果你想要更多"elegant",你甚至可以为此创建一个辅助函数,这对你来说可能更容易。
function extend(BaseClassFactory, SuperClass) {
const BaseClass = BaseClassFactory(SuperClass.prototype, SuperClass);
BaseClass.prototype = Object.assign(BaseClass.prototype, Object.create(SuperClass));
BaseClass.prototype.constructor = BaseClass;
return BaseClass;
}
function SuperClass() {
this.superClass = true;
}
SuperClass.prototype.method = function() {
return 'one';
}
const ExtendingClass = extend((Super, SuperCtor) => {
function ExtendingClass () {
SuperCtor.call(this);
this.extending = true;
}
// Example of calling a super method:
ExtendingClass.prototype.method = function () {
return Super.method.call(this) + ' two'; // one two
}
return ExtendingClass;
}, SuperClass);
const extending = new ExtendingClass();
extending.method(); // => one two
使用 ES6 的 class
运算符
JavaScript 中有一个新的 class
运算符已在 JavaScript 中发布,这可能会使整个体验更具表现力。
class SuperClass {
constructor() {
this.superClass = true;
}
method() {
return 'one';
}
}
class ExtendingClass extends SuperClass {
constructor() {
super();
this.extending = true;
}
method() {
// In this context, `super.method` refers to a bound version of `SuperClass.method`, which can be called like a normal method.
return `${super.method()} two`;
}
}
const extending = new ExtendingClass();
extending.method(); // => one two
希望这对您有所帮助。
我想验证在扩展原型时我使用的方法是否正确 - 假设 "extend" 是正确的词。
这个主题得到了很多克隆。我仍在努力正确理解这个话题...
目的是: - 编写干净和良好的代码。 - 避免使用框架,如果可能的话 Javascript。 - 获得有关不扭曲 JS 以获得 class 启用行为的干净框架的建议。
这是我的沙箱的父级原型:
function Parent(){
}
Parent.prototype = {
"init":function(){
this.name = "anon";
},
"initWithParameters":function(parameters){
this.name = parameters.name ? parameters.name : "anon";
},
"talk": function(){
console.log('Parent is: ' + this.name);
}
}
现在是 Child 原型 - 它添加了 "position" 属性 并重新定义了行为:
function Child(){
Parent.call(this);
}
Child.prototype = new Parent;
Child.prototype.constructor = Child;
Child.prototype.init = function(){
Parent.prototype.call(this);
this.setPosition(0, 0);
}
Child.prototype.initWithParameters = function(parameters){
Parent.prototype.initWithParameters.call(this, parameters);
if(!this.position){
this.position = {x:0, y:0};
}
this.setPosition(parameters.pos.x, parameters.pos.y);
}
Child.prototype.setPosition = function(x, y){
this.position.x = x;
this.position.y = y;
}
Child.prototype.talk = function(){
console.log('Child is: ' + this.name + ' and location is: ' + this.position.x + ', ' + this.position.y);
}
这是一个好习惯吗?是否没有 shorthand 来避免在覆盖 属性 时写 "Child.prototype." (可能使用文字,就像写的 Parent 原型一样)。
我知道 J. Resig 的 Class/extend 方法。但我宁愿使用 Javascript 作为原型语言,而不是让它作为 "class-like behaving class-less OO language".
感谢您的帮助:-)
您的方法是一种很好的纯 JavaScript 方法。每次小费 "Child.prototype" 的唯一方法是将其放入参考变量中。
喜欢:
var children = Child.prototype;
children.init = function(){ /*/someoverridecode*/}
但你还在做这背后的Child.prototype。你也可以定义一个函数来为你做这件事,见下划线的绑定,也许它适合你的需要。
干杯
我可能会因为这个建议而大吃一惊,因为有几篇文章可以反对我的示例中的某些做法,但这对我有用并且适用于看起来干净的代码,保持一致,缩小得很好,在严格模式,兼容IE8
我也喜欢使用原型方法(而不是随处可见的所有 'extend' 或 'apply' 样式)。
我这样写我的类。是的,它看起来很像一种你不想要的 OOP 语言,但它仍然遵循原型模型,同时与其他熟悉的语言有相似之处,这使得项目更容易导航。
这是我喜欢的风格 :) 我并不是说它是最好的,但它很容易阅读。
(function(ns) {
var Class = ns.ClassName = function() {
};
Class.prototype = new baseClass();
Class.constructor = Class;
var _public = Class.prototype;
var _private = _public._ = {};
Class.aClassProperty = "aValue";
Class.aClassMethod = function(params) {
}
_public.aMethod = function(params) {
_private.myMethod.call(this, "aParam");
Class.aClassMethod("aParam");
}
_private.myMethod = function(params) {
}
})({});
编辑:
我继续将您的示例转换为这种样式,只是为了向您展示它的外观:
var namespace = {};
(function(ns) {
var Class = ns.Parent = function() {
};
var _public = Class.prototype;
var _private = _public._ = {};
_public.init = function() {
this.name = "anon";
}
_public.initWithParameters = function(parameters) {
this.name = parameters.name ? parameters.name : "anon";
}
_public.talk = function() {
console.log('Parent is: ' + this.name);
}
})(namespace);
(function(ns) {
var Class = ns.Child = function() {
this.position = {x:0, y:0};
};
Class.prototype = new ns.Parent();
Class.constructor = Class;
var _public = Class.prototype;
var _private = _public._ = {};
_public.init = function() {
_public.init.call(this);
this.setPosition(0, 0);
}
_public.initWithParameters = function(parameters) {
_public.initWithParameters.call(this, parameters);
this.setPosition(parameters.pos.x, parameters.pos.y);
}
_public.setPosition = function(x, y) {
this.position.x = x;
this.position.y = y;
}
_public.talk = function() {
console.log('Child is: ' + this.name + ' and location is: ' + this.position.x + ', ' + this.position.y);
}
})(namespace);
一般来说,您的方法会奏效,但更好的方法是替换:
Child.prototype = new Parent;
与:
Child.prototype = Object.create(Parent.prototype);
这样您就不需要调用 new Parent
,这有点反模式。您也可以直接定义新属性,如下所示:
Child.prototype = Object.create(Parent.prototype, {
setPosition: {
value: function() {
//... etc
},
writable: true,
enumerable: true,
configurable: true
}
});
希望对您有所帮助。
这些是我常用的方法:
使用辅助函数:
/**
* A clone of the Node.js util.inherits() function. This will require
* browser support for the ES5 Object.create() method.
*
* @param {Function} ctor
* The child constructor.
* @param {Function} superCtor
* The parent constructor.
*/
function inherits (ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false
}
});
};
那么你可以简单地做:
function ChildClass() {
inherits(this, ParentClass);
// If you want to call parent's constructor:
this.super_.apply(this, arguments);
}
使用 Lodash 扩展原型
_.assign(ChildClass.prototype, {
value: key
});
或者给ES6一个机会!
class ParentClass {
constructor() {
var date = new Date();
var hours = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();
this.initializeTime = hours + ':' + minutes + ':' + seconds;
}
}
class ChildClass extends ParentsClass {
constructor() {
super();
console.log(this.initializeTime);
}
}
来自 2019 年 google。
从latest MDN documentation开始,扩展原型的方法是:
function MyClass() {
SuperClass.call(this);
}
// inherit one class
MyClass.prototype = Object.create(SuperClass.prototype);
// mixin another
Object.assign(MyClass.prototype, {
//... you own prototype ...
});
// re-assign constructor
MyClass.prototype.constructor = MyClass;
我的示例展示了几件事:私有变量、parant 和 child 构造函数的相同解析参数、重写 .toString() 函数尝试:""+this
。 :)
带文档的完整示例:
输出:
构造函数参数
MM = new Parent("val of arg1", "val of arg2");
Child1 = new childInterface("1", "2");
Child2 = new child2Interface("a", "b");
console.log(MM + "args:", MM.arg1, MM.arg2);
// Parentargs: val of arg1 val of arg2
console.log(Child1 + "args:", Child1.arg1, Child1.arg2);
// childInterfaceargs: 1 2
console.log(Child2 + "args:", Child2.arg1, Child2.arg2);
// child2Interfaceargs: a b
扩展 child 中的函数 class
MM.init();
// Parent: default ouput
Child1.init();
// childInterface: new output
Child2.init();
// child2Interface: default ouput
增量变量
MM.increment();
// Parent: increment 1
Child1.increment();
// childInterface: increment 1
Child2.increment();
// child2Interface: increment 1
Child2.increment();
// child2Interface: increment 2
MM.increment();
// Parent: increment 2
console.log("p", "c1", "c2");
// p c1 c2
console.log(MM.value, " " + Child1.value, " " + Child2.value);
// 2 1 2
私有变量
MM.getHidden();
// Parent: hidden (private var) is true
MM.setHidden(false);
// Parent: hidden (private var) set to false
Child2.getHidden();
// child2Interface: hidden (private var) is true
MM.setHidden(true);
// Parent: hidden (private var) set to true
Child2.setHidden(false);
// child2Interface: hidden (private var) set to false
MM.getHidden();
// Parent: hidden (private var) is true
Child1.getHidden();
// childInterface: hidden (private var) is true
Child2.getHidden();
// child2Interface: hidden (private var) is false
保护变量
function Parent() {
//...
Object.defineProperty(this, "_id", { value: 312 });
};
console.log(MM._id); // 312
MM._id = "lol";
console.log(MM._id); // 312
/**
* Class interface for Parent
*
* @class
*/
function Parent() {
this.parseArguments(...arguments);
/**
* hidden variable
*
* @type {Boolean}
* @private
*/
var hidden = true;
/**
* Get hidden
*/
this.getHidden = () => {
console.log(this + ": hidden (private var) is", hidden);
}
/**
* Set hidden
*
* @param {Boolean} state New value of hidden
*/
this.setHidden = (state) => {
console.log(this + ": hidden (private var) set to", !!state);
hidden = state;
}
Object.defineProperty(this, "_id", { value: "312" });
}
Object.defineProperty(Parent.prototype, "nameString", { value: "Parent" });
/**
* Parse arguments
*/
Parent.prototype.parseArguments = function(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
};
/**
* Get className with `class.toString()`
*/
Parent.prototype.toString = function() {
return this.nameString;
};
/**
* Initialize middleware
*/
Parent.prototype.init = function() {
console.log(this + ": default ouput");
};
/**
* Increment value
*/
Parent.prototype.increment = function() {
this.value = (this.value) ? this.value + 1 : 1;
console.log(this + ": increment", this.value);
};
/**
* Class interface for Child
*
* @class
*/
function childInterface() {
this.parseArguments(...arguments);
}
// extend
childInterface.prototype = new Parent();
Object.defineProperty(childInterface.prototype, "nameString", { value: "childInterface" });
/**
* Initialize middleware (rewrite default)
*/
childInterface.prototype.init = function(chatClient) {
console.log(this + ": new output");
};
/**
* Class interface for Child2
*
* @class
*/
function child2Interface() {
this.parseArguments(...arguments);
}
// extend
child2Interface.prototype = new Parent();
Object.defineProperty(child2Interface.prototype, "nameString", { value: "child2Interface" });
//---------------------------------------------------------
//---------------------------------------------------------
MM = new Parent("val of arg1", "val of arg2");
Child1 = new childInterface("1", "2");
Child2 = new child2Interface("a", "b");
console.log(MM + " args:", MM.arg1, MM.arg2);
console.log(Child1 + " args:", Child1.arg1, Child1.arg2);
console.log(Child2 + " args:", Child2.arg1, Child2.arg2);
console.log(" ");
MM.init();
Child1.init();
Child2.init();
console.log(" ");
MM.increment();
Child1.increment();
Child2.increment();
Child2.increment();
MM.increment();
console.log("p", "c1", "c2");
console.log(MM.value, " " + Child1.value, " " + Child2.value);
console.log(" ");
MM.getHidden();
MM.setHidden(false);
Child2.getHidden();
MM.setHidden(true);
console.log(" ");
Child2.setHidden(false);
MM.getHidden();
Child1.getHidden();
Child2.getHidden();
console.log(MM._id);
MM._id = "lol";
console.log(MM._id);
我一般都是这样做的。我现在使用 class
运算符,但在 ES3 中仍然有一个很好的方法。
使用 Node.js 实用程序
Node.js 包括一个 utility function 用于 这件事。
const { inherits } = require('util');
function SuperClass () {
this.fromSuperClass = 1;
}
function ExtendingClass () {
this.fromExtendingClass = 1;
}
inherits(ExtendingClass, SuperClass);
const extending = new ExtendingClass();
this.fromSuperClass; // -> 1
this.fromExtendingClass; // -> 1
以上有it's fair share of problems。它没有建立原型链,因此它被认为 与 class
运算符在语义上不兼容。
使用 Object.create
API
否则,您可以使用Object.create
。
function Person () {
this.person = true;
}
function CoolPerson () {
Person.call(this);
this.cool = true;
}
CoolPerson.prototype = Object.create(Person);
CoolPerson.prototype.constructor = CoolPerson;
使用 "helper function"
请注意,在上面的例子中使用了Object.create
API,如果你不在[=20=中调用Person
("super class") ](扩展 class),在实例化 Person
.
如果你想要更多"elegant",你甚至可以为此创建一个辅助函数,这对你来说可能更容易。
function extend(BaseClassFactory, SuperClass) {
const BaseClass = BaseClassFactory(SuperClass.prototype, SuperClass);
BaseClass.prototype = Object.assign(BaseClass.prototype, Object.create(SuperClass));
BaseClass.prototype.constructor = BaseClass;
return BaseClass;
}
function SuperClass() {
this.superClass = true;
}
SuperClass.prototype.method = function() {
return 'one';
}
const ExtendingClass = extend((Super, SuperCtor) => {
function ExtendingClass () {
SuperCtor.call(this);
this.extending = true;
}
// Example of calling a super method:
ExtendingClass.prototype.method = function () {
return Super.method.call(this) + ' two'; // one two
}
return ExtendingClass;
}, SuperClass);
const extending = new ExtendingClass();
extending.method(); // => one two
使用 ES6 的 class
运算符
JavaScript 中有一个新的 class
运算符已在 JavaScript 中发布,这可能会使整个体验更具表现力。
class SuperClass {
constructor() {
this.superClass = true;
}
method() {
return 'one';
}
}
class ExtendingClass extends SuperClass {
constructor() {
super();
this.extending = true;
}
method() {
// In this context, `super.method` refers to a bound version of `SuperClass.method`, which can be called like a normal method.
return `${super.method()} two`;
}
}
const extending = new ExtendingClass();
extending.method(); // => one two
希望这对您有所帮助。