原型模式和基于原型继承的JavaScript对象系统
使用克隆的原型模式 var Plane = function(){ this.blood = 100; this.attackLevel = 1; this.defenseLevel = 1; }; var plane = new Plane(); plane.blood = 500; plane.attackLevel = 10; plane.defenseLevel = 7; var clonePlane = Object.create( plane ); console.log( clonePlane ); // 输出:Object {blood: 500, attackLevel: 10, defenseLevel: 7} 在不支持 Object.create 方法的浏览器中,则可以使用以下代码: Object.create = Object.create || function( obj ){ var F = function(){}; F.prototype = obj; return new F(); }
JavaScript中的原型继承
JavaScript 也同样遵守这些原型编程的基本规则。
所有的数据都是对象。
要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并克隆它。
对象会记住它的原型。
如果对象无法响应某个请求,它会把这个请求委托给它自己的原型。
下面我们来分别讨论 JavaScript 是如何在这些规则的基础上来构建它的对象系统的。
1. 所有的数据都是对象
JavaScript 在设计的时候,模仿 Java 引入了两套类型机制:基本类型和对象类型。基本类型 包括 undefined、number、boolean、string、function、object。从现在看来,这并不是一个好的 想法。
按照 JavaScript 设计者的本意,除了 undefined 之外,一切都应是对象。
事实上,JavaScript 中的根对象是 Object.prototype 对象。Object.prototype 对象是一个空的 对象。我们在 JavaScript 遇到的每个对象,实际上都是从 Object.prototype 对象克隆而来的, Object.prototype 对象就是它们的原型。比如下面的 obj1 对象和 obj2 对象:
var obj1 = new Object(); var obj2 = {};
可以利用 ECMAScript 5 提供的 Object.getPrototypeOf 来查看这两个对象的原型:
console.log( Object.getPrototypeOf( obj1 ) === Object.prototype ); // 输出:true
console.log( Object.getPrototypeOf( obj2 ) === Object.prototype ); // 输出:true
2. 要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并克隆它
3. 对象会记住它的原型
JavaScript 给对象提供了一个名为__proto__的隐藏属性,某个对象的__proto__属性默认会指 向它的构造器的原型对象,
即{Constructor}.prototype。在一些浏览器中,__proto__被公开出来, 我们可以在 Chrome 或者 Firefox 上用这段代码来验证:
var a = new Object();
console.log ( a.__proto__=== Object.prototype ); // 输出:true
4. 如果对象无法响应某个请求,它会把这个请求委托给它的构造器的原型
这条规则即是原型继承的精髓所在。从对 Io 语言的学习中,我们已经了解到,当一个对象 无法响应某个请求的时候,它会顺着原型链把请求传递下去,直到遇到一个可以处理该请求的对 象为止。
this的指向
除去不常用的 with 和 eval 的情况,具体到实际应用中,this 的指向大致可以分为以下 4 种。
作为对象的方法调用。
作为普通函数调用。
构造器调用。
Function.prototype.call 或 Function.prototype.apply 调用。
1. 作为对象的方法调用 当函数作为对象的方法被调用时,this 指向该对象:
var obj = {
a: 1,
getA: function(){
alert ( this === obj ); // 输出:true
alert ( this.a ); // 输出: 1
}
};
obj.getA();
2. 作为普通函数调用 当函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的 this 总是向全局对象。在浏览器的 JavaScript 里,这个全局对象是 window 对象。
window.name = 'globalName'; var getName = function(){ return this.name; }; console.log( getName() );// 输出:globalName 或者: window.name = 'globalName'; var myObject = { name: 'sven', getName: function(){ return this.name; } }; var getName = myObject.getName; console.log( getName() ); // globalName
call和apply的用途
1. 改变 this 指向
2. Function.prototype.bind
Function.prototype.bind = function( context ){ var self = this; // 保存原函数 return function(){ return self.apply( context, arguments );// 返回一个新的函数 // 执行新的函数的时候,会把之前传入的 context // 当作新函数体内的 this } }; var obj = { name: 'sven' }; var func = function(){ alert ( this.name ); }.bind( obj); func();// 输出:sven
3. 借用其他对象的方法-这个对象至少还要满足:
对象本身要可以存取属性;
对象的 length 属性可读写。
var a = {}; Array.prototype.push.call( a, 'first' ); alert ( a.length ); // 输出: alert ( a[ 0 ] ); // first
u