【问题标题】:JavaScript override methodsJavaScript 覆盖方法
【发布时间】:2011-10-16 15:46:08
【问题描述】:

假设您有以下代码:

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

现在的问题是,如果有什么方法可以用AB 中的方法覆盖C 中的方法modify。在 Java 中,您会使用 super-关键字,但如何在 JavaScript 中实现这样的功能?

【问题讨论】:

  • modify 不是一种方法,而是一个嵌套函数——这两者之间是有区别的......
  • 在 Java 中,您使用 super 关键字访问超类的非私有字段和方法。您不会使用它来覆盖它们。

标签: javascript oop overriding


【解决方案1】:

你上次调用的方法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();

【讨论】:

  • C.prototype.modify() 会有错误的this 值。即C.prototype而不是c的实例。请使用.call(this),但你的答案只是重复的:)
【解决方案2】:

modify() 在您的示例中是一个私有函数,除了在您的 A、B 或 C 定义中之外,无法从任何地方访问。您需要将其声明为

this.modify = function(){}

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

【讨论】:

  • 修改是一个本地函数。 javascript中没有private
  • 本地/私有,这不是同一个东西,只是一个不同的术语吗?
【解决方案3】:

编辑:距写出原始答案已有六年了,发生了很多变化!

  • 如果您使用较新版本的 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 的更好语法。

【讨论】:

  • 除了使用工具“更好地创建类”之外,您根本无法创建类。 js 中的经典 OO 仿真总是很混乱。
  • (非建设性评论)作为浏览器世界中的“低级”语言非常丑陋,无缘无故。还在学习中,谢谢!
  • 我相信不是 Car.prototype = new Vehicle();这应该是 Car.prototype = Object.create(Vehicle.prototype);没有?
  • @Martin 是对的,见javascript-inheritance
  • Car.prototype = new Vehicle(); 的原因之一不正确,因为在接收颜色时没有任何东西可以传递给 Vehicle()。
【解决方案4】:

除非您将所有变量设为“公共”,即直接或通过prototype 属性将它们设为Function 的成员,否则不会。

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

最后,不能在Function 声明中调用modify,因为当我们将假定的“超类”设置为@987654339 时,会再次执行对“超类”的隐式调用@ 假定的“子类”的属性。

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

HTH,

FK

【讨论】:

  • 无论如何,&lt;name&gt;.prototype = new C; 对原型的所有成员的影子都没有任何意义
  • @Raynos:是的。也就是说,如果您不实例化C 对象,所有继承的Objects 将共享C 中的同一个成员。因此,在A 中更改x 将在C 中更改x,从而在B 中更改x。这显然是不可取的。
  • 你没有抓住重点。您可以删除该行,代码仍然可以运行
  • @Raynos:恐怕你错过了自己的观点。 ;-) 我们希望AB 继承自C。如果缺少那条线,情况就不是这样了。事实上,AB 的唯一原型将“影子”在这种情况下可以访问将是 Object.prototype
  • 看代码。 A 和 B 不使用原型中的任何 C 成员。所以从C“继承”是没有用的。这是因为 A 和 B 重新定义了 xymodify,从而影响了 C 的所有成员。如果您不使用它,将 C 放入原型有什么意义?这是死代码。
【解决方案5】:

Once 应该避免模仿经典的 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);

【讨论】:

【解决方案6】:

由于这是 Google 上的热门话题,我想给出一个更新的答案。

使用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 仍然不支持此功能,而 5 个月前发布的 iOS 9 已部分支持。

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

【讨论】:

  • 这个答案值得称赞,目前是正确答案。
  • 哇!像魅力一样工作!
【解决方案7】:

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

【讨论】:

    猜你喜欢
    • 2021-12-25
    • 2021-07-09
    • 2013-09-15
    • 2015-05-14
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    相关资源
    最近更新 更多