JavaScript继承
我正在尝试用javascript实现继承。我提出了以下最低限度的代码来支持它JavaScript继承,javascript,inheritance,Javascript,Inheritance,我正在尝试用javascript实现继承。我提出了以下最低限度的代码来支持它 function Base(){ this.call = function(handler, args){ handler.call(this, args); } } Base.extend = function(child, parent){ parent.apply(child); child.base = new parent; child.base.chil
function Base(){
this.call = function(handler, args){
handler.call(this, args);
}
}
Base.extend = function(child, parent){
parent.apply(child);
child.base = new parent;
child.base.child = child;
}
专家们,请让我知道这是否足够,或者我可能错过的任何其他重要问题。根据面临的类似问题,请提出其他修改建议
以下是完整的测试脚本:
function Base(){
this.call = function(handler, args){
handler.call(this, args);
}
this.superalert = function(){
alert('tst');
}
}
Base.extend = function(child, parent){
parent.apply(child);
child.base = new parent;
child.base.child = child;
}
function Child(){
Base.extend(this, Base);
this.width = 20;
this.height = 15;
this.a = ['s',''];
this.alert = function(){
alert(this.a.length);
alert(this.height);
}
}
function Child1(){
Base.extend(this, Child);
this.depth = 'depth';
this.height = 'h';
this.alert = function(){
alert(this.height); // display current object height
alert(this.a.length); // display parents array length
this.call(this.base.alert);
// explicit call to parent alert with current objects value
this.call(this.base.superalert);
// explicit call to grandparent, parent does not have method
this.base.alert(); // call parent without overriding values
}
}
var v = new Child1();
v.alert();
alert(v.height);
alert(v.depth);
我认为Crockfords的解决方案太复杂了,就像John的一样。获取javascript继承要比它们所描述的简单得多。考虑:
//Classes
function A() {
B.call(this);
}
function B() {
C.call(this);
this.bbb = function() {
console.log("i was inherited from b!");
}
}
function C() {
D.call(this);
}
function D() {
E.call(this);
}
function E() {
//instance property
this.id = Math.random()
}
//set up the inheritance chain (order matters)
D.prototype = new E();
C.prototype = new D();
B.prototype = new C();
A.prototype = new B();
//Add custom functions to each
A.prototype.foo = function() {
console.log("a");
};
B.prototype.bar = function() {
console.log("b");
};
C.prototype.baz = function() {
console.log("c");
};
D.prototype.wee = function() {
console.log("d");
};
E.prototype.woo = function() {
console.log("e");
};
//Some tests
a = new A();
a.foo();
a.bar();
a.baz();
a.wee();
a.woo();
console.log(a.id);
a.bbb();
console.log(a instanceof A);
console.log(a instanceof B);
console.log(a instanceof C);
console.log(a instanceof D);
console.log(a instanceof E);
var b = new B();
console.log(b.id)
我已经在上写了上述解决方案的完整描述 要在中实现javascript继承,可以定义对象的原型并使用
object.create
进行继承。还可以根据需要添加/覆盖属性
例如:
/**
*变换基类
*/
函数变换(){
this.type=“2d”;
}
Transform.prototype.toString=函数(){
返回“转换”;
}
/**
*翻译课。
*/
函数转换(x,y){
//父构造函数
转换。调用(此);
//公共财产
这个.x=x;
这个。y=y;
}
//继承权
Translation.prototype=Object.create(Transform.prototype);
//凌驾
Translation.prototype.toString=函数(){
返回Transform.prototype.toString()+this.type+“Translation”+this.x+:“+this.y;
}
/**
*轮换班。
*/
函数旋转(角度){
//父构造函数
转换。调用(此);
//公共财产
这个角度=角度;
}
//继承权
Rotation.prototype=Object.create(Transform.prototype);
//凌驾
Rotation.prototype.toString=函数(){
返回Transform.prototype.toString()+this.type+“Rotation”+this.angle;
}
//测验
翻译=新翻译(10,15);
console.log(转换的转换实例);//符合事实的
console.log(翻译的翻译实例);//符合事实的
console.log(旋转的平移实例);//错误的
console.log(translation.toString())//Transform2d translation 10:15
当我玩JS对象时,我发现了一个更简单的解决方案:-)享受吧
范例
function A() {
this.info1 = function() {
alert("A");
}
}
function B(p1,p2) {
extend(B,A,this);
this.info2 = function() {
alert("B"+p1+p2);
}
}
function C(p) {
extend(C,B,this,["1","2"]);
this.info3 = function() {
alert("C"+p);
}
}
var c = new C("c");
c.info1(); // A
c.info2(); // B12
c.info3(); // Cc
这里是理解JS中继承的最简单的方法,我希望也是最简单的方法。这个例子对PHP程序员最有帮助
function Mother(){
this.canSwim = function(){
console.log('yes');
}
}
function Son(){};
Son.prototype = new Mother;
Son.prototype.canRun = function(){
console.log('yes');
}
现在,子对象有一个重写的方法和一个新的
function Grandson(){}
Grandson.prototype = new Son;
Grandson.prototype.canPlayPiano = function(){
console.log('yes');
};
Grandson.prototype.canSwim = function(){
console.log('no');
}
var g = new Grandson;
g.canRun(); // => yes
g.canPlayPiano(); // => yes
g.canSwim(); // => no
现在,孙子有两个替代方法和一个新方法
function Grandson(){}
Grandson.prototype = new Son;
Grandson.prototype.canPlayPiano = function(){
console.log('yes');
};
Grandson.prototype.canSwim = function(){
console.log('no');
}
var g = new Grandson;
g.canRun(); // => yes
g.canPlayPiano(); // => yes
g.canSwim(); // => no
虽然我同意以上所有答案,但我觉得JavaScript不需要面向对象(避免继承),而应该在大多数情况下就足够了
我喜欢从面向对象编程开始谈论OO的方式。与其破译实现继承的最佳方法,不如花更多精力学习JavaScript的功能方面,因此,我发现函数编程更有趣。为什么不使用对象而不是函数:
//This is an example of how to override a method, while preserving access to the original.
//The pattern used is actually quite simple using JavaScripts ability to define closures:
this.somefunction = this.someFunction.override(function(args){
var result = this.inherited(args);
result += this.doSomethingElse();
return result;
});
//It is accomplished through this piece of code (courtesy of Poul Krogh):
/***************************************************************
function.override overrides a defined method with a new one,
while preserving the old method.
The old method is only accessible from the new one.
Use this.inherited() to access the old method.
***************************************************************/
Function.prototype.override = function(func)
{
var remember = this;
var f = function()
{
var save = this.inherited;
this.inherited = remember;
var result = func.apply(this, Array.prototype.slice.call(arguments));
this.inherited = save;
return result;
};
return f;
}
var Base = {
superalert : function() {
alert('tst');
}
};
var Child = Object.create(Base);
Child.width = 20;
Child.height = 15;
Child.a = ['s',''];
Child.childAlert = function () {
alert(this.a.length);
alert(this.height);
}
var Child1 = Object.create(Child);
Child1.depth = 'depth';
Child1.height = 'h';
Child1.alert = function () {
alert(this.height);
alert(this.a.length);
this.childAlert();
this.superalert();
};
这样称呼它:
var child1 = Object.create(Child1);
child1.alert();
这种方法比使用函数更简洁。
我发现这个博客解释了为什么在JS中使用函数继承不是正确的方法:
编辑
变量子级也可以写成:
var Child = Object.create(Base, {
width : {value : 20},
height : {value : 15, writable: true},
a : {value : ['s', ''], writable: true},
childAlert : {value : function () {
alert(this.a.length);
alert(this.height);
}}
});
最简单的使用方法。官方样本:
/**
* A-class
*/
var ClassA = AWeb.class({
public : {
/**
* A-class constructor
*/
constructor : function() {
/* Private variable */
this.variable1 = "A";
this.calls = 0;
},
/**
* Function returns information about the object
*/
getInfo : function() {
this.incCalls();
return "name=" + this.variable1 + ", calls=" + this.calls;
}
},
private : {
/**
* Private function
*/
incCalls : function() {
this.calls++;
}
}
});
/**
* B-class
*/
var ClassB = AWeb.class({
extends : ClassA,
public : {
/**
* B-class constructor
*/
constructor : function() {
this.super();
/* Private variable */
this.variable1 = "B";
},
/**
* Function returns extended information about the object
*/
getLongInfo : function() {
return this.incCalls !== undefined ? "incCalls exists" : "incCalls undefined";
}
}
});
/**
* Main project function
*/
function main() {
var a = new ClassA(),
b = new ClassB();
alert(
"a.getInfo " + (a.getInfo ? "exists" : "undefined") + "\n" +
"a.getLongInfo " + (a.getLongInfo ? "exists" : "undefined") + "\n" +
"b.getInfo " + (b.getInfo ? "exists" : "undefined") + "\n" +
"b.getLongInfo " + (b.getLongInfo ? "exists" : "undefined") + "\n" +
"b.getInfo()=" + b.getInfo() + "\n" +
"b.getLongInfo()=" + b.getLongInfo()
);
}
我找到了一个比扩展和原型化更容易的解决方案。事实上,我不知道这有多高效,尽管它看起来干净实用
var A = function (p) {
if (p == null) p = this;
p.a1 = 0;
this.a2 = 0;
var a3 = 0;
};
var B = function (p) {
if (p == null) p = this;
p.b1 = new A(this);
this.b2 = new A(this);
var b3 = new A(this);
this b4 = new A();
};
var a = new A ();
var b = new B ();
结果:
a
a1 0
a2 0
b
a1 0
b1
a2 0
b2
a2 0
b4
a1 0
a2 0
实例:
var Point = function (p) {
if (p == null) p = this;
var x = 0;
var y = 0;
p.getPoint = function () { return [x,y]; };
p.setPoint = function (_x,_y) { x = _x; y = _y; };
};
var Dimension = function (p) {
if (p == null) p = this;
var w = 0;
var h = 0;
p.getDimension = function() { return [w,h] };
p.setDimension = function(_w,_h) { w = _w; h = _h };
};
var Rect = function (p) {
if (p == null) p = this;
var dimension = new Dimension(this);
var location = new Point(this);
};
var rect = new Rect ();
rect.setDimension({w:30,h:40});
rect.setPoint({x:50,y:50});
这个简单的方法怎么样
function Body(){
this.Eyes = 2;
this.Arms = 2;
this.Legs = 2;
this.Heart = 1;
this.Walk = function(){alert(this.FirstName + ' Is Walking')};
}
function BasePerson() {
var BaseBody = new Body(this);
BaseBody.FirstName = '';
BaseBody.LastName = '';
BaseBody.Email = '';
BaseBody.IntroduceSelf = function () { alert('Hello my name is ' + this.FirstName + ' ' + this.LastName); };
return BaseBody;
}
function Person(FirstName,LastName)
{
var PersonBuild = new BasePerson();
PersonBuild.FirstName = FirstName;
PersonBuild.LastName = LastName;
return PersonBuild;
}
var Person1 = new Person('Code', 'Master');
Person1.IntroduceSelf();
Person1.Walk();
这是我的解决方案,它基于中描述的标准原型继承方法 首先,我从定义这些帮助器方法开始,这些方法使以后的事情更容易理解和可读:
Function.prototype.setSuperclass = function(target) {
// Set a custom field for keeping track of the object's 'superclass'.
this._superclass = target;
// Set the internal [[Prototype]] of instances of this object to a new object
// which inherits from the superclass's prototype.
this.prototype = Object.create(this._superclass.prototype);
// Correct the constructor attribute of this class's prototype
this.prototype.constructor = this;
};
Function.prototype.getSuperclass = function(target) {
// Easy way of finding out what a class inherits from
return this._superclass;
};
Function.prototype.callSuper = function(target, methodName, args) {
// If methodName is ommitted, call the constructor.
if (arguments.length < 3) {
return this.callSuperConstructor(arguments[0], arguments[1]);
}
// `args` is an empty array by default.
if (args === undefined || args === null) args = [];
var superclass = this.getSuperclass();
if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");
var method = superclass.prototype[methodName];
if (typeof method != "function") throw new TypeError("TypeError: Object " + superclass.prototype + " has no method '" + methodName + "'");
return method.apply(target, args);
};
Function.prototype.callSuperConstructor = function(target, args) {
if (args === undefined || args === null) args = [];
var superclass = this.getSuperclass();
if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");
return superclass.apply(target, args);
};
诚然,即使使用helper函数,这里的语法也相当笨拙。不过,谢天谢地,在ECMAScript 6中添加了一些语法糖(),使事情变得更漂亮。例如:
/**
* Transform base class
*/
class Transform {
constructor() {
this.type = "2d";
}
toString() {
return "Transform";
}
}
/**
* Translation class.
*/
class Translation extends Transform {
constructor(x, y) {
super(); // Parent constructor
// Public properties
this.x = x;
this.y = y;
}
toString() {
return super(...arguments) + this.type + " Translation " + this.x + ":" + this.y;
}
}
/**
* Rotation class.
*/
class Rotation extends Transform {
constructor(angle) {
// Parent constructor
super(...arguments);
// Public properties
this.angle = angle;
}
toString() {
return super(...arguments) + this.type + " Rotation " + this.angle;
}
}
// Tests
translation = new Translation(10, 15);
console.log(translation instanceof Transform); // true
console.log(translation instanceof Translation); // true
console.log(translation instanceof Rotation); // false
console.log(translation.toString()) // Transform2d Translation 10:15
请注意,ECMAScript 6目前仍处于起草阶段,据我所知,它没有在任何主要的web浏览器中实现。但是,如果您愿意,可以使用类似的东西编译ECMAScript 6
到基于普通的ECMAScript 5
的JavaScript。您可以看到上面使用Traceur编译的示例。Basic原型继承
在JavaScript中执行继承的一种简单但有效的方法是使用以下两个线性函数:
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
这类似于这样做:
B.prototype = new A();
两者之间的主要区别在于A
的构造函数在使用时不运行,这更直观,更类似于基于类的继承
在创建B
的新实例时,通过将其添加到B
的构造函数中,您始终可以选择运行A
的构造函数:
function B(arg1, arg2) {
A(arg1, arg2); // This is optional
}
如果要将B
的所有参数传递给A
,还可以使用:
如果要将另一个对象混合到B
的构造函数链中,可以将对象与以下对象组合。创建:
演示
函数A(名称){
this.name=名称;
}
A.prototype=Object.create(Object.prototype);
A.prototype.constructor=A;
函数B(){
A.应用(这个,论点);
this.street=“唐宁街10号”;
}
B.prototype=Object.create(A.prototype);
B.prototype.constructor=B;
函数mixin(){
}
mixin.prototype=Object.create(Object.prototype);
mixin.prototype.constructor=mixin;
mixin.prototype.getProperties=函数(){
返回{
姓名:this.name,
地址:这条街,
年份:今年
};
};
函数C(){
B.应用(此,论点);
本年=“2018”
}
C.prototype=Object.assign(Object.create(B.prototype),mixin.prototype);
C.prototype.constructor=C;
var实例=新的C(“弗兰克”);
console.log(实例);
log(instance.getProperties())代码>Translation.prototype=Object.create(new Transform())?Translation.prototype=Object.create(Transform.prototype)@4esn0k是的,谢谢。为什么不干脆Translation.prototype=new Transform()
?此外,由于答案目前不起作用,y
function B(arg1, arg2) {
A(arg1, arg2); // This is optional
}
function B() {
A.apply(this, arguments); // This is optional
}
B.prototype = Object.assign(Object.create(A.prototype), mixin.prototype);
B.prototype.constructor = B;