第一章 Javascript-表现力

       JavaScript is one of themost popular and widely used languages in the world today. Because
it is embedded in all modern browsers, it has an extraordinarily wide distribution. As a lan-
guage, it is incredibly important in our daily lives, powering the websites that we go to and
helping the Web to present a rich interface.

 

  今天,Javascript是世界上非常流行,得到广泛使用的语言。因为它可以嵌入到当今所有的浏览器上,特别广泛地分布在世界各地。难以置信,作为一种语言,它在我们的日常生活中竟如此地重要,我们使用它来构建非常丰富多姿的界面。

  

     Why then do some still consider it to be a toy language, not worthy of the professional
programmer? We think it is because people do not realize the full power of the language and
how unique it is in the programming world today. JavaScript is a very expressive language,
with some features that are uncommon to the C family of languages.

 

为什么有些人仍然认为Javascript是一种用来玩玩而已的的语言,不值得专业程序员使用。我想,这是因为他们不够全面了解这门语言的功能,以及在当今世界,它是如何的独特。Javascript是一门非常有表现力的语言,并不同于C语言系列。

 

     In this chapter we explore some of the features that make JavaScript so expressive. We
look at how the language allows you to accomplish the same task in a number of different
ways and how you can take alternative approaches to object-oriented programming by using
concepts from functional programming. We discuss why you should use design patterns in the
first place and how adapting them to JavaScript will make your code more efficient and easier
to work with.

 

这一章,我们将探索是什么特性使得Javascript如此地富有表现力。我们将看到这门语言如何允许你用几种不同的方式实现你的任务,使用函数型设计来实现面向对象编程。我们会讨论为什么你应该首先使用设计模式,并把它们Javascript上,使得你的Js代码更高效,更简洁,便于使用。

 

The Flexibility of JavaScript

灵活的JavaScript


One of the most powerful features of the language is its flexibility. As a JavaScript programmer,
you can make your programs as simple or as complex as you wish them to be. The language
also allows several different programming styles. You can write your code in the functional style
or in the slightly more complex object-oriented style. It also lets you write relatively complex
programs without knowing anything at all about functional or object-oriented programming;
you can be productive in this language just by writing simple functions. This may be one of the
reasons that some people see JavaScript as a toy, but we see it as a good thing. It allows programmers
to accomplish useful tasks with a very small, easy-to-learn subset of the language. It also
means that JavaScript scales up as you become a more advanced programmer.

 

这门语言的众多强大的特征之一就是它的灵活性。作为一名JavaScript程序员,你可以使得你的程序很简单,或者很复杂。这门语言还允许你有许多不同的编程风格。你可以使用函数风格或者更加复杂的面向对象风格来编写你的代码。即使你对函数和面向对象一无所知,使用它也能你写一些相对复杂的程序。仅仅通过使用JavaScript写一些简单的函数,你就可以制造一些效果。这点也许就是有些人把JavaScript当作一种玩具的原因之一,而我们却视其为优点。它允许程序员使用很小的,容易学的JavaScript的子集去完成一些非常有用的工作。这也意味着如果你是一名高级程序员,那JavaScript就很重要了。

 

JavaScript allows you to emulate patterns and idioms found in other languages. It even
creates a few of its own. It provides all the same object-oriented features as the more traditional
server-side languages.

 

JavaScript允许你效仿其它语言中模式或一些惯用方法,甚至有一些是它独创的。它提供了面向对象所有相同的特征,作为较为传统的的服务器端的语言。

 

Let’s take a quick look at a few different ways you can organize code to accomplish one
task: starting and stopping an animation. It’s OK if you don’t understand these examples; all of
the patterns and techniques we use here are explained throughout the book. For now, you can
view this section as a practical example of the different ways a task can be accomplished in
JavaScript.

 

让我们立刻去看一下,通过不同的方式,你可以组织你的代码去实现一个任务:开始和结束一个动画。如果你不理解这个例子也没关系;我们在这里使用的所有的模式和技术贯穿全书。现在,你能把这一段看作使用JavaScript,用不同方式去实现一个任务的真实的实例。

 

If you’re coming from a procedural background, you might just do the following:

如果你有程序设计经验,也许你像下面这样做:


/* Start and stop animations using functions. */

使用函数来启动和关闭动画


function startAnimation() {
...
}
function stopAnimation() {
...
}
This approach is very simple, but it doesn’t allow you to create animation objects, which
can store state and have methods that act only on this internal state. This next piece of code
defines a class that lets you create such objects:

 

这个方法非常简单,但是它不允许你去创建能存储状态和拥有只能操作内部状的方法态的动画对象。这是另一段代码,定义了能让你实现这样的对象。


/* Anim class. */
var Anim = function() {
...
};
Anim.prototype.start = function() {
...
};
Anim.prototype.stop = function() {
...
};
/* Usage. */
var myAnim = new Anim();
myAnim.start();
...
myAnim.stop();


This defines a new class called Anim and assigns two methods to the class’s prototype
property. We cover this technique in detail in Chapter 3. If you prefer to create classes encapsulated
in one declaration, you might instead write the following:

这定义了一个新的名为Anim的类,有属于它的原型属性的两个方法。我们将会在第三章讲到这种技术。如果你喜欢创建封装在一个声明里的类,你可能反而像下面这样写:
/* Anim class, with a slightly different syntax for declaring methods. */
var Anim = function() {
...
};
Anim.prototype = {
start: function() {
...
},

stop: function() {
...
}
};
This may look a little more familiar to classical object-oriented programmers who are used
to seeing a class declaration with the method declarations nested within it. If you’ve used this
style before, you might want to give this next example a try. Again, don’t worry if there are parts
of the code you don’t understand:

这看起来像比较熟悉的经典的面向对象程序设计,经常看到的嵌套这方法声明的类声明。如果你以前使用过这种方式,你也许要尝试一下下面给出的例子。再次提示你,别当心代码中有些你不能理解。
/* 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 allows you to add new methods to classes. It takes two arguments.
The first is a string to use as the name of the new method, and the second is a function
that will be added under that name.
You can take this a step further by modifying Function.prototype.method to allow it to be
chained. To do this, you simply return this after creating each method. We devote Chapter 6
to chaining:

 

Function.prototype.method 允许你为类加上一个新的方法。它带有两个参数。第一个是字符类型,用来作为方法名,第二个是函数,赋给方法名。你能进一步修改允许它被关联起来。这样,你简单地创建了各个方法后返回。第六章专门讲关联。
/* 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() {
...
});
You have just seen five different ways to accomplish the same task, each using a slightly
different style. Depending on your background, you may find one more appealing than another.
This is fine; JavaScript allows you to work in the style that is most appropriate for the project at
hand. Each style has different characteristics with respect to code size, efficiency, and performance.
We cover all of these styles in Part 1 of this book.

 

你刚刚看过五种不同方式去实现相同的任务,每一种使用稍有不同。相信以你的背景,你会发现一种比一种更吸引人。这很好;JavaScript允许你使用最适当的方式去为你手头上的工程工作。每一种方式在代码尺寸、效率、执行上有不同的特征。我们将在本书的第一部分讲解这些方式。

 

A Loosely Typed Language

一种弱型语言

 

In JavaScript, you do not declare a type when defining a variable. However, this does not mean
that variables are not typed. Depending on what data it contains, a variable can have one of
several types. There are three primitive types: booleans, numbers, and strings (JavaScript differs
from most other mainstream languages in that it treats integers and floats as the same type).
There are functions, which contain executable code. There are objects, which are composite
datatypes (an array is a specialized object, which contains an ordered collection of values).
Lastly, there are the null and undefined datatypes. Primitive datatypes are passed by value,
while all other datatypes are passed by reference. This can cause some unexpected side effects
if you aren’t aware of it.

在JavaScript里,当你定义一个变量时,不用声明它的类型。然而,这并不意味着一个变量没有类型。根据含有什么数据,一个变量为几种类型中的一种。有三种花基本类型:布尔型,数值型,字符型(JavaScript与其它主流的的语言不同,整数和浮点数是相同的类型)。函数,包含着执行代码。还有对象,混合数据类型(数组是一种专门的对象,包含一个有序的值的集合)。最后是,null和defined类型。基本数据类型是值传递,其它的传递引用。如果你不了解这一点,可能会产生一些意外的副作用。
As in other loosely typed languages, a variable can change its type, depending on what
value is assigned to it. The primitive datatypes can also be cast from one type to another. The
toString method converts a number or boolean to a string. The parseFloat and parseInt functions
convert strings to numbers. Double negation casts a string or a number to a boolean:

如同其它弱型语言,一个变量能改变它的类型,根据赋给它怎样的值。基本类型也能从另外一种类型转换过而来。toString方法把一个数字变成一个字符串。parseFloat和parseInt函数把字符串变成数字。双重否定将字符串或者数字类型转换布尔类型。

 

var bool = !!num;


Loosely typed variables provide a great deal of flexibility. Because JavaScript converts type
as needed, for the most part, you won’t have to worry about type errors.

松散类型变量提供一个很棒的灵活的处理。因为JavaScript如果需要转变,大部分,你不需要担心会出错。

 

Functions As First-Class Objects
In JavaScript, functions are first-class objects. They can be stored in variables, passed into other
functions as arguments, passed out of functions as return values, and constructed at run-time.
These features provide a great deal of flexibility and expressiveness when dealing with functions.
As you will see throughout the book, these features are the foundation around which you will
build a classically object-oriented framework.
You can create anonymous functions, which are functions created using the function()
{ ... } syntax. They are not given names, but they can be assigned to variables. Here is an
example of an anonymous function:

 

函数作为第一类型对象

在JavaScript里,韩式是第一类对象。它们能存储在变量里,输入其它函数作为参数,输出函数作为返回值,在运行时构建它。

在处理函数时,这些特征提供一个非常灵活和有表现力的处理。当你看完整本书,这些特征是构建一个经典的面向对象框架的基础。

你能使用function(){}语法创建匿名函数。它们没有名字,但是它们能被赋给一个变量。这是一个匿名函数的例子。

/* An anonymous function, executed immediately. */
(function() {
var foo = 10;
var bar = 2;
alert(foo * bar);
})();
This function is defined and executed without ever being assigned to a variable. The pair
of parentheses at the end of the declaration execute the function immediately. They are empty
here, but that doesn’t have to be the case:
/* An anonymous function with arguments. */
(function(foo, bar) {
alert(foo * bar);
})(10, 2);


This anonymous function is equivalent to the first one. Instead of using var to declare the
inner variables, you can pass them in as arguments. You can also return a value from this function.
This value can be assigned to a variable:

这个匿名函数等于第一个。通过使用一个内部变量赋值给一个变量。


/* An anonymous function that returns a value. */
var baz = (function(foo, bar) {
return foo * bar;
})(10, 2);
// baz will equal 20.


The most interesting use of the anonymous function is to create a closure. A closure is
a protected variable space, created by using nested functions. JavaScript has function-level scope.
This means that a variable defined within a function is not accessible outside of it. JavaScript is
also lexically scoped, which means that functions run in the scope they are defined in, not the
scope they are executed in. These two facts can be combined to allow you to protect variables by
wrapping them in an anonymous function. You can use this to create private variables for classes:

最有趣的用法是创建一个封闭的匿名函数。一个封闭域由嵌套函数创建,是受保护的空间。JavaScript有函数级范围。这意味着在函数里定义一个变量,外面不能访问。JavaScript也有词汇范围,这意味着函数运行在定义它们的范围内,而不是执行它们的范围内。这两个事实联合起来,允许你通过把变量包装在匿名函数里来保护它们。你能使用这种方法去创建累的私有变量。
/* An anonymous function used as a closure. */
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.
The variables foo and bar are defined only within the anonymous function. Because the
function baz was defined within that closure, it will have access to those two variables, even
after the closure has finished executing. This is a complex topic, and one that we touch upon
throughout the book. We explain this technique in much greater detail in Chapter 3, when we
discuss encapsulation.

变量foo和bar只在匿名函数里定义。因为函数baz定义在一个闭包里,它可以访问其它两个变量,甚至在闭包之后可以执行。这是一个复杂的话题,我们在全书中会涉及到它。我们在第三章讨论封装时会非常详细的解释这种技术。

 

The Mutability of Objects
In JavaScript, everything is an object (except for the three primitive datatypes, and even they
are automatically wrapped with objects when needed). Furthermore, all objects are mutable.
These two facts mean you can use some techniques that wouldn’t be allowed in most other
languages, such as giving attributes to functions:

JavaScript中的对象是易变的,一切皆对象(除了三种基本数据类型,甚至当它们需要时,也自动包装为对象)。此外,所有的对象是易变的。这两个事实意味着你能使用一些部分语言不允许使用的技术,比如将一个属性设置为一个函数。
function displayError(message) {
displayError.numTimesExecuted++;
alert(message);
};
displayError.numTimesExecuted = 0;
It also means you can modify classes after they have been defined and objects after they
have been instantiated:
/* Class Person. */
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
getName: function() {
return this.name;
},
getAge: function() {
return this.age;
}
}
/* Instantiate the class. */
var alice = new Person('Alice', 93);
var bill = new Person('Bill', 30);
/* Modify the class. */

Person.prototype.getGreeting = function() {
return 'Hi ' + this.getName() + '!';
};
/* Modify a specific instance. */
alice.displayGreeting = function() {
alert(this.getGreeting());
}
In this example, the getGreeting method is added to the class after the two instances are
created, but these two instances still get the method, due to the way the prototype object works.
alice also gets the displayGreeting method, but no other instance does.

 

在这个例子,getGreeting方法在创建了两个实例后赋给类,但是这两个类仍能获取这个方法,是因为使用了原型这种方式。

alice也能获得dispalyGreeting方法,但是其它实例就不行。
Related to object mutability is the concept of introspection. You can examine any object at
run-time to see what attributes and methods it contains. You can also use this information to
instantiate classes and execute methods dynamically, without knowing their names at development
time (this is known as reflection). These are important techniques for dynamic scripting
and are features that static languages (such as C++) lack.

与对象易变性相关联的是自我检测(内省)的概念。你能在运行时检测任何对象,看看它包含什么属性和方法。你也能使用这个信息去动态实例化或执行方法,而不需要再开发时就知道它们的名字(这就是所谓的反射)。这对于动态脚本来说是非常重要的技术,也是静态语言(如C++)所欠缺的特征。
Most of the techniques that we use in this book to emulate traditional object-oriented
features rely on object mutability and reflection. It may be strange to see this if you are used to
languages like C++ or Java, where an object can’t be extended once it is instantiated and classes
can’t be modified after they are declared. In JavaScript, everything can be modified at run-time.
This is an enormously powerful tool and allows you to do things that are not possible in those
other languages. It does have a downside, though. It isn’t possible to define a class with a particular
set of methods and be sure that those methods are still intact later on. This is part of
the reason why type checking is done so rarely in JavaScript. We cover this in Chapter 2 when
we talk about duck typing and interface checking.

我们在本书使用的大多数技术效法传统的依赖对象易变性和反射的面向对象的特征。如果你用惯了C++或者Java:对象实例化了就不能扩展,类声明后就不能修改。在JavaScript,一切都能在运行时修改。这是一种非常强大的工具,允许你去做一些在其它语言里不能做的事情。尽管这有不利的一面。它不能定义一个类拥有一组特定的方法并且必须保证这些方法在以后不被改变(原封不动)。这就是为什么很少在JavaScript里做类型检测的一部分原因。我们将在第二章讨论鸭子类型和接口检测是覆盖这方面。
Inheritance
Inheritance is not as straightforward in JavaScript as in other object-oriented languages. JavaScript
uses object-based (prototypal) inheritance; this can be used to emulate class-based (classical)
inheritance. You can use either style in your code, and we cover both styles in this book. Often
one of the two will better suit the particular task at hand. Each style also has different performance
characteristics, which can be an important factor in deciding which to use. This is a complex
topic, and we devote Chapter 4 to it.
Design Patterns in JavaScript
In 1995, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides published a book titled
Design Patterns. This book catalogs the different ways objects can interact with each other and
it created a common vocabulary around the different types of objects. The blueprints for creating
these different types of objects are called design patterns. The book describes these patterns
in a somewhat language-agnostic way, so that they can be used anywhere. The book you are
holding in your hands takes those patterns and applies them specifically to JavaScript.
CHAPTER 1 ■ EXPRESSIVE JAVASCRIPT 9
The fact that JavaScript is so expressive allows you to be very creative in how design patterns
are applied to your code. There are three main reasons why you would want to use design
patterns in JavaScript:
1. Maintainability: Design patterns help to keep your modules more loosely coupled. This
makes it easier to refactor your code and swap out different modules. It also makes it
easier to work in large teams and to collaborate with other programmers.
2. Communication: Design patterns provide a common vocabulary for dealing with
different types of objects. They give programmers shorthand for describing how their
systems work. Instead of long explanations, you can just say, “It uses the factory pattern.”
The fact that a particular pattern has a name means you can discuss it at a high
level, without having to get into the details.
3. Performance: Some of the patterns we cover in this book are optimization patterns.
They can drastically improve the speed at which your program runs and reduce the
amount of code you need to transmit to the client. The flyweight (Chapter 13) and
proxy (Chapter 14) patterns are the most important examples of this.
There are two reasons why you might not want to use design patterns:
1. Complexity: Maintainability often comes at a cost, and that cost is that your code may
be more complex and less likely to be understood by novice programmers.
2. Performance: While some patterns improve performance, most of them add a slight
performance overhead to your code. Depending on the specific demands of your project,
this overhead may range from unnoticeable to completely unacceptable.
Implementing patterns is the easy part; knowing which one to use (and when) is the hard
part. Applying design patterns to your code without knowing the specific reasons for doing so
can be dangerous. Make an effort to ensure that the pattern you select is the most appropriate
and won’t degrade performance below acceptable limits.
Summary
The expressiveness of JavaScript provides an enormous amount of power. Even though the
language lacks certain useful built-in features, its flexibility allows you to add them yourself.
You can write code to accomplish a task in many different ways, depending on your background
and personal preferences.
JavaScript is loosely typed; programmers do not declare a type when defining a variable.
Functions are first-class objects and can be created dynamically, which allows you to create
closures. All objects and classes are mutable and can be modified at run-time. There are two
styles of inheritance you can use, prototypal and classical, and each has its own strengths and
weaknesses.
Design patterns in JavaScript can be extremely helpful and beneficial, but they can also
be detrimental if used improperly. In a language as lightweight as JavaScript, overly complex
architectures can quickly bog down your application. Always make sure the style of programming
you use and the patterns you select are right for the job.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值