英语原文共 10 页,剩余内容已隐藏,支付完成后下载完整资料
跳动的javascript
哈弗贝克
第三章
1 函数
函数是JavaScript编程的重要组成部分。把一个程序打包成一个值的概念有很多用途。它为我们提供了一种构造大型程序、减少重复、将名称与子程序相关联、以及将这些子程序彼此隔离的方法。
函数最明显的应用是定义新词汇。在散文中创造新词通常是不好的文体。但是在编程中,它是必不可少的。
典型的成年人英语词汇中有20000个单词。很少有编程语言带有内置的20000个命令。而可用的词汇往往比人类语言更精确地定义,因而更不灵活。因此,我们通常会引入新的概念来避免重复太多。
2.定义函数
函数定义是一个正则绑定,其中绑定的值是一个函数。例如,这个代码定义了平方方法来表示产生给定数的平方的函数:
const square = function(x) {
return x * x;
};
console.log(square(12));
// → 144
一个函数是用一个关键字开始的表达式创建的。函数有一组参数(在这种情况下,只有x)和一个体,其中包含函数调用时要执行的语句。这样创建的函数的函数体必须总是用括号括起来,即使它仅由单个语句组成。
一个函数可以有多个参数或者根本没有参数。在下面的示例中,makeNoise不列出任何参数名,而幂power列出了两个参数:
const makeNoise = function() {
console.log('Pling!');
};
makeNoise();
// → Pling!
const power = function(base, exponent) {
let result = 1;
for (let count = 0; count lt; exponent; count ) {
result *= base;
}
return result;
};
console.log(power(2, 10));
// → 1024
一些函数产生一个值,例如幂和平方,而一些函数则不存在,例如makeNoise。返回语句决定函数返回的值。当程序遇到这样的语句时,它立即跳出当前函数,并将返回的值赋给调用函数的代码。返回关键字没有表达式后会导致函数返回未定义。函数中没有一个“返回”语句,比如makeNoise,类似地返回未定义的函数。
函数的参数就像正则绑定一样,但是它们的初始值由函数的调用方来给出,而不是函数本身中的代码。
3.绑定及其作用域
每个绑定都有一个范围,它是所绑定可见程序的一部分。对于定义在任何函数或块之外的绑定,作用域是整个程序,您可以在任何需要的地方引用此类绑定。这些被称为“全局”。
但是为函数参数创建的绑定或在函数内声明的绑定只能在该函数中引用,因此它们被称为“局部绑定”。每次调用函数时,都创建这些绑定的新实例。这提供了一些功能之间的隔离,每个函数调用在其自己的小世界(其本地环境)中起作用,并且经常可以被理解而不知道在全局环境中发生了什么。
声明的绑定,如“let”和“const”实际上是它们被声明的块的局部,所以如果你在一个循环中创建它们中的一个,循环前后的代码就不能“看到”它。在2015年前的JavaScript中,只有函数创建了新的范围,所以用VAR关键字创建的旧样式绑定在整个函数中都可见,如果它们不在函数中,则它们出现在全局范围内或整个全局范围内。
let x = 10;
if (true) {
let y = 20;
var z = 30;
console.log(x y z);
// → 60
}
// y is not visible here
console.log(x z); // → 40
每个范围都可以“查看”到它周围的范围,因此X在示例中的块内可见。例外情况是,在这种情况下,多个绑定具有相同的名称,代码只能看到最里面的一个。例如,当减半函数中的代码是指n时,它看到的是它自己的n,而不是全局的n。
const halve = function(n) {
return n / 2;
};
let n = 10;
console.log(halve(100));
// → 50
console.log(n);
// → 10
4.嵌套作用域
JavaScript不仅仅区分全局的和局部的绑定。块和函数可以在其他块和函数中创建,产生多个局部性。
例如,输出一批鹰嘴豆所需的成分的函数内部还有另一个函数:
const hummus = function(factor) {
const ingredient = function(amount, unit, name) {
let ingredientAmount = amount * factor;
if (ingredientAmount gt; 1) {
unit = 's';
}
console.log(`${ingredientAmount} ${unit} ${name}`);
};
ingredient(1, 'can', 'chickpeas');
ingredient(0.25, 'cup', 'tahini');
ingredient(0.25, 'cup', 'lemon juice');
ingredient(1, 'clove', 'garlic');
ingredient(2, 'tablespoon', 'olive oil');
ingredient(0.5, 'teaspoon', 'cumin');
};
函数中的代码可以从外函数中看到beta;因子的绑定。但它的局部绑定,如单元单位或pi;成分量,在外函数中是不可见的。
简而言之,每个局部作用域也可以看到包含它的所有局部作用域。块内可见的绑定集由程序块中的块的位置决定。每个局部作用域也可以看到包含它的所有局部作用域,并且所有作用域都可以看到全局范围。这种绑定可见性的方法称为词法范围。
5. 作为参数的函数
函数绑定通常只是作为程序特定的一个名称。这样的绑定被定义一次并且从未改变。这使得很容易混淆函数及其名称。
但两者是不同的。一个函数值可以完成所有其他值所能做的事情,你可以把它用在任意表达式中,而不只是调用它。可以将函数值存储在新绑定中,将其作为参数传递给函数,以此类推。类似地,持有函数的绑定仍然只是一个常规绑定,如果不是常数,则可以分配一个新的值,如下所示:
let launchMissiles = function() {
missileSystem.launch('now');
};
if (safeMode) {
launchMissiles = function() {/* do nothing */};
}
在第5章中,我们将讨论通过将函数值传递给其他函数所做的有趣的事情。
6. 声明符号
创建函数绑定的方式稍短一些。当在语句开始时使用“函数”关键字时,它的工作方式不同。
function square(x) {
return x * x;
}
这是一个函数声明。语句定义绑定平方,并将其指向给定函数。它稍微容易写,并且在函数之后不需要分号。
这种形式的函数定义有一个微妙之处。
console.log('The future says:', future());
function future() {
return 'Youll never have flying cars';
}
前面的代码是有效的,即使函数定义在下面的代码中。函数声明不是控件上下规则流的一部分。它们在概念上被移动到其范围的顶部,并且可以被该范围内的所有代码使用。这有时是有用的,因为它提供了以看似有意义的方式来对代码进行排序的自由,而不必担心在使用它们之前必须定义所有函数。
7. 箭头函数
函数的第三个符号,看起来和其他的很不一样。它使用的不是函数关键字,而是一个由等号和大于字符组成的箭头 (=gt;) (不要与写的大于或等于的运算符gt;=混淆)。
const power = (base, exponent) =gt; {
let result = 1;
for (let count = 0; count lt; exponent; count ) {
result *= base;
}
return result;
};
箭头在参数列表之后,然后是函数的主体。它表示类似“这个输入(参数)产生这个结果(主体)”。
当只有一个参数名时,可以省略参数列表周围的括号。如果主体是单个表达式,而不是括号中的块,则该表达式将从函数返回。所以,这两个正方形的定义是一样的
const square1 = (x) =gt; { return x * x; };
const square2 = x =gt; x * x;
当一个箭头函数完全没有参数时,它的参数列表只是一个空的括号
const horn = () =gt; {
console.log('Toot');
};
在语言中,没有深层次的原因可以同时拥有箭头函数和函数表达式。除了一个小细节,我们将在第六章中讨论,他们也做同样的事情。在2015年添加了箭头函数,主要是为了使小函数表达式的编写变得不那么冗长。我们会在第五章中经常用到它们。
8. 调用堆栈
通过函数的控制流会涉及到。让我们仔细看看。下面是一个简单的程序,它可以调用几个函数:
function greet(who) {
console.log('Hello ' who);
}
greet('Harry');
console.log('Bye');
通过这个程序的运行大致是这样的:对greet的调用使其跳转到该函数的开始(第2行)。日志,它负责控制,完成它的工作,然后将控制返回到第2行。它到达了欢迎函数的末尾,所以它返回到调用它的地方,也就是第4行。然后再调用console.log。在那之后,程序就会结束
我们可以像这样显示控制流程:
not in function
in greet
in console.log
in greet
not in function
in console.log
not in function
因为函数必须返回到它返回时调用它的位置,所以计算机必须记住调用发生的上下文。在一个案例中,控制台。日志必须在完成后返回到greet函数。在另一种情况下,它返回到程序的末尾。
计算机存储此上下文的位置是调用堆栈。每当调用一个函数时,当前上下文就存储在这个堆栈的顶部。当函数返回时,它将从堆栈中移除顶部上下文,并使用该上下文继续执行。
存储这个堆栈需要计算机内存中的空间。当堆栈变得太大时,计算机将会以“超出堆栈空间”或“太多递归”之类的消息失败。下面的代码通过向计算机提出一个非常困难的问题来说明这一点,它会在两个函数之间产生无限的来回。相反,如果计算机有一个无限的堆栈,它将是无限的。就像这样,我们将耗尽空间,或者“炸了堆栈”。
function chicken() {
return egg();
}
function egg() {
return chicken();
}
console.log(chicken() ' came first.');
9. 可选参数
允许和执行以下代码没有任何问题:
function square(x) { return x * x; }
console.log(square(4, true, 'hedgehog'));
// → 16
我们仅用一个参数定义了平方。然而,当我们用三来
剩余内容已隐藏,支付完成后下载完整资料
资料编号:[23387],资料为PDF文档或Word文档,PDF文档可免费转换为Word
课题毕业论文、外文翻译、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。