全面理解面向对象的 JavaScript(来自ibm)(3)


// 构造器 Person 本身是一个函数对象
 function Person() {
  // 此处可做一些初始化工作
 }
 // 它有一个名叫 prototype 的属性
 Person.prototype = {
    name: “张三”,
    age: 26,
    gender: “男”,
    eat: function( stuff ) {
        alert( “我在吃” + stuff );
    }
 }
 // 使用 new 关键字构造对象
 var p = new Person();

由于早期 JavaScript 的发明者为了使这门语言与大名鼎鼎的 Java 拉上关系 ( 虽然现在大家知道二者是雷锋和雷锋塔的关系 ),使用了new 关键字来限定构造器调用并创建对象,以使其在语法上跟 Java 创建对象的方式看上去类似。但需要指出的是,这两门语言的new含义毫无关系,因为其对象构造的机理完全不同。也正是因为这里语法上的类似,众多习惯了类式面向对象语言中对象创建方式的程序员,难以透彻理解 JS 对象原型构造的方式,因为他们总是不明白在 JS 语言中,为什么“函数名可以作为类名”的现象。而实质上,JS 这里仅仅是借用了关键字 new,仅此而已;换句话说,ECMAScript 完全可以用其它 非 new 表达式来用调用构造器创建对象。

彻底理解原型链 (prototype chain)

在 ECMAScript 中,每个由构造器创建的对象拥有一个指向构造器 prototype 属性值的 隐式引用(implicit reference,这个引用称之为 原型(prototype。进一步,每个原型可以拥有指向自己原型的 隐式引用(即该原型的原型),如此下去,这就是所谓的原型链(prototype chain ()。在具体的语言实现中,每个对象都有一个 __proto__ 属性来实现对原型的 隐式引用。说明了这一点。

清单 4. 对象的 __proto__ 属性和隐式引用

复制代码 代码如下:


 function Person( name ) {
    this.name = name;
 }
 var p = new Person();
 // 对象的隐式引用指向了构造器的 prototype 属性,所以此处打印 true
 console.log( p.__proto__ === Person.prototype );

// 原型本身是一个 Object 对象,所以他的隐式引用指向了
 // Object 构造器的 prototype 属性 , 故而打印 true
 console.log( Person.prototype.__proto__ === Object.prototype );

// 构造器 Person 本身是一个函数对象,所以此处打印 true
 console.log( Person.__proto__ === Function.prototype );

有了 原型链,便可以定义一种所谓的 属性隐藏机制,并通过这种机制实现继承。ECMAScript 规定,当要给某个对象的属性赋值时,解释器会查找该对象原型链中第一个含有该属性的对象(注:原型本身就是一个对象,那么原型链即为一组对象的链。对象的原型链中的第一个对象是该对象本身)进行赋值。反之,如果要获取某个对象属性的值,解释器自然是返回该对象原型链中首先具有该属性的对象属性值。说名了这中隐藏机制:


图 1. 原型链中的属性隐藏机制

图 1. 原型链中的属性隐藏机制

 

在图 1 中,object1->prototype1->prototype2 构成了 对象 object1 的原型链,根据上述属性隐藏机制,可以清楚地看到 prototype1 对象中的 property4 属性和 prototype2 对象中的 property3 属性皆被隐藏。理解了原型链,那么将非常容易理解 JS 中基于原型的继承实现原理, 是利用原型链实现继承的简单例子。

清单 5. 利用原型链 Horse->Mammal->Animal 实现继承

复制代码 代码如下:


// 声明 Animal 对象构造器
 function Animal() {
 }
 // 将 Animal 的 prototype 属性指向一个对象,
 // 亦可直接理解为指定 Animal 对象的原型
 Animal.prototype = {
    name: animal",
    weight: 0,
    eat: function() {
        alert( "Animal is eating!" );
    }
 }
 // 声明 Mammal 对象构造器
 function Mammal() {
    this.name = "mammal";
 }
 // 指定 Mammal 对象的原型为一个 Animal 对象。
 // 实际上此处便是在创建 Mammal 对象和 Animal 对象之间的原型链
 Mammal.prototype = new Animal();

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdzydw.html