JavaScript设计模式(1)

面向对象的 JavaScript

JavaScript 没有提供传统面向对象语言中的类式继承,而是通过原型委托的方式来实现对象与对象之间的继承。 JavaScript 也没有在语言层面提供对抽象类和接口的支持。正因为存在这些跟传统面向对象语言不一致的地方,我们在用设计模式编写代码的时候,更要跟传统面向对象语言加以区别。

动态类型语言和鸭子类型

编程语言按照数据类型大体可以分为两类,一类是静态类型语言,另一类是动态类型语言。静态类型语言在编译时便已确定变量的类型,而动态类型语言的变量类型要到程序运行的时候,待变量被赋予某个值之后,才会具有某种类型。

在 JavaScript 中,当我们对一个变量赋值时,显然不需要考虑它的类型,因此, JavaScript是一门典型的动态类型语言。动态类型语言对变量类型的宽容给实际编码带来了很大的灵活性。由于无需进行类型检测,我们可以尝试调用任何对象的任意方法,而无需去考虑它原本是否被设计为拥有该方法。
这一切都建立在鸭子类型(duck typing)的概念上,鸭子类型的通俗说法是:“ 如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。 ”

多态

多态的实际含义是:同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果。换句话说,给不同的对象发送同一个消息的时候,这些对象会根据这个消息分别给出不同的反馈。

封装

封装的目的是将信息隐藏。一般而言,我们讨论的封装是封装数据和封装实现。这一节将讨论更广义的封装,不仅包括封装数据和封装实现,还包括封装类型和封装变化。

原型模式和基于原型继承的 JavaScript 对象系统

在 Brendan Eich 为 JavaScript 设计面向对象系统时,借鉴了 Self 和 Smalltalk 这两门基于原型的语言。之所以选择基于原型的面向对象系统,并不是因为时间匆忙,它设计起来相对简单,而是因为从一开始 Brendan Eich 就没有打算在 JavaScript 中加入类的概念。

使用克隆的原型模式

从设计模式的角度讲,原型模式是用于创建对象的一种模式,如果我们想要创建一个对象,一种方法是先指定它的类型,然后通过类来创建这个对象。原型模式选择了另外一种方式,我们不再关心对象的具体类型,而是找到一个对象,然后通过克隆来创建一个一模一样的对象。
在不支持 Object.create 方法的浏览器中,则可以使用以下代码:

1
2
3
4
5
Object.create = Object.create || function( obj ){
var F = function(){};
F.prototype = obj;
return new F();
}

原型编程范型的一些规则

现在我们明白了原型编程中的一个重要特性,即当对象无法响应某个请求时,会把该请求委托给它自己的原型。

  • 所有的数据都是对象。
  • 要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并克隆它。
  • 对象会记住它的原型.
  • 如果对象无法响应某个请求,它会把这个请求委托给它自己的原型。

JavaScript中的原型继承

  1. 所有的数据都是对象。JavaScript 在设计的时候,模仿 Java 引入了两套类型机制:基本类型和对象类型。基本类型包括 undefined、 number、 boolean、 string、 function、 object。从现在看来,这并不是一个好的想法。按照 JavaScript 设计者的本意,除了 undefined 之外,一切都应是对象。为了实现这一目标,number、 boolean、 string 这几种基本类型数据也可以通过“包装类”的方式变成对象类型数据来处理。事实上, JavaScript 中的根对象是 Object.prototype 对象。 Object.prototype 对象是一个空的对象。我们在 JavaScript 遇到的每个对象,实际上都是从 Object.prototype 对象克隆而来的,Object.prototype 对象就是它们的原型。
  2. 要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并克隆它。
  3. 对象会记住它的原型JavaScript 给对象提供了一个名为__proto__的隐藏属性,某个对象的__proto__属性默认会指向它的构造器的原型对象,即{Constructor}.prototype。在一些浏览器中, __proto__被公开出来。
  4. 如果对象无法响应某个请求,它会把这个请求委托给它的构造器的原型。 首先,尝试遍历对象 a 中的所有属性,但没有找到 name 这个属性。查找 name 属性的这个请求被委托给对象 a 的构造器的原型,它被 a.__proto__ 记录着并且指向 A.prototype,而 A.prototype 被设置为对象 obj。在对象 obj 中找到了 name 属性,并返回它的值。
坚持原创技术分享,您的支持将鼓励我继续创作!