### JavaScript - 基于原型的面向对象

1. 引言

JavaScript 是一种基于原型的面向对象语言,而不是基于类的!!!

  • 基于类的面向对象语言,比如 Java,是构建在两个不同实体的概念之上的:即类和对象。

  • 基于原型的语言(如 JavaScript)并不存在这种区别:它只有对象。基于原型的语言具有所谓原型对象(prototypical object)的概念。原型对象可以作为一个模板,新对象可以从中获得原始的属性。任何对象都可以指定其自身的属性,既可以是创建时也可以在运行时创建。而且,任何对象都可以作为另一个对象的原型(prototype),从而允许后者共享前者的属性。

对象的产生

  • 基于类的面向对象语言: 依靠类产生
  • 基于原型的面向对象语言: 依靠 构造器利用原型构造出来的。

例如工厂造一辆车,一方面,工人必须参照一张工程图纸,设计规定这辆车应该如何制造。这里的工程图纸就好比是语言中的 类 (class),而车就是按照这个 类(class)制造出来的;另一方面,工人和机器 ( 相当于 constructor) 利用各种零部件如发动机,轮胎,方向盘 ( 相当于 prototype 的各个属性 ) 将汽车构造出来。

2.构造对象

  • 字面式对象声明

例如:

var test = {
name : 'Test',
email : '123@qq.com'
website : 'http://www.test.com'
}

然后可以访问

//以成员的方式
test.name;
test.email;
//以hash_map的方式
test["name"];
test["website"];
  • 使用函数构造器构造对象

每个构造器实际上是一个 函数(function) 对象, 该函数对象含有一个“prototype”属性用于实现 基于原型的继承(prototype-based inheritance)和 共享属性(shared properties)。

对象可以由“new 关键字 + 构造器调用”的方式来创建

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

3.理解原型链

每个由构造器创建的对象拥有一个指向构造器 prototype 属性值的 隐式引用(implicit reference),这个引用称之为 原型(prototype)。进一步,每个原型可以拥有指向自己原型的 隐式引用(即该原型的原型),如此下去,这就是所谓的 原型链(prototype chain) 。

在具体的语言实现中,每个对象都有一个 proto 属性来实现对原型的 隐式引用。

function Person(name){
this.name = name;
}
var p = new Person();
console.log(p.__proto__ === Person.prototype ); // 对象的隐式引用指向了构造器的 prototype 属性,所以此处打印 true
console.log(Person.prototype.__proto__ === Object.prototype ); //原型本身是一个 Object 对象,所以他的隐式引用指向了Object 构造器的 prototype 属性 , 故而打印 true
console.log(Person.__proto__ === Function.prototype );// 构造器 Person 本身是一个函数对象,所以此处打印 true

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

object1->prototype1->prototype2 构成了 对象 object1 的原型链,根据上述属性隐藏机制,可以清楚地看到 prototype1 对象中的 property4 属性和 prototype2 对象中的 property3 属性皆被隐藏。(因为解释器会查找该对象原型链中第一个含有该属性的对象

4.继承

  • 利用原型链 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.prototype = new Animal(); // 实际上此处便是在创建 Mammal 对象和 Animal 对象之间的原型链 // 声明 Horse 对象构造器
    function Horse(height,weight){
    this.name = "horse";
    this.height = height;
    this.weight = weight;
    }
    // 将 Horse对象的原型指定为一个 Mamal 对象,继续构建 Horse 与 Mammal 之间的原型链
    Horse.prototype = new Mammal(); // 重新指定 eat方法 , 此方法将覆盖从 Animal 原型继承过来的 eat 方法
    Horse.prototype.eat = function() {
    alert( "Horse is eating grass!");
    } // 验证并理解原型链
    var horse = new Horse( 100, 300 );
    console.log(horse.__proto__ === Horse.prototype );
    console.log( Horse.prototype.__proto__ === Mammal.prototype );
    console.log( Mammal.prototype.__proto__ === Animal.prototype );
  • 类式继承

基于原型的继承方式,虽然实现了代码复用,但其行文松散且不够流畅,可阅读性差,不利于实现扩展和对源代码进行有效地组织管理。

所以,类式继承方式在语言实现上更具健壮性,且在构建可复用代码和组织架构程序方面具有明显的优势。这使得程序员们希望寻找到一种能够在 JavaScript 中以类式继承风格进行编码的方法途径。

jQuery 之父 John Resig 在搏众家之长之后,用不到 30 行代码便实现了自己的 Simple Inheritance。使用其提供的 extend 方法声明类非常简单。

4.JavaScript 私有成员实现

JavaScript 的信息隐藏就是靠闭包实现的。

// 声明 User 构造器
function User( pwd ) {
var password = pwd; // 定义私有属性
// 定义私有方法
function getPassword() { // 返回了闭包中的 password
return password;
} // 特权函数声明,用于该对象其他公有方法能通过该特权方法访问到私有成员
this.passwordService = function() {
return getPassword();
}
}
// 公有成员声明
User.prototype.checkPassword = function( pwd ) {
return this.passwordService() === pwd;
};
// 验证隐藏性
var u = new User( "123456" );
console.log( u.checkPassword("123456" )); // 打印 true
console.log( u.password ); // 打印 undefined
console.log( typeof u.getPassword === "undefined" );// 打印 true

JavaScript的prototype 具体含义,或者继承机制的设计思想,良心推荐,讲的非常清楚。

http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html

JavaScript - 基于原型的面向对象的更多相关文章

  1. javascript: 基于原型的面向对象编程

    Douglas Crockford指出javascript是世界上最被误解的编程语言.由于javascript缺少常见的面向对象概念,许多程序猿认为javascript不是一个合适的语言.我在做第一个 ...

  2. javascript基于原型实现面向对象

    传统的OO语言有类的概念,但js(ES5)却是基于原型实现的面向对象. 原型是?我们创建的每一个函数都会有一个原型(prototype)属性,这个属性是一个指针,指向函数的原型(prototype)对 ...

  3. javascript基于原型的语言的特点

    一.基于原型的语言的特点 1 只有对象,没有类;对象继承对象,而不是类继承类. 2  “原型对象”是基于原型语言的核心概念.原型对象是新对象的模板,它将自身的属性共享给新对象.一个对象不但可以享有自己 ...

  4. JavaScript基于原型的继承

    在一个纯粹的原型模式中,我们会摒弃类,转而专注于对象,基于原型的继承相比基于类的继承的概念上更为简单 if( typeof Object.beget !== 'function') { Object. ...

  5. 面向对象的JavaScript --- 原型模式和基于原型继承的JavaScript对象系统

    面向对象的JavaScript --- 原型模式和基于原型继承的JavaScript对象系统 原型模式和基于原型继承的JavaScript对象系统 在 Brendan Eich 为 JavaScrip ...

  6. JavaScript初探系列之面向对象

    面向对象的语言有一个标志,即拥有类的概念,抽象实例对象的公共属性与方法,基于类可以创建任意多个实例对象,一般具有封装.继承.多态的特性!但JS中对象与纯面向对象语言中的对象是不同的,ECMA标准定义J ...

  7. Atitit.prototype-base class-based  基于“类” vs 基于“原型”

    Atitit.prototype-base class-based  基于“类” vs 基于“原型” 1. 基于“类” vs 基于“原型”1 2.  对象的产生有两种基本方式.一种是以原型(proto ...

  8. javascript面向对象 用new创建一个基于原型的javascript对象

    //创建一个类 其实就是个对象 var Student={ name:"robot", height:1.6, run:function(){ console.log(this.n ...

  9. 通过JavaScript原型链理解基于原型的编程

    零.此文动机 用了一段时间的Lua,用惯了Java C++等有Class关键字的语言,一直对Lua的中的面向对象技术感到费解,一个开源的objectlua更是看了n遍也没理解其中的原理,直到看到了Pr ...

随机推荐

  1. python3-day3(函数-返回值)

    1.函数 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 2.return返回值 import smtplibfro ...

  2. Zedboard甲诊opencv图像处理(三)

    整个工程进展到这一步也算是不容易吧,但技术含量也不怎么高,中间乱起八糟的错误太烦人了,不管怎么样,现在面临了最大的困难吧,图像处理算法.算法确实不好弄啊,虽然以前整过,但都不是针对图像的. 现在的图像 ...

  3. php缓存方案

    一.说说Memcached优化方案 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态.数据 ...

  4. C++11 多线程 教学(2)

      C++11开始支持多线程编程,之前多线程编程都需要系统的支持,在不同的系统下创建线程需要不同的API如pthread_create(),Createthread(),beginthread()等, ...

  5. Linux的启动流程

    1.首先是bios加电自检.初始化,这个过程会检测相关硬件(cpu.内存.硬盘等),然后会读取硬盘中的MBR:2.加载内核,读取/boot里边的配置文件:3.启动初始化进程,开始运行/sbin/ini ...

  6. Enable-Migrations 在应用程序配置文件中找不到xx连接字符串

    在解决方案中有多个项目时,使用Enable-Migrations 命令进行数据迁移时,出现以下错误: 尝试在Enable-Migrations 命令中指定-projectName也不行,最后将要操作的 ...

  7. REST 相关

    REST 相关 REST:Representational State Transfer,表现层状态转化(出现在阮一峰的博客 理解RESTful架构 中,但是,很明显,Representational ...

  8. SVN CornerStone的使用

    http://www.henishuo.com/mac-cornerstone-svn-use/

  9. hdu 1262寻找素数对

    Problem Description 哥德巴赫猜想大家都知道一点吧.我们现在不是想证明这个结论,而是想在程序语言内部能够表示的数集中,任意取出一个偶数,来寻找两个素数,使得其和等于该偶数. 做好了这 ...

  10. HDU 5044 离线LCA算法

    昨天写了HDU 3966 ,本来这道题是很好解得,结果我想用离线LCA 耍一把,结果发现离线LCA 没理解透,错了好多遍,终得AC ,这题比起 HDU 3966要简单,因为他不用动态查询.但是我还是错 ...