html5中文学习网

您的位置: 首页 > 网站及特效实例 > javascript特效 » 正文

JavaScript中的原型继承基础学习教程_基础知识_

[ ] 已经帮助:人解决问题

大多数编程语言中,都有类和对象,一个类可以继承其他类。LZkHTML5中文学习网 - HTML5先行者学习网
在JavaScript中,继承是基于原型的(prototype-based),这意味着JavaScript中没有类,取而代之的是一个对象继承另一个对象。:)LZkHTML5中文学习网 - HTML5先行者学习网

1. 继承, the protoLZkHTML5中文学习网 - HTML5先行者学习网
在JavaScript中,当一个对象rabbit继承另一了对象animal时,这意味着rabbit对象中将会有一个特殊的属性:rabbit.__proto__ = animal;LZkHTML5中文学习网 - HTML5先行者学习网
当访问rabbit对象时,如果解释器在rabbit中不能找到属性,那么它会顺着__proto__链往上在animal对象中寻找LZkHTML5中文学习网 - HTML5先行者学习网
栗子中的__proto__属性仅在Chrome和FireFox中可以访问,请看一个栗子:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

var animal = { eats: true }var rabbit = { jumps: true }rabbit.__proto__ = animal // inheritalert(rabbit.eats) // true

eats属性是从animal对象中访问的。LZkHTML5中文学习网 - HTML5先行者学习网
如果在rabbit对象中已经发现了属性,那么就不会去检查proto属性啦。LZkHTML5中文学习网 - HTML5先行者学习网
再来一个栗子,当子类中也有eats属性时,父类中的就不会访问了。LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

var animal = { eats: true }var fedUpRabbit = { eats: false}fedUpRabbit.__proto__ = animal alert(fedUpRabbit.eats) // false

你也可以在animal中添加一个函数,那么在rabbit中也可以访问了。LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

var animal = { eat: function() {  alert( "I'm full" )  this.full = true }}var rabbit = { jump: function() { /* something */ }}rabbit.__proto__ = animal 

(1)rabbit.eat():LZkHTML5中文学习网 - HTML5先行者学习网
rabbit.eat()函数以如下两步执行:LZkHTML5中文学习网 - HTML5先行者学习网
首先,解释器查找rabbit.eat,rabbit中没有eat函数,那么它就顺着rabbit.__proto__往上找,在animal中找到了。LZkHTML5中文学习网 - HTML5先行者学习网
函数以this = rabbit运行。this值与__proto__属性完全无关。LZkHTML5中文学习网 - HTML5先行者学习网
因此,this.full = true在rabbit中:LZkHTML5中文学习网 - HTML5先行者学习网
看看这里我们有什么新发现,一个对象调用了父类函数,但是this还是指向对象本身,这就是继承。LZkHTML5中文学习网 - HTML5先行者学习网
被__proto__引用的对象称作是原型(prototype),animal是rabbit的原型(译者注:这就是rabbit的__proto__属性引用了animal 的prototype属性)LZkHTML5中文学习网 - HTML5先行者学习网
(2)读时查找,不是写时LZkHTML5中文学习网 - HTML5先行者学习网
当读取一个对象时,比如this.prop,解释器会在它的原型中查找属性。LZkHTML5中文学习网 - HTML5先行者学习网
当设置一个属性值时,比如this.prop = value,那么就没有理由去查找了,这个属性(prop)会被直接添加到这个对象中(这里是this)。delete obj.prop也类似,它只删除对象本身的属性,原型中的属性保持原封不动。LZkHTML5中文学习网 - HTML5先行者学习网
(3)关于protoLZkHTML5中文学习网 - HTML5先行者学习网
如果你在阅读指南,这里我们叫的__proto__,在指南中表示为[[Prototype]]。双方括号是很重要的,因为有另一个属性叫做prototype。LZkHTML5中文学习网 - HTML5先行者学习网

2. Object.create, Object.getPrototypeOfLZkHTML5中文学习网 - HTML5先行者学习网
__proto__是一个非标准的属性,由Chrome/FireFox提供访问,在其他的浏览器中保持不可见。LZkHTML5中文学习网 - HTML5先行者学习网
所有的现代浏览器除了Opera(IE > 9)支持两个标准的函数来处理原型问题:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

Object.ceate(prop[,props])

用给定了proto创建一个空对象:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

var animal = { eats: true }rabbit = Object.create(animal)alert(rabbit.eats) // true

上面代码创建了一个空rabbit对象,并且原型设置为animalLZkHTML5中文学习网 - HTML5先行者学习网
rabbit对象创建好以后,我们可以往里添加属性了:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

var animal = { eats: true }rabbit = Object.create(animal)rabbit.jumps = true

Object.creat函数的第二个参数props是可选的,它允许像新对象设置属性。这里就省略了,因为我们关系的继承。LZkHTML5中文学习网 - HTML5先行者学习网
(1)Object.getPrototypeOf(obj)LZkHTML5中文学习网 - HTML5先行者学习网
返回obj.__proto__的值。这个函数是标准的,可以在不能直接访问__proto__属性的浏览器中使用了。LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

var animal = { eats: true}rabbit = Object.create(animal)alert( Object.getPrototypeOf(rabbit) === animal ) // true

现代浏览器允许读取__proto__属性值,但是不能设置。LZkHTML5中文学习网 - HTML5先行者学习网

3. The prototypeLZkHTML5中文学习网 - HTML5先行者学习网
有一些好的跨浏览器的方式设置__proto__属性,这将会使用构造器函数(constructor functions)。记住!任何函数创建一个对象都是通过new关键字的。LZkHTML5中文学习网 - HTML5先行者学习网
一个栗子:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

function Rabbit(name) { this.name = name}var rabbit = new Rabbit('John')alert(rabbit.name) // John

new操作将原型的属性设置到rabbit对象的的__proto__属性中了。LZkHTML5中文学习网 - HTML5先行者学习网
让我们来看看它的原理,例如,new Rabbit 对象,而Rabbit是继承animal 的。LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

var animal = { eats: true }function Rabbit(name) { this.name = name}Rabbit.prototype = animalvar rabbit = new Rabbit('John')alert( rabbit.eats ) // true, because rabbit.__proto__ == animal

Rabbit.prototype = animal 字面量意味着:对所有由new Rabbit创建的对象设__proto__ = animalLZkHTML5中文学习网 - HTML5先行者学习网

4. 跨浏览器 Object.create(proto)LZkHTML5中文学习网 - HTML5先行者学习网
Object.create(prop)函数功能的强大的,因为它允许从给定的对象直接继承。它可以由如下代码模拟:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

function inherit(proto) { function F() {} F.prototype = proto return new F}

inherit(animal) 与Object.create(animal)是完全等同的,返回一个空的对象,并且object.__proto__ = animal。LZkHTML5中文学习网 - HTML5先行者学习网
一个栗子:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

var animal = { eats: true }var rabbit = inherit(animal)alert(rabbit.eats) // truealert(rabbit.hasOwnProperty('eats')) // false, from prototype

来看一下它的原理是什么:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

function inherit(proto) { function F() {}   // (1) F.prototype = proto // (2) return new F()   // (3)}

(1) 创建了一个新函数,函数没有向this设置任何属性,以此`new F` 会创建一个空对象。LZkHTML5中文学习网 - HTML5先行者学习网
(2) `F.prototype`被设置为protoLZkHTML5中文学习网 - HTML5先行者学习网
(3) `new` F创建了一个空对象,对象的`__proto__ = F.prototype` LZkHTML5中文学习网 - HTML5先行者学习网
(4) Bingo! 我们得到了一个继承`proto`的空对象LZkHTML5中文学习网 - HTML5先行者学习网
这个函数广泛适用于各种库和框架之中。LZkHTML5中文学习网 - HTML5先行者学习网
你的函数接受了一个带有options 的对象LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

/* options contains menu settings: width, height etc */function Menu(options) { // ...}你想设置某些optionsfunction Menu(options) { options.width = options.width || 300 // set default value // ...}

。。。但是改变参数值可能会产生一些错误的结果,因为options可能会在外部代码中使用。一个解决办法就是克隆options对象,复制所有的属性到一个新的对象中,在新对象中修改,LZkHTML5中文学习网 - HTML5先行者学习网
怎样用继承来解决这个问题呢? P.S. options可以添加设设置,但是不能被删除。LZkHTML5中文学习网 - HTML5先行者学习网
SolutionLZkHTML5中文学习网 - HTML5先行者学习网
你可以继承options,并且在它的子类的中修改或者添加新的属性。LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

function inherit(proto) { function F() {} F.prototype = proto return new F}function Menu(options) { var opts = inherit(options) opts.width = opts.width || 300 // ...}

所有的操作只在子对象中有效,当Menu方法结束时,外部代码仍然可以使用没有修改的过的options对象。delete操作在这里非常重要,如果width是一个prototype中的属性,delete opts.width不会产生任何作用LZkHTML5中文学习网 - HTML5先行者学习网

5. hasOwnPropertyLZkHTML5中文学习网 - HTML5先行者学习网
所有的对象都有hasOwnProperty函数,它可以用来检测一个属性是否对象自身还是属于原型LZkHTML5中文学习网 - HTML5先行者学习网
一个栗子:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

function Rabbit(name) { this.name = name}Rabbit.prototype = { eats: true }var rabbit = new Rabbit('John')alert( rabbit.hasOwnProperty('eats') ) // false, in prototypealert( rabbit.hasOwnProperty('name') ) // true, in object

6. Looping with/without inherited propertiesLZkHTML5中文学习网 - HTML5先行者学习网
for..in循环输出一个对象的所有属性,包括自身的和原型的。LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

function Rabbit(name) { this.name = name}Rabbit.prototype = { eats: true }var rabbit = new Rabbit('John')for(var p in rabbit) { alert (p + " = " + rabbit[p]) // outputs both "name" and "eats"}

用hasOwnProperty可以过滤得到属于对象自己的属性:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

function Rabbit(name) { this.name = name}Rabbit.prototype = { eats: true }var rabbit = new Rabbit('John')for(var p in rabbit) { if (!rabbit.hasOwnProperty(p)) continue // filter out "eats" alert (p + " = " + rabbit[p]) // outputs only "name"}

7. SummaryLZkHTML5中文学习网 - HTML5先行者学习网
JavaScript是通过一个特殊的属性proto来实现继承的LZkHTML5中文学习网 - HTML5先行者学习网
当访问一个对象的属性时,如果解释器不能在对象中找到,它就会去对象的原型中继续寻找 对函数属性来说,this指向这个对象,而不是它的原型。LZkHTML5中文学习网 - HTML5先行者学习网
赋值obj.prop = value, 删除delete obj.propLZkHTML5中文学习网 - HTML5先行者学习网
管理proto:LZkHTML5中文学习网 - HTML5先行者学习网
Chrome和FireFox可以直接访问对象的__proto__属性,大多数现代浏览器支持用Object.getPrototypeOf(obj)只读访问。LZkHTML5中文学习网 - HTML5先行者学习网
Object.create(proto) 可以用给定的proto生成空的子对象,或者通过如下代码达到相同的功能:LZkHTML5中文学习网 - HTML5先行者学习网
LZkHTML5中文学习网 - HTML5先行者学习网

function inherit(proto) {   function F() {}      F.prototype = proto   return new F()    }

其他方法:LZkHTML5中文学习网 - HTML5先行者学习网
for..in循环输出一个对象的所有属性(包括自身的和原型的)和对象的原型链。LZkHTML5中文学习网 - HTML5先行者学习网
如果一个属性prop属于对象obj那么obj.hasOwnProperty(prop)返回true,否则返回false。LZkHTML5中文学习网 - HTML5先行者学习网

(责任编辑:)
推荐书籍
推荐资讯
关于HTML5先行者 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助