函数是应用程序的基础外文翻译资料
2022-07-27 10:53:32
书名:Programming JavaScript Applications 作者:Eric Eliott
出版商:Orsquo;Reilly Media 出版年:2014 页数:254 ISBN:987-1-49195-029-6
Chapter 2.Fuctions
Functions are the building blocks of applications. They are particularly important in JavaScript because JavaScript supports first-class functions, functions as objects, runtime function definition, and so on. JavaScript#39;s features allow you to use functions in ways that you may not be familiar with. It#39;s important to have a thorough understanding of how functions work in JavaScript so you can leverage them to full advantage in your applications. By the end of this chapter, you should see functions in a whole new light.
Here are some guidelines that will help you write better functions:
Don#39;t Repeat Yourself (DRY)
Good programmers are both lazy and very productive. They express a lot of functionality in very little code. Once you have established a pattern for something that gets repeated again in the code, it#39;s time to write a function, object, or module that encapsulates that pattern so that it can be easily reused.
Doing so also quarantines that functionality to a single spot in the code base, so that if you later find something wrong with the code or the algorithm, you only have to fix it in one place.
Writing a reusable function also forces you to isolate the pattern from the problem, which helps you keep related functionality grouped together.
Do One Thing (DOT)
Each function should do only one thing, and do that one thing as well as it can. Following this principle will make your function more reusable, more readable, and easier to debug.
Keep It Simple Stupid (KISS)
Programmers are often tempted to come up with clever solutions to problems. That#39;s a good thing, of course, but sometimes programmers are too clever, and the solutions are cryptic. This tends to happen when a single line of code is used to accomplish more than a single atomic goal.
Less Is More
In order to aid readability and reduce the temptation to do more than one thing, functions should be as short as possible: Just enough code to do the one thing they were made to do, and no more. In most cases, functions should be just a handful of lines long. If they run much longer, consider breaking out subtasks and data into separate functions and objects.
Minimize Side Effects
There are two classes of bugs that are extremely common and easily avoidable. The first is syntax errors (covered in “Code Quality”). The second is unintentional side effects.
Unintentional side effects are the bane of code reuse. They occur when multiple functions depend on and manipulate the values of the same variables or object properties. In this situation, it becomes much more difficult to refactor code, because your functions assume too much about the state of the program. For example, imagine your app includes a shopping cart, and your users can save cart contents between sessions.
Now the user wants to change the order for the current session, only:
test(#39;Order WITH unintentional side effect.#39;, function () {
var cartProto = {
items: [],
addItem: function addItem(item) {
this.items.push(item);
}
},
createCart = function (items) {
var cart = Object.create(cartProto);
cart.items = items;
return cart;
},
// Load cart with stored items.
savedCart = createCart(['apple', 'pear', 'orange']),
session = {
get: function get() {
return this.cart;
},
// Grab the saved cart.
cart: createCart(savedCart.items)
};
// addItem gets triggered by an event handler somewhere:
session.cart.addItem(#39;grapefruit#39;);
ok(session.cart.items.indexOf(#39;grapefruit#39;)
!== -1, #39;Passes: Session cart has grapefruit.#39;);
ok(savedCart.items.indexOf(#39;grapefruit#39;) === -1,
#39;Fails: The stored cart is unchanged.#39;);});
Sadly, when the user adds or removes items from his session cart, those changes will destroy the settings for the stored cart that he wants to use later. The trouble with this code is here:
createCart = function (items) {
var cart = Object.create(cartProto);
cart.items = items;
return cart;},
At this point, cart.items is a reference to the prototype items attribute. This is improved with one small change to the code:
cart.items = Object.create(items);
Now the new cart will have its own copy of the item data, so changes will not be destructive to storedCart.
The best way to ensure that your program contains few unintentional side effects is to avoid them in yourfunctions. If your function operates on outside variables, return a copy instead of the original.
A pure function has no side effects. It does not alter existing variables or program state in any way, and always returns the same value given the same inputs.
Wherever possible, make sure that your functions don#39;t change anything outside the function itself. Return amended copies rather than originals. Note that you can still alter program state. REST works this way: you get a copy of the data resource (called a representation), manipulate it, and send the copy back to the server. Sometimes performance implications make this advice impractical, but it#39;s helpful to consider the possibility of using pure functions.
Writing most of your functions in a similar fashion can help you separate concerns and reduce code duplication. For example, if you need to implement data validation months after you wrote the original code and you have a sing
全文共64684字,剩余内容已隐藏,支付完成后下载完整资料
第二章 功能
函数是应用程序的基础。由于javascript支持第一类函数(该等级类型的值可以传给子程序作为参数,可以从子程序里返回,可以赋给变量。大多数程序设计语言里,整型、字符类型等简单类型都是一级的。 ),对象函数等等,所以函数在javascript中尤为重要。
下面是一些指导方针,可以帮助你写更好的函数。
1.不要重复自己
好的程序员都是又懒惰又高效的,他们可以在非常少的代码中表达很多功能。一旦你写了一些会重复使用的代码,就说明该写一个函数,对象,或者一个模块来封装该部分,以便以后更好的复用。
这样做可以将该功能单独的隔离到你代码库中的某个位置,以后你的代码或者算法出了问题,只需要在一个地方解决即可。
编写一个可复用的函数还可以强迫你将模式与问题分离,这有助于将相关功进行分组。
2.只做一件事
每个函数应该 做只有一件事,做一件它能做到的事。遵循这个原则增加函数的可复用性,可读性,且更易调试。
3.保持简单愚蠢
程序员经常试图想出聪明的解决问题的办法。这是一件好事,当然,但有时程序员太聪明,解决方案是不易理解的。尤其是当单行代码用于完成多于一个子目标时,这种情况往往会发生。
4.少即是多
为了增加可读性和减少做多个事情的倾向,函数应该尽可能短:代码只需要足够做它们能做的事情即可。在大多数情况下,函数应该只是短短几行。如果它们运行得更长,可以考虑将子任务和数据分解为单独的函数和对象。
副作用最小化
有两种bug是非常常见和容易避免的。第一个是语法错误(在“代码质量”中有说明)。第二个是无意的副作用。
无意的副作用是代码复用的祸根。当多个函数依赖和操作相同变量或者对象属性是,常常会产生副作用。在这种情况下,重构代码变得更加困难,因为你的函数对程序的状态承担太多。例如,想象您的应用程序包含购物车,您的用户可以在会话中保存购物车的物品。
现在用户想要更改当前会话的顺序,只有:
test(#39;Order WITH unintentional side effect.#39;, function () {
var cartProto = {
items: [],
addItem: function addItem(item) {
this.items.push(item);
}
},
createCart = function (items) {
var cart = Object.create(cartProto);
cart.items = items;
return cart;
},
// Load cart with stored items.
savedCart = createCart(['apple', 'pear', 'orange']),
session = {
get: function get() {
return this.cart;
},
// Grab the saved cart.
cart: createCart(savedCart.items)
};
// addItem gets triggered by an event handler somewhere:
session.cart.addItem(#39;grapefruit#39;);
ok(session.cart.items.indexOf(#39;grapefruit#39;)
!== -1, #39;Passes: Session cart has grapefruit.#39;);
ok(savedCart.items.indexOf(#39;grapefruit#39;) === -1,
#39;Fails: The stored cart is unchanged.#39;);});
不幸的是,当用户从会话购物车中添加或移除商品时,会摧毁购物车中已存储的以后要用到的设置,造成这些问题的代码如下所示:
createCart = function (items) {
var cart = Object.create(cartProto);
cart.items = items;
return cart;},
此时,cart.items是对原型属性的items引用。可以对代码进行一个小改动来改进:
cart.items = Object.create(items);
现在新的购物车将有自己项目数据的副本,所以更改不会是对storedCart造成破坏。
确保程序包含少量副作用的最佳方法是在函数中避免它们 。如果函数对外部变量进行操作,则返回一个副本而不是原始数据。
一个纯函数无副作用。它不以任何方式改变现有变量或程序状态,并且在给定相同输入的情况下总是返回相同的值。
只要有可能,请确保您的函数不会更改函数本身之外的任何内容。返回值是修改后的副本,而不是原始数据。注意,你仍然可以改变程序状态。REST以这种方式工作:您获得数据的副本资源(称为代表),操纵它,然后发送复印件回服务器。有时性能影响使此建议不切实际,但有助于考虑使用纯函数的可能性。
以类似的方式编写大部分功能可以帮助分离问题并减少代码重复。例如,如果您需要在写入原始代码后几个月内进行数据验证,并且您有一个单一函数负责向数据资源写入数据,那么添加验证是非常简单。如果整个代码库中有数百个函数直接访问数据,就会变成一个困难的任务。
以这种方式保持事物隔离也可以提高管理状态的能力。如果操作数据的函数不必担心程序的状态,也考虑其他函数创建造成的副作用,他们可以用更少的代码来完成他们的工作。他们必须知道的是如何完成他们被要求做的任务。
同样,唯一应该操作DOM的函数应该是专用于DOM操作的方法,例如视图的.render()方法或DOM插件。
函数定义
在JavaScript中有几种方法来定义函数。每个都有自己的优点和缺点:
function foo() {
/* Warning: arguments.callee is deprecated. Use with caution. Used here strictly for illustration. */
return arguments.callee;}
foo(); //=gt; [Function: foo]
在这段代码中,foo()是一个函数声明。 如“提升”中所述,重要的是,你不能用条件语句声明一个函数。 例如,以下代码将失败:
var score = 6;
if (score gt; 5) {
function grade() {
return #39;pass#39;;
}} else {
function grade() {
return #39;fail#39;;
}}
module(#39;Pass or Fail#39;);
test(#39;Conditional function declaration.#39;, function () {
// Firefox: Pass
// Chrome, Safari, IE, Opera: Fail
equal(grade(), #39;pass#39;,
#39;Grade should pass.#39;);});
更糟糕的是,这种模式在浏览器之间不一致。 最好是完全避免使用条件语句进行函数声明。 更多相关详细信息,请参阅“提升”。
函数声明往往鼓励大堆松散相关的函数在你的模块中增长,没有真正的暗示关于什么应该放在哪里,是公共还是私有,或多个函数如何一起工作:
var bar = function () {
return arguments.callee;};
bar(); //=gt; [Function] (Note: It#39;s anonymous.)
bar()示例将一个函数体分配给变量bar。 这个实现称为函数expressio
函数表达式的优点是可以使用与向变量赋值相同的方法给函数赋值。 您可以依赖函数表达式来可靠地跟踪应用程序逻辑。 如果你想做一个条件赋值,它会按预期工作。
函数表达式的缺点是除非你显式地提供名称,否则函数表达式会创建匿名函数,。 匿名函数在JavaScript中经常使用 - 可能是肆无忌惮地放弃。 想象一下,你已经声明了所有的函数,你有一堆函数调用函数调用更多的函数。 这是一个在架构良好,事件驱动的应用程序中的常见情况。 现在想象你有12个函数调用深,出现问题。 你需要调试和查看你的调用堆栈,但它看起来像这样:
(Anonymous function)
(Anonymous function)
(Anonymous function)
(Anonymous function)
(Anonymous function)
(Anonymous function)
(Anonymous function)
(Anonymous function)
(Anonymous function)
(Anonymous function)
(Anonymous function)
(Anonymous function)
明显的,这种方式不是很有效:
var baz = {
f: function () {
return arguments.callee;
}
};
baz.f(); // =gt; [Function] (Note: Also anonymous.)
baz函数这个例子与之前存在相同的问题。这是另一种匿名函数的表示形式,将函数复制给对象字面量的一个属性。函数表达式有时也可以叫说方法字面量,方法是附加到对象的函数。
方法字面量优点是使用对象字面量很容易对相关函数进行分组。例如,您有一组控制灯泡状态的函数:
var lightBulbAPI = {
toggle: function () {},
getState: function () {},
off: function () {},
on: function () {},
blink: function () {}
};
当您将相关功能组合在一起是很好的做法。代码将更有条理和可读性,在上下文中也将更容易理解和维护。
另一个优点是,当您注意到模块变得太大时,您可以更轻松地重新排列代码。例如,如果你的智能房屋模块由于一些用于灯泡,电视,音乐和车库门的API,变得过于笨重,并且它们都是按照这些分组的,那么更容易将它们分离成单独的模块文件。
不要使用Function()构造函数声明一个函数。将函数传递给一个字符串相当于传递一个字符串到eval()函数。它具有在第2章中讨论的相同的缺点和安全隐患。
命名函数表达式
如你看到的, 所有的函数定义技术都有弱点,但它可能获得代码组织和条件函数定义的好处,而不是乱堆栈的跟踪与匿名函数。让我们再来看看lightbulbAPI这个例子:
var lightbulbAPI = {
toggle: function toggle() {},
getState: function getState() {},
off: function off() {},
on: function on() {},
blink: function blink() {}
};
命名函数表达式除了它们有一个名称,便于在函数内部递归调用以外,其余与匿名函数表达式都是一样的。该名称也方便地出现在函数调用堆栈。
与匿名函数表达式一样,您可以在使用变量的任何位置使用它们,而不仅仅是在方法字面量的内部。命名函数表达式是不一样的函数声明。与函数声明不同,您分配的名称仅在函数内
全文共17879字,剩余内容已隐藏,支付完成后下载完整资料
资料编号:[144386],资料为PDF文档或Word文档,PDF文档可免费转换为Word