JavaScript中的继承(高级篇)

[b]本文主要是针对《悟透JavaScript》第7、11章做的笔记。[/b]

[color=gray]为了方便,这篇笔记里我直接使用“类”这个名称。[/color]

[color=red][b]0、JSON[/b][/color]

先插点题外话(不是JavaScript的题外话,只是与主题“继承”没有直接关系),说说JSON。
JSON是JavaScript对象的另外一种表示方式,可以算是JavaScript对象的字面量吧。习惯上,我们是这样创建对象并给它添加属性:
var object = new Object
object.name = "an object"
object.age = 0

实际上,我们还有另外一种表示JavaScript对象的方式,也就是JSON,它的格式是这样的:
var object = {name:"an object", age:0}

给它添加个方法吧:
var object = {name:"an object", age:0, sayHi:function(){
alert("hi")
}
}

这形式看起来有点像哈希表(HashTable)。只是这个hash只能以字符串为key,来看看都有什么玩法:
var hash = {x:2,y:3}
alert(hash["x"]) //alert: 2
alert(hash.x) //alert: 2
hash["z"] = 4
alert(hash["z"]) //alert: 4
alert(hash.z) //alert: 4


假如有这样的代码:
var d = new Date;
var o = {d:'hello'};
alert(o[d]);
将会弹出什么?hello?不对,是undefined。要想看到hello必须这样:
alert(o['d']);
这个例子进一步说明了这个key只能是字符串,而不能是其它对象。
[quote="《JavaScript语言精粹》"]属性名可以是包括空字符串在内的任何字符串。在对象字面量中,如果属性名是一个合法的JavaScript标识符且不是保留字,并不强制要求用引号括住属性名。[/quote]

OK,JSON内容到此为止。

[color=red][b]1、原型真谛[/b][/color]

[url="http://yuan.iteye.com/blog/372259"]之前[/url]的JavaScript继承其实还有些美中不足:子类的prototype不但继承了父类的方法,同时也继承了父类的属性,但这些属性对子类的实例来说是没有用的,尽管这些属性的值是undefined,但这也是一种浪费啊(给JavaScript对象的一个属性赋值为undefined不意味着清除了该属性,反而会因此多了一个属性):
var puts = function(content){
document.write(content + "<br/>")
}

//定义Person类
function Person(name, age){
this.name = name
this.age = age
}

Person.prototype.sayHello = function(){
alert("Hello, I'm " + this.name + ".")
}

//定义Employee类
function Employee(name, age, salary){
//Person.call(this, name, age)
Person.apply(this, [name, age])
this.salary = salary
}

Employee.prototype = new Person
Employee.prototype.showMeTheMoney = function(){
alert(this.name + "$" + this.salary)
}

for(var e in Employee.prototype)
puts(e) //将会看到输出了name和age两个属性

回想对象创建的过程,构造函数只起到两个作用:1、介绍原型对象;2、初始化对象。那么我们能否自己定义一个对象来当做原型呢?直接用一个对象做原型,并且保证这个对象没有不必要的一些属性,不是就可以避免上面的情况了吗:
var Person = {
_create:function(name, age){
this.name = name
this.age = age
},
sayHello:function(){
alert("Hello, I'm " + this.name)
},
howOld:function(){
alert(this.name + " is " + this.age + " years old.")
}
}

可以这样利用上面的对象来构造对象:
function anyfun(name, age){
Person._create.apply(this, [name, age])
}

anyfun.prototype = Person
var yuan = new anyfun("yuan", 24)
yuan.sayHello()

但这个anyfun在构造完对象之后就没有用处了。如果把上面的这几句代码写成一个通用函数,那这个anyfun不就成了函数内的函数了吗?这样一来,当这个通用函数执行完毕,这个anyfun也就被销毁了。
function New(clazz, params){
function new_(){
clazz._create.apply(this, params)
}

new_.prototype = clazz
return new new_
}

var yuan = New(Person, ["yuan", 24])
yuan.sayHello()

再来加一些东西,让它更像一般的对象语言:
var object = {
isA:function(type){
var _self = this
while(_self){
if(_self == type)
return true
_self = _self._type
}
return false
}
}

function Class(base, define){
function class_(){ //构造一个原型
this._type = base //因为是构造原型,所以这个_type属性属于原型,而不是实例。
for(var member in define) //遍历定义体,把定义体中的每个属性复制给原型
this[member] = define[member]
}
class_.prototype = base //原型的类的原型。给原型的原型传递base对象的所有属性(即定义在基类中的所有方法),相当于间接给原型传递属性。。。。这话怎么这么绕呢
return new class_ //返回构造好的原型
}

function New(clazz, params){
function new_(){ //根据原型构造对象
this._type = clazz //这个对象有个_type,指向原型,供内部使用。
clazz._create.apply(this, params) //调用原型的构造方法,把参数传进去。
}
new_.prototype = clazz //从原型继承方法
return new new_ //构造并返回对象
}


var Person = Class(object, {
_create:function(name, age){
this.name = name
this.age = age
},
sayHello:function(){
alert("Hello, I'm " + this.name + ".")
},
howOld:function(){
alert(this.name + " is " + this.age + " years old.")
}
})

var Employee = Class(Person,{
_create:function(name, age, salary){
Person._create.call(this, name, age)
this.salary = salary
},
showMeTheMoney:function(){
alert(this.name + "$" + this.salary)
}
})

var yuan = New(Employee, ["yuan", 24, 8000])
yuan.sayHello()
yuan.howOld()
yuan.showMeTheMoney()
alert(yuan.isA(Employee))
alert(yuan.isA(Person))

很好很强大!

书上说这样的做法会使JavaScript程序效率更高,因为其原型对象里既没有了毫无用处的那些对象级的成员,而且还不存在constructor属性体,少了与构造函数间的牵连,但依旧保持了方法的共享性。这让JavaScript在追溯原型链和搜索属性及方法时少费许多工夫。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值