|
471 | 471 |
|
472 | 472 | 什么时候使用这种模式呢?其实,最好是能避免则避免,因为它带来了在这门语言中不存在的完整的类的概念,会让人疑惑。使用它需要学习新的语法和新的规则,也就是说,如果你或者你的团队习惯于使用类并且对原型感到不习惯,这种模式可能是一个可以探索的方向。这种模式允许你完全忘掉原型,好处就是你可以使用像其它语言那样的(变种)语法。 |
473 | 473 |
|
474 | | -<a name="a17"></a> |
475 | 474 | ## 原型继承 |
476 | 475 |
|
477 | | -现在,让我们从一个叫作“原型继承”的模式来讨论没有类的现代继承模式。在这种模式中,没有任何类进来,在这里,一个对象继承自另外一个对象。你可以这样理解它:你有一个想复用的对象,然后你想创建第二个对象,并且获得第一个对象的功能。下面是这种模式的用法: |
| 476 | +现在,让我们从一个叫作“原型继承”的模式来讨论没有类的现代继承模式。在这种模式中,没有任何类牵涉进来,一个对象继承自另外一个对象。你可以这样理解它:你有一个想复用的对象,然后你想创建第二个对象,并且获得第一个对象的功能。下面是这种模式的用法: |
478 | 477 |
|
479 | | - //需要继承的对象 |
| 478 | + // 需要继承的对象 |
480 | 479 | var parent = { |
481 | 480 | name: "Papa" |
482 | 481 | }; |
483 | 482 |
|
484 | | - //新对象 |
| 483 | + // 新对象 |
485 | 484 | var child = object(parent); |
486 | 485 |
|
487 | | - //测试 |
| 486 | + // 测试 |
488 | 487 | alert(child.name); // "Papa" |
489 | 488 |
|
490 | | -在这个代码片段中,有一个已经存在的使用对象字面量创建的对象叫parent,我们想创建一个和parent有相同的属性和方法的对象叫child。child对象使用object()函数创建。这个函数在JavaScript中并不存在(不要与构造函数Object()混淆),所以我们来看看怎样定义它。 |
| 489 | +在这个代码片段中,有一个已经存在的使用对象字面量创建的对象叫`parent`,我们想创建一个和`parent`有相同的属性和方法的对象叫`child`。`child`对象使用`object()`函数创建。这个函数在JavaScript中并不存在(不要与构造函数`Object()`混淆),所以我们来看看怎样定义它。 |
491 | 490 |
|
492 | | -与Holy Grail类式继承相似,可以使用一个空的临时构造函数F(),然后设定F()的原型为parent对象。最后,返回一个临时构造函数的新实例。 |
| 491 | +与Holy Grail类式继承相似,可以使用一个空的临时构造函数`F()`,然后设定`F()`的原型为`parent`对象。最后,返回一个临时构造函数的新实例。 |
493 | 492 |
|
494 | 493 | function object(o) { |
495 | 494 | function F() {} |
496 | 495 | F.prototype = o; |
497 | 496 | return new F(); |
498 | 497 | } |
499 | 498 |
|
500 | | -图6-9展示了使用原型继承时的原型链。在这里child总是以一个空对象开始,它没有自己的属性但通过原型链(\_\_proto\_\_)拥有父对象的所有功能。 |
| 499 | +图6-9展示了使用原型继承时的原型链。这样创建的`child`总是一个空对象,它没有自有属性但通过原型链(`__proto__`)拥有父对象的所有功能。 |
501 | 500 |
|
502 | 501 |  |
503 | 502 |
|
504 | 503 | 图6-9 原型继承模式 |
505 | 504 |
|
506 | | -<a name="a18"></a> |
507 | 505 | ### 讨论 |
508 | 506 |
|
509 | | -在原型继承模式中,parent不需要使用对象字面量来创建。(尽管这是一种更常用的方式。)可以使用构造函数来创建parent。注意,如果你这样做,那么自己的属性和原型上的属性都将被继承: |
| 507 | +在原型继承模式中,`parent`不一定需要使用对象字面量来创建(尽管这是一种常用的方式),也可以使用构造函数来创建。注意,如果你这样做,那么自有属性和原型上的属性都将被继承: |
510 | 508 |
|
511 | | - // parent constructor |
| 509 | + // 父构造函数 |
512 | 510 | function Person() { |
513 | | - // an "own" property |
| 511 | + // 自有属性 |
514 | 512 | this.name = "Adam"; |
515 | 513 | } |
516 | | - // a property added to the prototype |
| 514 | + // 原型上的属性 |
517 | 515 | Person.prototype.getName = function () { |
518 | 516 | return this.name; |
519 | 517 | }; |
520 | 518 |
|
521 | | - // create a new person |
| 519 | + // 使用Person()创建一个新对象 |
522 | 520 | var papa = new Person(); |
523 | | - // inherit |
| 521 | + // 继承 |
524 | 522 | var kid = object(papa); |
525 | 523 |
|
526 | | - // test that both the own property |
527 | | - // and the prototype property were inherited |
| 524 | + // 测试:自有属性和原型上的属性都被继承了 |
528 | 525 | kid.getName(); // "Adam" |
529 | 526 |
|
530 | | -在这种模式的另一个变种中,你可以选择只继承已存在的构造函数的原型对象。记住,对象继承自对象,不管父对象是怎么创建的。这是前面例子的一个修改版本: |
| 527 | +也可以使用这种模式的一个变种,只继承已存在的构造函数的原型对象。记住,对象继承自对象,而不管父对象是怎么创建的。这是前面例子的一个修改版本: |
531 | 528 |
|
532 | | - // parent constructor |
| 529 | + // 父构造函数 |
533 | 530 | function Person() { |
534 | | - // an "own" property |
| 531 | + // 自有属性 |
535 | 532 | this.name = "Adam"; |
536 | 533 | } |
537 | | - // a property added to the prototype |
| 534 | + // 原型上的属性 |
538 | 535 | Person.prototype.getName = function () { |
539 | 536 | |
540 | 537 | }; |
541 | 538 |
|
542 | | - // inherit |
| 539 | + // 继承 |
543 | 540 | var kid = object(Person.prototype); |
544 | 541 |
|
545 | | - typeof kid.getName; // "function", because it was in the prototype |
546 | | - typeof kid.name; // "undefined", because only the prototype was inherited |
| 542 | + typeof kid.getName; // "function",因为它在原型中 |
| 543 | + typeof kid.name; // "undefined",因为只有原型中的成员被继承了 |
547 | 544 |
|
548 | | -<a name="a19"></a> |
549 | | -###例外的ECMAScript 5 |
| 545 | +### ECMAScript5中的原型继承 |
550 | 546 |
|
551 | | -在ECMAScript 5中,原型继承已经正式成为语言的一部分。这种模式使用Object.create方法来实现。换句话说,你不再需要自己去写类似object()的函数,它是语言原生的了: |
| 547 | +在ECMAScript5中,原型继承已经正式成为语言的一部分。这种模式使用`Object.create()`方法来实现。换句话说,你不再需要自己去写类似`object()`的函数,它是语言原生的部分了: |
552 | 548 |
|
553 | 549 | var child = Object.create(parent); |
554 | 550 |
|
555 | | -Object.create()接收一个额外的参数——一个对象。这个额外对象中的属性将被作为自己的属性添加到返回的子对象中。这让我们可以很方便地将继承和创建子对象在一个方法调用中实现。例如: |
| 551 | +`Object.create()`接收一个额外的参数——一个对象。这个额外对象中的属性将被作为自有属性添加到返回的子对象中。这让我们可以很方便地将继承和创建子对象在一个方法调用中实现。例如: |
556 | 552 |
|
557 | 553 | var child = Object.create(parent, { |
558 | | - age: { value: 2 } // ECMA5 descriptor |
| 554 | + age: { value: 2 } // ES5中的属性描述符 |
559 | 555 | }); |
560 | 556 | child.hasOwnProperty("age"); // true |
561 | 557 |
|
562 | | -你可能也会发现原型继承模式已经在一些JavaScript类库中实现了,比如,在YUI3中,它是Y.Object()方法: |
| 558 | +你可能也会发现原型继承模式已经在一些JavaScript类库中实现了,比如,在YUI3中,它是`Y.Object()`方法: |
563 | 559 |
|
564 | 560 | YUI().use('*', function (Y) { |
565 | 561 | var child = Y.Object(parent); |
|
0 commit comments