说我在JS中有一个原型函数的classe ......
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的代码会是什么样的?
答案 0 :(得分:4)
其中一种方式如下,
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();
答案 1 :(得分:3)
像这样......
function Bar(){
// your code
}
Bar.prototype = new Foo(); // Bar extends Foo
答案 2 :(得分:2)
接受的答案绝对可以解决问题。而这个“简短”的解释变成了漫无边际,但希望它有所帮助。
有一件事你需要了解接受的答案。当基本上通过执行Bar.prototype = new Foo()
“继承”时,你正在调用构造函数。因此,如果您的构造函数中的代码不希望用作另一个“类”的启动板,那么您将会遇到奇怪的效果。举个例子:
var Person = function (firstName, lastName) {
....
};
var Student = function (firstName, lastName, grade) {
....
};
假设Student
是Person
的扩展名。您如何在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
或call
与this
一起使用 - 运行方法的范围为当前对象,您可以传递任何您想要的参数,但是您选择的函数会接受它们。例如,Person.prototype.getName.apply(this);
在学生当前实例的上下文中运行Person getName
。假设我们想要将setAge重写为简单的console.log年龄。
Student.prototype.setAge = function () {
Person.prototype.setAge.apply(this, arguments);
console.log(this.age);
}
这里发生的事情是使用传递给Person
的{{1}}的参数调用setAge
的{{1}}。所以,它基本上允许东西通过,而你不必知道原始方法的参数的细节。
答案 3 :(得分: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
方法。使用扩充,您可以将上面的代码编写为:
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 inheritance: calling Object.create when setting a prototype
答案 4 :(得分:-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