JavaScript 继承

IT技术 javascript inheritance
2021-01-22 16:05:57

我正在尝试在 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.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);
6个回答

要在ECMAScript 5 中实现 javascript 继承,您可以定义对象的原型并用于Object.create继承。您还可以根据需要添加/覆盖属性。

例子:

/**
 * Transform base class
 */
function Transform() {
    this.type = "2d";
}

Transform.prototype.toString = function() {
    return "Transform";
}

/**
 * Translation class.
 */
function Translation(x, y) {
    // Parent constructor
    Transform.call(this);

    // Public properties
    this.x = x;
    this.y = y;
}

// Inheritance
Translation.prototype = Object.create(Transform.prototype);

// Override
Translation.prototype.toString = function() {
    return Transform.prototype.toString() + this.type + " Translation " + this.x + ":" + this.y;
}

/**
 * Rotation class.
 */
function Rotation(angle) {
    // Parent constructor
    Transform.call(this);

    // Public properties
    this.angle = angle;
}

// Inheritance
Rotation.prototype = Object.create(Transform.prototype);

// Override
Rotation.prototype.toString = function() {
    return Transform.prototype.toString() + 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
@4esn0k 是的,谢谢。
2021-03-24 16:05:57
@JörnZaefferer 看看这里:stackoverflow.com/q/4166616/885464“答案目前不起作用”是什么意思?
2021-03-25 16:05:57
为什么不只是Translation.prototype = new Transform()另外,由于答案目前不起作用,您会编辑它吗?
2021-03-31 16:05:57
Translation.prototype = Object.create(new Transform()); ? Translation.prototype = Object.create(Transform.prototype);
2021-04-05 16:05:57
你也应该设置子类的构造函数中明确:Translation.prototype.constructor = Translation用于克隆对象(在大多数技术中)。
2021-04-11 16:05:57

我认为 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)

我在我的博客上写了对上述解决方案的完整描述

除了它只支持所有公共成员
2021-03-12 16:05:57
最后,一个有效的非混淆解释!我颠倒了你的逻辑,让 E 沿相反的方向继承(E 对它的影响最大),因为这对我来说很有意义。谢谢!
2021-03-26 16:05:57
我认为@rodrigo-silveira 的意思是它不支持受保护的成员,解决方案也不支持。(根据定义,私有成员不能从子类访问,因此没有意义)。您必须使用类似this._myProtectedVariable = 5;创建受保护成员的方法。
2021-04-02 16:05:57
非常好的解决方案,只有(轻微)缺点,构造函数被执行两次。一次 D.call(this),再一次:new D()。这通常不是什么大问题,但如果你确实想避免它,你可以像这样使用 Object.create:而不是 C.prototype = new D(); 你可以写 C.prototype = Object.create(D.prototype); 示例:jsfiddle.net/9Dxkb/1
2021-04-07 16:05:57
@rodrigo-silveira,不确定你的意思。如果你想要私有,你只需用 var x = "whatever" 声明它们,不是吗?
2021-04-11 16:05:57

当我使用 JS 对象时,我发现了一个更简约的解决方案:-) 享受吧!

function extend(b,a,t,p) { b.prototype = a; a.apply(t,p); }

例子

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
2021-03-20 16:05:57
那会更糟。
2021-03-29 16:05:57
当然可以实现为 Object.create(new Son)
2021-04-04 16:05:57

为什么不使用对象而不是函数:

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 中使用函数继承不是正确的方法:http : //davidwalsh.name/javascript-objects-deconstruction

编辑

var Child 也可以写成:

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);
    }}
});