本章将探讨一些令JavaScript如此富有表现力的特性。从中你可以体会到,这种语言允许你用各种方式完成同样的任务,还允许你在面向对象编程的过程中借用函数式编程中的概念来丰富其实现方式。
本章揭示了究竟为什么应该使用设计模式,以及它们在JavaScript程序设计的运用是如何使代码更高效、更易于处理的。
1.1 JavaScript的灵活性
JavaScript最强大的特性是其灵活性。
作为JavaScript程序员,只要你愿意,可以把程序写得很简单,也可以写得很复杂。这种语言也支持多种不同的编程风格。你既可以采用函数式编程风格,也可以采用更复杂一点的面向对象的编程风格。使用这种语言,哪怕只采用编写一个个简单的函数的方式,你也能高效的完成任务。
先来看一个用不同方法完成同样任务的例子:启动和停止一个动画。
方法一,用function
function startAnimation() {
...
}
function stopAnimation() {
...
}
缺点: 无法创建可以保存状态并且具有一些仅对其内部状态进行操作的方法的动画对象。
方法二,用定义类的方法解决方法一中的缺点
/* Anim class . */
var Anim = function() {
...
};
Anim.prototype.start = function() {
...
};
Anim.prototype.stop = function() {
...
};
/* Usage. */
var myAnim = new Anim();
myAnim.start();
...
myAnim.stop();
方法三,把类的定义封装在一条声明中
/* Anim class . */
var Anim = function() {
...
};
Anim.prototype = {
start: function () {
...
},
stop: function () {
...
}
};
/* Usage. */
var myAnim = new Anim();
myAnim.start();
...
myAnim.stop();
方法四,定义方法 method(新方法名称, 用作新方法的函数) 为类添加新方法。
Function.prototype.method = function(name, fn) {
this.prototype[name] = fn;
};
/* Anim class.*/
var Anim = function() {
...
};
Anim.method('start', function(){
...
});
Anim.method('stop', function(){
...
});
方法五,修改method,使其可被链式调用
Function.prototype.method = function(name, fn) {
this.prototype[name] = fn;
return this;
};
/* Anim class.*/
var Anim = function () {
...
};
Anim.
method('start', function () {
...
}).
method('stop', function () {
...
});
你已经见识了完成同一项任务的5种不同方法,它们的风格略有差异。JavaScript允许你用最适合于手头项目的编程风格进行工作。不同的风格在代码篇幅、编码效率和执行性能方面各有特点。
1.2 弱类型语言
在JavaScript中,定义变量不必声明其类型。但这并不意味着变量没有类型。变量的类型取决于其包含的数据。
JavaScript有五种基本数据类型:布尔型、数值型、字符串型、空类型、未定义类型。
不区分整数和浮点数是JavaScript与大多数其他主流语言的不同之处。
原始数据类型按值传递,其他数据类型则按引用传递。
JavaScript中的变量可以根据所赋的值改变类型,原始数据类型之间也可以进行类型转换,例如:
- toSring:把数值或布尔值转变为字符串
- parseFloat、parseInt:把字符串转变为数值
- 双重“非”操作把字符串或数值转变成布尔值
弱类型的变量带来了极大的灵活性。因为JavaScript会根据需要进行类型转换,所以一般来说,你不用为类型操心。
1.3 函数是一等对象
在JavaScript中,函数是一等对象。
-
可以存储在变量中
var foo = function() { console.log("Hello World!"); }; foo();
-
可以作为参数传给其他函数
var sayHello = function() { return "Hello, "; } var greeting = function(helloMessage, name) { console.log(helloMessage() + name); }; greeting(sayHello, "Suki"); // "Hello, Suki
这个特性在js中运用相当广泛,相信对数组操作熟悉的伙伴,数组的sort方法可接受一个函数作为排序准则,map方法也可接受一个函数操作数组的每一项。
-
可以作为返回值从其他函数中传出
通常结合匿名,用以创建闭包。function fun(){ var p = "fun"; return function(){ console.log(p); } } var f = fun(); f(); // fun
/*将变量包裹在匿名函数中加以保护*/ var f; (function() { var p = "fun"; f = function (){ console.log(p); } }); f(); // fun
-
可以在运行时进行构造
1.4 对象的易变性
在JavaScript中,除了基本数据类型,一切都是对象,而且所有对象都是易变的。
易变性表现在:
-
为函数添加属性
function count () { count.num++; console.log(count.num); } count.num = 1; count(); //2 count.num;// 2
-
为类和实例化的对象进行修改
/*定义Person类*/ function Person(name, age) { this.name = name; this.age = age; } Person.prototype={ getName: function(){ return this.name; }, getAge: function() { return this.age; } } /* 实例化对象 */ var alice = new Person(); var bill = new Person(); /* 修改类 (两个实例都可以获得这个方法)*/ Person.prototype.getGreeting = function() { return 'Hi ' + this.getName() + '!'; }; /* 修改实例化的对象 (只有alice实例拥有这个方法)*/ alice.displayGreeting = function() { this.getGreeting(); }
1.5 继承
JavaScript使用的是基于对象的(prototype)继承,它可以用来模仿基于类的(class)继承。
这两种范型本书都会讲述,编写代码时用哪一种都可以,根据手头任务的实际情况,又是其中的某种会更适合一些,它们在性能上也有不同的表现,这也是在进行选择时需要考虑的重要因素。这个将在第4章中进行探讨。
1.6 JavaScript中的设计模式
JavaScript强大的表现力赋予了程序员在运用设计模式编写代码时极大的创造性。
在JavaScript中使用设计模式主要有以下三个原因。
- 可维护性。 设计模式有助于降低模块间的耦合程度。这使对代码进行重构和换用不同的模块变得更容易,也使程序员在大型团队中的工作以及与其他程序员的合作变得更容易。
- 沟通。 设计模式为处理不同类型的对象提供了一套通用的术语。程序员因此可以更简明的描述自己的系统的工作方式。你不用进行冗长的说明,往往这样一句话就够了:“它使用了XX模式”。每个模式都有自己的名称,这意味着你可以在较高层面上对其进行讨论,而不必涉足过多的细节。
- 性能。 本书讲述的某些模式是起优化作用的模式。它们可以大幅提高程序的运行速度,并减少需要传送到客户端的代码量。这方面最重要的例子是享元模式(13章)和代理模式(14章)。
当然,设计模式也有一定的缺点。
- 复杂性。 获得可维护性往往要付出代价,那就是代码会变得更加复杂、更难被程序设计新手理解。
- 性能。 尽管某些模式能提升性能,但大多数模式对代码的性能都有所拖累。这种拖累可能微不足道,也可能完全不能接受,这取决于项目的具体需求。
实现设计模式比较容易,而懂得应该在时候使用什么模式则较为困难。未搞懂设计模式的用途就盲目套用,是一种不安全的做法。你应该尽量保证所选用的模式就是最恰当的那种,并且不要过度牺牲性能。
1.7 小结
JavaScript的丰富表现力是其力量之源。完成一项任务可以有多种方式,你可以根据自己的技术背景和喜好选择编写代码的方式。
JavaScript是弱类型语言。函数是一等对象,并且可以动态创建,因此你可以创建闭包。所有对象和类都是易变的,可以在运行时修改。可供使用的继承范型有两种,即原型式继承和类式继承,它们各有其优缺点。
JavaScript中的设计模式颇有助益,但其不当应用也会产生负面效果。在JavaScript这类轻灵的语言中,过度复杂的架构会很快把应用程序拖入泥沼。你使用的编程风格和选择的设计模式应该与所要完成的具体工作相称。