JavaScript 是一种基于原型的面向对象语言,而不是基于类的!!!javascript
基于类的面向对象语言,好比 Java,是构建在两个不一样实体的概念之上的:即类和对象。html
基于原型的语言(如 JavaScript)并不存在这种区别:它只有对象。基于原型的语言具备所谓原型对象(prototypical object)的概念。原型对象能够做为一个模板,新对象能够从中得到原始的属性。任何对象均可以指定其自身的属性,既能够是建立时也能够在运行时建立。并且,任何对象均可以做为另外一个对象的原型(prototype),从而容许后者共享前者的属性。java
对象的产生程序员
例如工厂造一辆车,一方面,工人必须参照一张工程图纸,设计规定这辆车应该如何制造。这里的工程图纸就比如是语言中的 类 (class),而车就是按照这个 类(class)制造出来的;另外一方面,工人和机器 ( 至关于 constructor) 利用各类零部件如发动机,轮胎,方向盘 ( 至关于 prototype 的各个属性 ) 将汽车构造出来。web
例如:闭包
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)。ide
对象能够由“new 关键字 + 构造器调用”的方式来建立函数
// 构造器 Person 自己是一个函数对象 function Person() { // 此处可作一些初始化工做 } // 它有一个名叫 prototype 的属性 Person.prototype = { name: "张三", age: 26, gender: "男", eat: function(stuff){ alert("我在吃" + stuff); } } // 使用 new 关键字构造对象 var p = new Person();
每一个由构造器建立的对象拥有一个指向构造器 prototype 属性值的 隐式引用(implicit reference),这个引用称之为 原型(prototype)。进一步,每一个原型能够拥有指向本身原型的 隐式引用(即该原型的原型),如此下去,这就是所谓的 原型链(prototype chain) 。this
在具体的语言实现中,每一个对象都有一个 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 属性皆被隐藏。(由于解释器会查找该对象原型链中第一个含有该属性的对象)
利用原型链 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 方法声明类很是简单。
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