JavaScript覆盖方法

问题描述 投票:68回答:7

假设你有以下代码:

function A() {
    function modify(){
       x = 300;
       y = 400;
    }
    var c = new C();
}

function B() {
    function modify(){
       x = 3000;
       y = 4000;
    }
    var c = new C();
}


C = function () {
   var x = 10;
   var y = 20;

   function modify() {
      x = 30;
      y = 40;
   };

   modify();
   alert("The sum is: " + (x+y));
}

现在问题是,如果有任何方法,我可以使用A和B中的方法覆盖C中的方法modify。在Java中,您将使用super关键字,但是如何在JavaScript中实现类似的功能呢?

javascript oop override
7个回答
123
投票

编辑:现在已经六年了,原来的答案已经写好了,而且很多都改变了!

  • 如果您使用的是较新版本的JavaScript,可能使用像Babel这样的工具进行编译,那么您可以使用use real classes
  • 如果您正在使用AngularReact提供的类类组件构造函数,那么您将需要查看该框架的文档。
  • 如果你正在使用ES5并使用原型手工制作“假”类,下面的答案仍然是正确的。

祝好运!


JavaScript继承看起来与Java有点不同。以下是本机JavaScript对象系统的外观:

// Create a class
function Vehicle(color){
  this.color = color;
}

// Add an instance method
Vehicle.prototype.go = function(){
  return "Underway in " + this.color;
}

// Add a second class
function Car(color){
  this.color = color;
}

// And declare it is a subclass of the first
Car.prototype = new Vehicle();

// Override the instance method
Car.prototype.go = function(){
  return Vehicle.prototype.go.call(this) + " car"
}

// Create some instances and see the overridden behavior.
var v = new Vehicle("blue");
v.go() // "Underway in blue"

var c = new Car("red");
c.go() // "Underway in red car"

不幸的是,这有点难看,它不包含一个非常好的“超级”方式:你必须手动指定要调用哪个父类的方法。因此,有许多工具可以使创建类更好。尝试查看Prototype.js,Backbone.js或类似的库,其中包含用于在js中执行OOP的更好的语法。


34
投票

由于这是谷歌的热门话题,我想提供一个更新的答案。

使用ES6 classes使继承和方法覆盖更容易:

'use strict';

class A {
    speak() {
        console.log("I'm A");
    }
}

class B extends A {
    speak() {
        super.speak();

        console.log("I'm B");
    }
}

var a = new A();
a.speak();
// Output:
// I'm A

var b = new B();
b.speak();
// Output:
// I'm A
// I'm B

super keyword在继承类中使用时引用父类。此外,父类的所有方法都绑定到子实例,因此您不必编写super.method.apply(this);

至于兼容性:the ES6 compatibility table仅显示主要播放器支持类的最新版本(主要是)。 V8浏览器从今年1月开始就已经有了它们(Chrome和Opera),使用SpiderMonkey JS引擎的Firefox将在下个月推出官方Firefox 45版本。在移动端,Android仍然不支持此功能,而五个月前发布的iOS 9有部分支持。

幸运的是,有Babel,一个用于将Harmony代码重新编译为ES5代码的JS库。 ES6中的类和许多其他很酷的功能可以使您的Javascript代码更具可读性和可维护性。


6
投票

应该避免模仿经典OO并使用原型OO。一个很好的实用OO实用程序库是traits

而不是覆盖方法和设置继承链(一个应该始终支持对象组合而不是对象继承),您应该将可重用的函数捆绑到特征中并使用这些特性创建对象。

Live Example

var modifyA = {
    modify: function() {
        this.x = 300;
        this.y = 400;
    }
};

var modifyB = {
    modify: function() {
        this.x = 3000;
        this.y = 4000;
    }
};

C = function(trait) {
    var o = Object.create(Object.prototype, Trait(trait));

    o.modify();
    console.log("sum : " + (o.x + o.y));

    return o;
}

//C(modifyA);
C(modifyB);

3
投票

您的示例中的modify()是一个私有函数,不能从A,B或C定义中的任何位置访问。您需要将其声明为

this.modify = function(){}

C没有引用它的父项,除非你把它传递给C.如果C被设置为继承自A或B,它将继承它的公共方法(不是它的私有函数,就像你定义了modify())。一旦C从其父级继承方法,您就可以覆盖继承的方法。


2
投票

你在最后调用的方法modify()在全局上下文中被调用,如果你想覆盖modify(),你首先必须继承AB

也许你正试图这样做:

在这种情况下,C继承了A

function A() {
    this.modify = function() {
        alert("in A");
    }
}

function B() {
    this.modify = function() {
        alert("in B");
    }
}

C = function() {
    this.modify = function() {
        alert("in C");
    };

    C.prototype.modify(); // you can call this method where you need to call modify of the parent class
}

C.prototype = new A();

1
投票

除非你将所有变量都设为“公共”,即直接或通过Function属性使它们成为prototype的成员。

var C = function( ) {
    this.x = 10 , this.y = 20 ;
    this.modify = function( ) {
        this.x = 30 , this.y = 40 ;
        console.log("(!) C >> " + (this.x + this.y) ) ;
    } ;
} ;

var A = function( ) {
    this.modify = function( ) {
       this.x = 300 , this.y = 400 ;
       console.log("(!) A >> " + (this.x + this.y) ) ;
    } ;
} ;
    A.prototype = new C ;

var B = function( ) {
    this.modify = function( ) {
       this.x = 3000 , this.y = 4000 ;
       console.log("(!) B >> " + (this.x + this.y) ) ;
    } ;
} ;


new C( ).modify( ) ;
new A( ).modify( ) ;
new B( ).modify( ) ; 

您会注意到一些变化。

最重要的是,对所谓的“超类”构造函数的调用现在隐含在这一行中:

<name>.prototype = new C ;

AB现在都有单独可修改的成员xy,如果我们改为编写... = C,情况就不会如此。

然后,xymodify都是“公共”成员,因此为他们分配不同的Function

 <name>.prototype.modify = function( ) { /* ... */ }

将用这个名称“覆盖”原来的Function

最后,对modify的调用无法在Function声明中完成,因为当我们将所谓的“超类”设置为所谓的“子类的prototype属性”时,将再次执行对“超类”的隐式调用。 ”。

但是,这或多或少是你在JavaScript中做这种事情的方式。

HTH,

FK


0
投票

function A() {
    var c = new C();
	c.modify = function(){
		c.x = 123;
		c.y = 333;
	}
	c.sum();
}

function B() {
    var c = new C();
	c.modify = function(){
		c.x = 999;
		c.y = 333;
	}
	c.sum();
}


C = function () {
   this.x = 10;
   this.y = 20;

   this.modify = function() {
      this.x = 30;
      this.y = 40;
   };
   
   this.sum = function(){
	this.modify();
	console.log("The sum is: " + (this.x+this.y));
   }
}

A();
B();
© www.soinside.com 2019 - 2024. All rights reserved.