JavaScript: The Good Parts 读书笔记(三)
三.继承
概述??? 伪类模式的本意是模拟OO语言中的继承,向面向对象靠拢,但它看起来显得格格不入。下面可以通过一些辅助方法来隐藏一些丑陋的细节.?
?? 虽然通过隐藏一些繁琐的针对prototype的操作细节,使用伪类继承看起来没那么怪异了.但我们是否真的有所改善呢? 我们现在有了行为像 “类” 的构造器函数,但仔细去看,他们却存在令人惊讶的行为: 没有私有环境,所有属性都是公开的。无法访问父类的方法(super). 更糟糕的是,使用构造器函数存在一个严重的危害。如果你在调用构造器函数时忘了在前面加上new操作符,那么this将会被绑定到全局对象上,这样你既没有扩充新对象,反而破坏了全局变量。而且此时既没有编译时警告,也没有运行时警告。这是一个严重的语言设计错误。为了降低产生这个问题的风险,所有构造器函数都约定为使用首字母大写命名。
?? “伪类” 形式可以给不熟悉Javascript 的程序员提供便利,但它也已隐藏了该语言的真实本质。借鉴类的表示法可能误导程序员去编写过于深入与复杂的层次结构。而Javascript中却有更好的选择。
函数化模式
??? 在一个纯粹的原型模式中,我们会摒弃类,转而专注于对象。基于原型的继承相比基于类的继承在概念上更为简单:一个新对象可以继承一个旧对象的属性。通过构造一个有用的基础对象,接着可以构造更多和那个对象类似的对象。可以完全避免把一个应用拆解成一些列嵌套抽象类的分类过程。?这是一种 “差异化继承”. 通过定制该新对象,我们指明了它与其基类对象的区别.
隐私的保护
??? 迄今为止,我们所论述的继承模式都存在一个弱点:我们没法保护隐私. 对象的所有属性都是可见的。我们设置保护私有变量和私有函数。其中一个解决方法是使用模块模式。下面是一个使用模块模式的伪代码模板:?? ?函数化模式还给我们提供了一个处理父类方法的机会. 我们将构造一个 superior 方法,它取得一个方法名并返回调用哪个方法的函数.该函数将调用原来的方法。(装饰/代理模式)? ? 函数化模式有很大的灵活性。它不仅不像伪类模式那样需要花费很多功夫,还让我们得到更好的封装和信息隐藏,以及访问父类方法的能力。我们可以从一套部件中组合出对象。例如,我们可以构造一个能添加简单事件处理特性到任何对象上的函数.他会给对象添加一个on方法,一个fire方法和一个私有的事件注册表对象。var eventuality = function(that){var registry = {};that.fire = function(event){// 触发通过 'on' 方法注册的事件处理程序。该事件可以是一个包含事件名称的字符串,// 或是一个拥有type属性的对象.var array,func,handler,i,type = typeof event === 'string' ? event : event.type;if(registry.hasOwnProperty(type)){array = registry[type];for(i = 0 ; i < array.length ; i++){handler = array[i];func = handler.method;// 每个处理程序包含一个方法和一组可选的参数.// 如果该方法是一个字符串形式的名字,那么就查找该函数.if(typeof func === 'string'){func = this[func];}// 调用处理程序。如果该条目包含参数,那么传递它们过去.否则,传递该事件对象。func.apply(this, handler.parameters || [event]);}}return this;};// 注册一个事件that.on = function(type, method ,parameters){var handler = {method : method,parameters : parameters};if(registry.hasOwnProperty(type)){registry[type].push(handler);}else{registry[type] = [handler];}return this;};return that;};?? ?用这种方式,一个构造器函数可以从一套部件(函数)中组装出对象。Javascript的弱类型在 此处是一个巨大的优势,因为我们无须花费精力去关注整个类型系统。相反,我们可以专注于它们的个性化内容。