十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
JavaScript创建对象的几种方式 潜意识里,JavaScript不能算是面向对象的语言,要算也只能说是趋向面向对象的一种语言,至少它不能很好的吻合面向对象最基本的三大特性(继承、封装、多态),当然有很多人就认为JavaScript是面向对象语言,好像也说得...
创新互联建站是一家专注于成都网站设计、网站建设与策划设计,洮南网站建设哪家好?创新互联建站做网站,专注于网站建设10余年,网设计领域的专业建站公司;建站业务涵盖:洮南等地区。洮南做网站价格咨询:18982081108
利用原型继承。。。例如,一个person类 function Person(){} 一个student类 function Student(){}
student类继承person类:Student.prototype=new Person();
多态性表达为两个方面:类型的模糊与类型的确认(或识别)。在一些高
级语言中,他们分别被表达为“as”和“is”这两个关键词或运算。
JavaScript 是弱 类型 的,通 过 typeof 运算 考察 变量时 ,它 要么是 对象
(object),要么是非对象 (number, undefined, string 等),绝不存在 “像是某个对
象或者某个类”这样的多态问题。反过来说,因为任何一个实例的类型都是
object,因此 JavaScript 这种语言本身就“类型模糊 ”的。
同样由于没有严格的类型检测,因此你可以对任何对象调用任何方法,而
无需考虑它是否“被设计为”拥有该方法。对象的多态性被转换为运行期的动
态特性——例如我们可以动态地添加对象的方法/成员,使它看起来象是某个对象。下面的例子说明这种情况:
function Bird() {
var bird = (arguments.length == 1 ? arguments[0] : this);
bird.wing = 2;
bird.tweet = function() { };
bird.fly = function() {
alert('I can fly.');
}
return bird;
}
// 测试 1: 让一个对象 "fly" ,或让一只 ( 模仿的 ) 鸟 "fly"
var obj = new Object();
var bird = Bird(obj);
bird.fly(); // 能飞
obj.fly(); // 能飞
我们可以在这个例子中看到:obj 是不是 Bird 类型,并不是“fly”的必要前 提——
obj 在创建时,以及通过 Bird(obj)运算转换后,都是一个 Object 类型的对象,
但它是可以“飞(fly)”的 。“能否飞行”只取决于它有没有 fly 方法,而不取决
于它是不是某种类型的对象。
下面我们进述类型识别的问题。
由于所有对象的 typeof 值都是“object”,因此当在某些系统中要确知对象
的具体类型时,就需要使用 instanceof 运算来检测了。在“1.5.4 对象及其成员
的检查”中我们已经讲过该运算,它其实就等效于其它高级语言中的 is 运算。
对于上例来说,如果我们要使对象“能否飞行”取决于它是否是 Bird 构造器
(等义于“类”)产生的实例,那么应该使用类似下面的代码:
// ( 续上例 )
// var obj = new Object();
// var bird = Bird(obj);
function doFly(bird) {
if (bird instanceof Bird) {
obj.fly();
}
else {
throw new Error(' 对象不是 Bird 或其子类的实例 .');
}
}
// 测试 2: Bird 的实例可以 "fly", Object 的实例不能 "fly".
doFly(new Bird()); // 能飞
doFly(bird); // 不能飞
然而多态性中的类型识别还不仅包括这些。另一个关键问题,是在类型继
承中识别父类的同名方法。仍以上面的代码为例,但我们现在遇到的是一只鸵
鸟:
function Ostrich() {
this.fly = function() {
alert('I can\'t fly.');
}
}
Ostrich.prototype = new Bird();
Ostrich.prototype.constructor = Ostrich;
// 演示 : 鸵鸟是鸟,但不能飞
var ostrich = new Ostrich();
doFly(ostrich);
但是对于 doFly()这个函数来说,我们用以识别的表达式是:
(bird instanceof Bird)
这并有没错。因此这里也并不是 instanceof 运算的结果导致“飞”的失败,而
是因为 Ostrich 类的 fly 方法覆盖了父类方法。我们没有理由说 Bird 的子类必
须象 Bird 一样飞得很难看(例如 Phoenix 类一定是很艺术化地飞),而又“可
能”必须具体飞的能力 —— 因此子类必须依赖父类的某些能力来扩展新的方
法。
但是,冲突出现了:我们在实现子类 Ostrich 时已经覆盖了 fly 方法。同样 ,
我们实现 Phoenix 等等类时,也会覆盖这个方法。于是我们想要“依赖父类的
某些方法”时,却发现“找不到这些方法”了。
对于这一点,Delphi 提供了 inherited 语句,并保留了关键字 dynamic(动
态方法)和 virtual(虚方法)。但在 JavaScript 却无法实现相应的功能。简单地
说,如果子类与父类存在同名方法,那么在对象理解“多态特性”时,是应该
视为子类还是父类的方法呢?好的,我们先给出答案。这个答案包括两个部分:
1. JavaScript 中子类一定是覆盖父类的同名方法的。因此方法同名时,脚本总是
直接调用子类方法;
2. 由于是(动态的)覆盖,所以 JavaScript 中子类方法总是无法调用父类的同 名
方法。
进一步的推论是:JavaScript 无法依赖父类的同名方法(或被子类覆盖的
其它方法)。
继承父类的功能(而非仅是成员名称)是构建复杂的对象系统时所必须的
特性。然而我们看到 JavaScript 自身并不具备这种能力,这与 JavaScript 初始
设计时的主要应用环境有关:它是用于浏览器客户端快速开发的一种脚本语
言,而不是用于构建大型系统的通用语言。
当 JavaScript 用作一种富浏览器客户端(RWC)中的开发语言,或者一种
客户端应用开发的辅助语言(例如插件或外挂脚本)时,它在组织对象系统方
面的缺点就凸显出来,成为噬待解决的问题。本书第二部分将在 Qomo 内核构
建的过程中讨论相关的方法,并解决这些问题。