这几天看了一些javascript的资料,有一些想法和疑惑,整理整理放在这里当作一个历史足印。
今天是第一篇,来点最基础的,说一说js的面向对象特性,总的来说,js的面向对象都是模拟的,跟一般的面向对象语言是有差异的,抓住这一点,所有的东西
说到OO,无非就是三大特性:封装/继承/多态。这些特性的存在都是基于类和对象的,那么先说说js的类。
js的类【模拟的类】:
//定义一个名为Person的类, function里面的内容就是构造函数了
var Person = function(name){
//
this.proname = name;
}
//静态方法
Person.write = function(str){
document.write(str + "<br/>");
}
var person = new Person("Jim");
//静态方法 classname.StaticFuncName
Person.write(person.proname);
js类的继承【模拟的类】:
JS的继承是通过一个叫作prototype的关键字是来实现,只要是挂在prototype上的对象,是的,就是对象,JS里面一切皆对象。看代码:
//定义一个名为Person的类, function里面的内容就是构造函数了
var Person = function(name){
//
this.proname = name;
}
//静态方法
Person.write = function(str){
document.write(str + "<br/>");
}
Person.prototype.walk = function(){
Person.write("Person.walk");
}
//var person = new Person("Jim");
//静态方法 classname.StaticFuncName
//Person.write(person.proname);
var Student = function(){}
Student.prototype = new Person;
//缓存父类的walk方法
var personWalk = Student.prototype.walk;
//重写walk
Student.prototype.walk = function(){
//父类的实现
personWalk.call(this);
Person.write("Student.walk");
}
var student = new Student;
student.walk();
输出的结果是:
Person.walk
Student.walk
这个例子演示了继承,也有点多态的味道,但是JS里面没有纯正的多态,总的来说所有的元素都是用于构造一种继承的样子。
目前看起来似乎跟一般的语言差不多,但是令我困惑以及有点小感悟的是下面这段
//Person基类?
var Person = function(){
this.init.call(this, arguments);
}
Person.writeLn = function(str){
document.write(str + "<br/>");
}
Person.prototype.init = function(){
Person.writeLn("Person.init");
}
//Student子类?
var Student = function(){}
Student.prototype = new Person;
var personInit = Student.prototype.init;
Student.prototype.init = function(){
personInit.call(this);
Person.writeLn("Student.init");
}
var student = new Student;
//输出什么?
这段代码我原先想构造这么一种情况:构造函数中调用一个可以被改写的方法,子类改写了之后,在实例化子类的时候,根据多态,应该会输出子类的实现,但是这个输出的结果竟然是 Person.init。为什么?没有得到预期的结果啊!这个还只是调用基类的实现而已啊?怎么破?
采用逐步屏蔽代码的方式,把最后一句(var student = new Student;
)屏蔽掉,一运行,竟然还是Person.init。这个结果让我恍然大悟!!!因为这个输出其实是Student.prototype = new Person;
这一句的结果,也就是说,我们的在实例化Student的时候,根本就没有执行walk方法。但是Student不是子类吗?最起码应该跟子类的构造函数一样啊?其实Student跟Person根本没有严格意义上的继承关系
很明显,仔细看一下,Student的构造函数本身是空的,如果说Student跟Person有几毛钱的关系,也仅仅在于prototype存储的是Person的实例,这样一来,Student就可以使用Person在prototype中共享的方法walk而已!仅此而已!因此,可以说JS中根本就没有面向对象,所有面向对象的感觉都是模拟出来的,同时模拟得如此真切以至于初学者很容易陷进去。
同时也说明了,prototype中存储的是一个对象,资料上一般说做原型对象。
其实总结一下就是,Js里面的类与类之间的关系更多是通过 组合的方式来实现的模拟继承,具体来说就是通过prototype来实现的组合,因此说其没有多态也算是OK了。
Prototype用来存储原型对象,而JS里面方法/属性其实都归属于对象,放在prototype上面就是用来共享的。用下面的一段代码结束:
//Person基类?
var Person = function(){
}
Person.writeLn = function(str){
document.write(str + "<br/>");
}
Person.prototype.commonInfo = [];
var p1 = new Person("jim");
p1.commonInfo.push("aaa");
var p2 = new Person("Kate");
p2.commonInfo.push("bbb");
Person.writeLn ("commonInfo.length:" + p2.commonInfo.length);
输出的结果是:commonInfo.length:2
commonInfo算是一个属性了,看起来共享了相同的对象!!!这个对于理解JavaScript很关键也就可见一斑了。