5

假设我在 JS 中有一个带有原型函数的类......

function Foo() {
    this.stuff = 7;
    this.otherStuff = 5;
}

Foo.prototype.doSomething = function() { };

Foo.prototype.doSomethingElse = function() { };

现在说我想通过继承它来“扩展”这个类。在 Java 中,这看起来像......

public class Bar extends Foo {}

现在我知道在 JS 中确实没有类的概念,一切都可以改变,这一切都归结为一堆废话,但尽管如此,我应该能够复制一个类的原型并附加它到另一个原型,对吧?

在 vanilla JS 中类似的代码会是什么样子?

4

5 回答 5

5

其中一种方法如下所示,

function Foo() {
    this.stuff = 7;
    this.otherStuff = 5;
}
Foo.prototype.doSomething = function() { alert("some"); };

Foo.prototype.doSomethingElse = function() { };

function Bar() {
   Foo.call(this); // this line
}
Bar.prototype = Object.create(Foo.prototype);

var b = new Bar();
b.doSomething(); 
于 2013-07-17T05:16:57.720 回答
2

像这样的东西...

function Bar(){
    // your code
}

Bar.prototype = new Foo(); // Bar extends Foo
于 2013-07-17T05:14:05.543 回答
2

接受的答案肯定会奏效。这个“简短”的解释变成了漫谈,但希望它会有所帮助。

对于接受的答案,您必须注意一件事。当你通过这样做基本上“继承”时,Bar.prototype = new Foo()你正在调用构造函数。因此,如果您的构造函数中有不希望用作另一个“类”的启动板的代码,那么您将得到奇怪的效果。举个例子:

var Person = function (firstName, lastName) {
    ....
};

var Student = function (firstName, lastName, grade) {
    ....
};

假设这StudentPerson. 您将如何构建原型Student?可能不喜欢Student.prototype = new Person("John", "Doe");

一种不同的处理方式,它有点复杂,但可以包装在另一个函数中,如下所示:

var extend = function (child, parent) {
    var f = function () {};
    f.prototype = parent.prototype;
    child.prototype = new f();
    child.prototype.constructor = parent;
}

var Person = function (firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}
Person.prototype.getName = function () {
    return this.firstName + " " + this.lastName;
}
Person.prototype.setAge = function (age) {
    this.age = age;
}


var Student = function (firstName, lastName, grade) {
    Person.call(this, firstName, lastName);
    this.grade = grade;
};

extend(Student, Person); //<< do this before adding stuff to the prototype

Student.prototype.getName = function () {
    var name = Person.prototype.getName.apply(this);
    return name + ", Grade " + this.grade;
}
Student.prototype.tooOldToBeAStudent = function () {
    if(this.age > 18) { return true; }
}

var p = new Person("Joe", "DiMaggio");
var s = new Student("Jack", "Sparrow", 12);
console.log(p.getName(), s.getName());
//consoles "Joe DiMaggio" "Jack Sparrow, Grade 12"
console.log(s instanceof Person); 
//true - even with the weird looking inheritance, Student is still an instance of Person.
s.setAge(30);
console.log(s.age);
//30, just like what you'd expect with a Person object.
console.log(s.tooOldToBeAStudent);
//true - as mentioned previously, 'age' is set via its inherited method.

这不仅为您提供了 Person 功能,还允许您在此基础上进行构建。有点像你实际上对继承所做的事情。

它是如何工作的?好问题。首先,对象是通过引用[基本上]分配的。原型是一个对象。因此,在extend函数中,我创建了一个空白函数,作为child. 这会将parent' 的原型复制到自身,然后将自身的新实例作为 的原型child。这样parent不会调用 ' 的构造函数,但仍使用父级的原型。为了确保它instanceof仍然有效,child.prototype.constructor设置为parent- 有效地通知 javascript 孩子来自父母,而不是代理人。

此外,当覆盖方法时,您可以使用您从原型方法继承的“类”和apply/或callthis- 在当前对象的范围内运行该方法,并且您可以传递任何您认为的参数,但它们被接受您选择的功能。例如,在学生的当前实例的上下文中Person.prototype.getName.apply(this);运行 Person's getName。假设我们想要覆盖 setAge 以简单地 console.log 退出年龄。

Student.prototype.setAge = function () {
    Person.prototype.setAge.apply(this, arguments);
    console.log(this.age);
}

这里发生的是使用传递给 ' PersonssetAge的参数调用Student's setAge。因此,它基本上允许这些东西通过,而您不必知道原始方法参数的细节。

于 2013-07-17T05:55:40.510 回答
2

mohkhan 提供的解决方案已经过时。进行继承的新方法是:

function Bar() {
    Foo.call(this, /* additional arguments if required */);
}

Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.constructor = Bar;              // don't forget to do this

如果你想让你的代码看起来更经典,那么看看这个augment方法。使用augment,您可以将上面的代码编写为:

var Bar = Foo.augment(function (base) {
    this.constructor = function () {
        base.constructor.call(this, /* additional arguments if required */);
    };
});

augment方法本身只有七行代码:

Function.prototype.augment = function (body) {
    var base = this.prototype;
    var prototype = Object.create(base);
    body.apply(prototype, Array.prototype.slice.call(arguments, 1).concat(base));
    if (!Object.hasOwnProperty.call(prototype, "constructor")) return prototype;
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
};

说真的,使用新方法。它更好。原因如下:Javascript 继承:设置原型时调用 Object.create

于 2013-07-17T06:38:05.893 回答
-3

javascript中扩展类的模式与java不同

var Person = Class.extend({
  init: function(isDancing){
    this.dancing = isDancing;
  },
  dance: function(){
    return this.dancing;
  }
});

var Ninja = Person.extend({
  init: function(){
    this._super( false );
  },
  dance: function(){
    // Call the inherited version of dance()
    return this._super();
  },
  swingSword: function(){
    return true;
  }
});

var p = new Person(true);
p.dance(); // => true

var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true

// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class
于 2013-07-17T05:11:23.183 回答