JAVASCRIPT
118、对象的继承
JavaScript 有多种方式模拟继承. 1. 利用 function: function superClass() {
this.bye = superBye; this.hello = superHello; }
function subClass() { this.inheritFrom = superClass; this.inheritFrom(); this.bye = subBye;
this.callback=(this.callback).andThen(callbackFunction); } } var manager=new Manager(); manager.registerCallback(sayHi); manager.registerCallback(sayBye); manager.callback();
var abook = new Book("JavaScript is Cool", "tom", 514); var books = getBooksWithSameAuthor.call(abook, 1990, 2005); 或 var books = getBooksWithSameAuthor.apply(abook, [1990, 2005]); 当一个 function 不作为一个对象的 method 时, JavaScript 会认为它是属于一个 Globle Object 对象的 method, 这个 Globle Object 在 Browser 中就是 window 类. 所以从这个角度来说, function 和 method 又可以统一起来了. Function object 还有一个非常重要的 property: prototype. 它是一个 predefined 的 prototype object. 当一个 Function 用作对象的 constructor 时, protptype property 将 发挥作用,中文翻译叫原型. JavaScript 的新对象就是通过 function 的原型来建立 的. 同时我们还可以利用 prototype 来动态的向对象中添加属性, 如: function Book (name, author, page) { = name; this.author = author; this.page = page; } var abook = new Book("JavaScript is Cool", "tom", 514);
} 或者: function subClass() {
superClass.call(this); } 先定义 subClass 的 inheritFrom 方法, 再调用这个方法(方法名称并不重要), 或者 直 接 使 用 Function Object 的 call 方 法 将 this 做 参 数 , 都 可 以 模 拟 实 现 从 superClass 的继承. 注意调用 superClass 时的 this 指向. 这个方法就是在执行 subClass 的 cunstructor function 时, 先执行 supperClass 的 cunstructor function.这个 方法的缺点在于子类仅仅是在自己的构造函数中, 将 this 作为参数调用了父类的 构造函数, 将构造函数赋予父类的所有域赋予子类. 所以, 任何父类在构造函数 之外(通过 prototype)定义的域, 子类都无法继承. 而且子类的构造函数一定要在 定义自己的域之前调用父类的构造函数, 免得子类的定义被父类覆盖. 使用这种 方法子类也尽量不要使用 prototype 来定义子类的域, 因为 prototype 的定义在子 类 new 的之后就执行, 所以它一定会在调用父类构造函数前, 同样会有被父类的 定义覆盖的危险. 2. 利用 prototype:
117、function 的用法
在 JavaScript 中, function 是一种数据类型, 所有的 function 都是从 buildin 的 Function object 衍生的对象. 所以在 JavaScript 中 function 可以作为参数传递, 可以作为 Object 的 property, 也可以当作函数返回值. function 在 JavaScript 中有 两种用法, 一种是当作 constructor, 前面加上 new keyword 用来建立对象. 一种是 当作 method, 为其他对象调用. 注意 function 和 method 在中文里的意思相当, 在有些语言里也可以通用. 但是在 JavaScript 中, 它们还是有所区别的. function 本身是是一个对象, 而当作为一个 方法他属于一个对象时, 就成为了一个这个对象的 method, 相当于一个对象种 的属性. 也就是说 method 是相对于一个对象而言的, function 在某些情况下成为 了一个对象的 method. function Book(name, author, page) { = name; this.author = author; this.page = page;
JavaScript 中的 Object 是一组数据的 key-value 的集合, 有点类似于 Java 中的有 这些数据都是 Object 里的 property. 通常情况下, JavaScript 中建立一个对象用” new”加上 constructor function 来实现. 如 new Date(), new Object()等. var book = new Object(); = "JavaScript is Cool"; book.author = "tom"; book.pages = 514; 上面例子中的 name 和 page 就是名为 book 的对象中的 property. 我们可以用 delete 来删除 Object 中的 property: “delete ;”. 除了 Object, Date 等 buildin 的对象外, 我们可以写自己的 constructor function, 然后使用 new 就可以建立自 己的对象. 如上面的 book 可以写成:
this.bye = superBye; this.hello = superHello; }
function subClass() { this.base = new supperClass(); base.sayBye = subBye; return base;
} 这种继承其实是一种扩展, 因为在调用 instanceOf 时, 子类会返回父类名称, 它 的好处在于在构造函数继承的基础上解放了父类, 父类可以使用 prototype 定义 自己的域, 但是子类仍然不建议使用 prototype, 以免被父类覆盖. 为了可以使子 类的 instanceof 返回正确类型, 我们可以再改进一下: function subClass() {
this.getReader = Book_getReader; } function Book_getReader() { //.... } 上面的例子种, function Book_getReader()就成为了 Book 的一个名为 getReader 的 method. call() 和 apply() 是 Function object 的 两 个 方 法 , 它 们 也 可 以 使 一 个 function 作为另一个对象的 method 来调用用. call()和 apply()都需要参数, 而第一 个参数就是调用对象, 也就是当 function 内部出现 this 时, this 所指的对象. call() 和 apply()的区别在于 call()可以传递任意长度参数, 只要第一个参数时调用对象. 而 apply 只接受两个参数, 需要将除调用对象外的所有参数放入一个数组中. 即: function getBooksWithSameAuthor(form, to) { var name = this.author; var books = ... //get books written by name and from year "from" to year "to" return books; }
var f=this;
return function() { f();g();
} }; function Manager() {
this.callback=function () {}; // do nothing this.registerCallback=function(callbackFunction) {
Book.prototype.getInfo = getInfo; function getInfo() { return + " written by " + this.author + " with " + this.page + " pages"; } alert(abook.getInfo()); 这里有一个例子, 用 prototype 方法来实现 callback: Function.prototype.andThen=function(g) {
function superClass() { this.bye = superBye; this.hello = superHello;
}
function subClass() { this.bye = subBye;
} subClass.prototype = new superClass(); subClass.prototype.constructor = superClass; 这 里 将 一 个 superClass 的 实 例 设 置 成 subclass 的 原 型 :protytype, 由 于 new superClass 实例一定会调用父类 prototype 定义的所有域, 所以这种方法避免了 上 一 种 方 法 的 一 个 问 题 , 父 类 可 以 通 过 prototype 来 描 述 域 . 可 以 实 现 从 superClass 的继承. 而这个方法也有缺点, 由于子类的 peototype 已经是父类的实 例(Object 实例), 不能再被实例化, 所以 new 子类实例的时候, 父类的所有非基 本数据类型(见 JavaScript 数据类型)都将是 reference copy 而非数据 copy. 简单说 就是所有的父类域在子类中虽然存在, 但看起来就像 Java 中的 static 域一样在子 类间 share.被一个子类改变, 所有子类都会改变. 注意这里的最后一句, 改变了子类 prototype 中的 constructor 属性. 它对子类使用 没有影响, 仅仅是为了在调用 instanceOf 方法时它使得子类实例返回 subClass. 3. Parasitic Inheritance (寄生继承) function superClass() {