第一章 神奇的JavaScript
JavaScript是近年来一个非常流行并被广泛应用的语言。因为它被几乎所有的浏览器所支持,因此也得到了广泛的推广。作为一种语言,它在我们的生活变得难以相信的重要,帮助我们增强web的功能,创建丰富的用户界面。
为什么仍然有一些人认为它是一种“玩具式”的语言,认为它不适合于专业的程序员。我认为这是因为他们没有认识到它的真正的强大之处和它相比其它各种编程语言的独特性。JavaScript是一门非常神奇高深的语言,拥有一些C家族类语言所没有的特性。
本章我们将探讨是哪些特性使JavaScript如此的神奇高深。我们将看到JavaScript使你可以用多种不同的方式来完成同一件事情,以及如何通过函数式程序设计的方式来模拟实现面向对象程序设计。我们将讨论为什么你应该把设计模式放在首页以及如何使用它来使你的代码更有效,工作更简单。
灵活的JavaScript
JavaScript的一个很重要的特性就是其灵活性。作为JavaScript程序员,你可以使你的程序很简单或很复杂。JavaScript允许你使用各种不同的编程风格。你可以使用函数式风格或者接近于面向对象的编程风格来编写你的代码,同样你可以在不了解函数式或面向对象编程的情形下书写相对复杂的程序,你也可以通过写一些简单的函数来使用它。或者这些也是一些人把JavaScript看做“玩具”语言的一个原因,但我们应该认为这些是一些优秀的特性。它可以使程序员只掌握小部分易学的语言子集来完成一些有用的功能,同样它也意味着当你成为一个更加高级的程序员时JavaScript会在你手中发挥更大的能力。
JavaScript允许你去模拟其他语言中的模式和思想。此外它自身还包含一些独有的特性。它提供了和传统服务端语言完全一样的面向对象特性。
我们来看一下通过几个不同的代码组织方式来完成同样的一件任务:启动和停止一个动画。如果你不理解这些例子也无所谓,我们这里使用的所有模式和技术都会在本书中讲到。现在,你可以把这一节做为JavaScript可以通过不同的方式来完成同一件任务的一个实际的例子。
如果你以前是一个面向过程的程序员,你可以会像下面这样做:
/* Start and stop animations using functions. */
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的类并为该类的prototype属性增加了两个方法。我们在第三章将详细讨论这种技术。如果你喜欢创建一个只有一个声明的类,你可能会写出如下的代码:
/* Anim class, with a slightly different syntax for declaring methods. */
var Anim = function() {
};
Anim.prototype = {
start: function() {
},
stop: function() {
}
};
这看起来有点类似于经典的面向对象编程风格:将函数声明嵌套在一个类声明之内。如果你之前使用过这种风格,你可以试一下下面这个例子,如果不太理解下面的部分代码也不要担心:
/* Add a method to the Function object that can be used to declare methods. */
Function.prototype.method = function(name, fn) {
this.prototype[name] = fn;
};
/* Anim class, with methods created using a convenience method. */
var Anim = function() {
};
Anim.method('start', function() {
});
Anim.method('stop', function() {
});
Function.prototype.method使你可以为类增加新的方法。它可以接收两个参数:第一个是作为新方法的名字的字符串,第二个是为这个方法名指定的一个函数。
你可以通过对Function.prototype.method稍作修改以使其可以进行链式调用。为此,你只需要在创建完每个方法时返回一个this即可。我们在第6章将讨论链:
/* This version allows the calls to be chained. */
Function.prototype.method = function(name, fn) {
this.prototype[name] = fn;
return this;
};
/* Anim class, with methods created using a convenience method and chaining. */
var Anim = function() {
};
Anim.
method('start', function() {
}).
method('stop', function() {
});
你刚刚看到了我们使用五种略微不同的方式来完成了同样一件任务。根据你的编程背景,你可能觉得某种方式比其他一种更好。这其实很好,JavaScript允许你使用最适合你们手中项目的编程方式。每种方式拥有不同的特点和不同代码量,效率和性能。我们在本书的第一部分涵盖了所有的这些编程方式。
一种弱类型的语言 在JavaScript中,在定义变量时不需要定义类型,但是这并不意味着它没有变量类型。一个变量可以保存多种数据类型的数据,其类型取决所赋予给它的数据。JS有三种基本的数据类型:布尔型、数字型和字符串型(JavaScript不同于其他的编程语言,它将整型和浮点型作为同一种类型),此外,它含有可执行代码的function(函数)类型,还有包含复合类型的对象(Object)类型(Array是一种特殊的对象,它包含一些有序的数据集合)。现在,它还有null和undefiend数据类型。基本数据类型按值传递,其它的数据类型是按照引用传递,因此如果你不小心就可能导致一些意外的问题。
和其它弱类型语言一样,变量会根据被赋予的值改变其数据类型。基本数据类型之间可以互相转换,toString方法可以将一个数字或布尔型数据转换为一个字符串。parseFloat和floatInt函数可以将字符串转换为数字型,双否定号可以将一个字符串或数字数据转换成布尔类型。
var bool = !!num;
弱类型的变量提供了很多了灵活性,你不需要担心数据类型错误,因为在需要的时候JavaScript会自动做转换。
函数是第一型对象 在JavaScript语言中,函数是第一性的对象。它可以被存储在一个变量中,作为参数传入到函数中,被函数作为返回值返回,或者在运行的时间动态构造。这些特性使你在使用函数增加了很大的灵活性和表现能力。在本书后面的部分你会看到,这些特性是你构建一个传统的面向对象框架的基础。
你可以使用functiuon(){…}方法创建一个匿名的函数。它没有函数名但可以被赋给一个变量。下面是一个匿名函数的例子:
/* An anonymous function, executed immediately. */
(function() {
var foo = 10;
var bar = 2;
alert(foo * bar);
})();
这个函数在定义和执行时没有赋给任何变量。最后的一对括号会使该函数立即执行。但并一定只能这样写:
/* An anonymous function with arguments. */
(function(foo, bar) {
alert(foo * bar);
})(10, 2);
这个匿名函数和第一个基本相同,但这个函数没有使用var在内部定义变量,而是作为参数传入了函数,这个函数可以有一个返回值并可以被赋予给一个变量。
/* An anonymous function that returns avalue. */
var baz = (function(foo, bar) {
return foo * bar;
})(10, 2);
// baz will equal 20.
匿名函数的一个最有趣的功能就是创建闭包。闭包就是通过使用嵌套函数,创建一个保护变量空间。JavaScript有函数级的作用域,也就是说在函数中定义的变量不能被外部访问。它还有语法上作用域,也就是函数运行在他们定义的作用域而不是他们执行时的作用域。这两者相结合使你可以通过匿名函数创建一个保护变量。你可以使用这点为类创建私有变量。
/* An anonymous function used as aclosure. */
var baz;
(function() {
var foo = 10;
var bar = 2;
baz = function() {
return foo * bar;
};
})();
baz(); // baz can access foo and bar, even though it is executed outside of the
// anonymous function.
变量foo和bar只在匿名函数中定义,因为baz函数也定义在这个闭包中,因此它可以访问这两个变量,甚至在闭包函数执行结束之后。这是我们整本书都会一直接触的一个复杂逻辑。我们在第三章讨论封装的时候将详细讲解这种技术。
阅读(190) | 评论(0) | 转发(0) |