From 01b0e12ba27b5069248fd09235e9a7143915ee30 Mon Sep 17 00:00:00 2001 From: Irvin Date: Wed, 16 Feb 2022 02:02:49 +0800 Subject: remove `notranslate` class in zh-CN --- .../web/javascript/guide/functions/index.html | 74 +++++++++++----------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'files/zh-cn/web/javascript/guide/functions') diff --git a/files/zh-cn/web/javascript/guide/functions/index.html b/files/zh-cn/web/javascript/guide/functions/index.html index 3d43d61305..54e0bffa4b 100644 --- a/files/zh-cn/web/javascript/guide/functions/index.html +++ b/files/zh-cn/web/javascript/guide/functions/index.html @@ -30,21 +30,21 @@ translation_of: Web/JavaScript/Guide/Functions

例如,以下的代码定义了一个简单的square函数:

-
function square(number) {
+
function square(number) {
   return number * number;
 }
 

函数square使用了一个参数,叫作number。这个函数只有一个语句,它说明该函数将函数的参数(即number)自乘后返回。函数的return语句确定了函数的返回值:

-
return number * number;
+
return number * number;
 

原始参数(比如一个具体的数字)被作为传递给函数;值被传递给函数,如果被调用函数改变了这个参数的值,这样的改变不会影响到全局或调用函数。

如果你传递一个对象(即一个非原始值,例如{{jsxref("Array")}}或用户自定义的对象)作为参数,而函数改变了这个对象的属性,这样的改变对函数外部是可见的,如下面的例子所示:

-
function myFunc(theObject) {
+
function myFunc(theObject) {
   theObject.make = "Toyota";
 }
 
@@ -62,19 +62,19 @@ y = mycar.make;     // y获取的值为 "Toyota"
 
 

虽然上面的函数声明在语法上是一个语句,但函数也可以由函数表达式创建。这样的函数可以是匿名的;它不必有一个名称。例如,函数square也可这样来定义:

-
const square = function(number) { return number * number; };
+
const square = function(number) { return number * number; };
 var x = square(4); // x gets the value 16

然而,函数表达式也可以提供函数名,并且可以用于在函数内部代指其本身,或者在调试器堆栈跟踪中识别该函数:

-
const factorial = function fac(n) {return n<2 ? 1 : n*fac(n-1)};
+
const factorial = function fac(n) {return n<2 ? 1 : n*fac(n-1)};
 
 console.log(factorial(3));
 

当将函数作为参数传递给另一个函数时,函数表达式很方便。下面的例子演示了一个叫map的函数如何被定义,而后使用一个表达式函数作为其第一个参数进行调用:

-
function map(f,a) {
+
function map(f,a) {
   let result = []; // 创建一个数组
   let i; // 声明一个值,用来循环
   for (i = 0; i != a.length; i++)
@@ -85,7 +85,7 @@ console.log(factorial(3));
 
 

下面的代码:

-
function map(f, a) {
+
function map(f, a) {
   let result = []; // 创建一个数组
   let i; // 声明一个值,用来循环
   for (i = 0; i != a.length; i++)
@@ -103,7 +103,7 @@ console.log(cube);

在 JavaScript 中,可以根据条件来定义一个函数。比如下面的代码,当num 等于 0 的时候才会定义 myFunc :

-
var myFunc;
+
var myFunc;
 if (num == 0){
   myFunc = function(theObject) {
     theObject.make = "Toyota"
@@ -118,14 +118,14 @@ if (num == 0){
 
 

定义一个函数并不会自动的执行它。定义了函数仅仅是赋予函数以名称并明确函数被调用时该做些什么。调用函数才会以给定的参数真正执行这些动作。例如,一旦你定义了函数square,你可以如下这样调用它:

-
square(5);
+
square(5);
 

上述语句通过提供参数 5 来调用函数。函数执行完它的语句会返回值25。

函数一定要处于调用它们的域中,但是函数的声明可以被提升(出现在调用语句之后),如下例:

-
console.log(square(5));
+
console.log(square(5));
 /* ... */
 function square(n) { return n*n }
 
@@ -136,7 +136,7 @@ function square(n) { return n*n }

提示:注意只有使用如上的语法形式(即 function funcName(){})才可以。而下面的代码是无效的。就是说,函数提升仅适用于函数声明,而不适用于函数表达式。

-
console.log(square); // square is hoisted with an initial value undefined.
+
console.log(square); // square is hoisted with an initial value undefined.
 console.log(square(5)); // Uncaught TypeError: square is not a function
 const square = function (n) {
   return n * n;
@@ -146,7 +146,7 @@ const square = function (n) {
 
 

函数可以被递归,就是说函数可以调用其本身。例如,下面这个函数就是用递归计算阶乘:

-
function factorial(n){
+
function factorial(n){
   if ((n == 0) || (n == 1))
     return 1;
   else
@@ -156,7 +156,7 @@ const square = function (n) {
 
 

你可以计算1-5的阶乘如下:

-
var a, b, c, d, e;
+
var a, b, c, d, e;
 
 a = factorial(1); // 1赋值给a
 b = factorial(2); // 2赋值给b
@@ -171,7 +171,7 @@ e = factorial(5); // 120赋值给e
 
 

在函数内定义的变量不能在函数之外的任何地方访问,因为变量仅仅在该函数的域的内部有定义。相对应的,一个函数可以访问定义在其范围内的任何变量和函数。换言之,定义在全局域中的函数可以访问所有定义在全局域中的变量。在另一个函数中定义的函数也可以访问在其父函数中定义的所有变量和父函数有权访问的任何其他变量。

-
// 下面的变量定义在全局作用域(global scope)中
+
// 下面的变量定义在全局作用域(global scope)中
 var num1 = 20,
     num2 = 3,
     name = "Chamahk";
@@ -212,7 +212,7 @@ getScore(); // 返回 "Chamahk scored 5"
 
 

例如,思考一下如下的函数定义:

-
var foo = function bar() {
+
var foo = function bar() {
    // statements go here
 };
 
@@ -227,7 +227,7 @@ getScore(); // 返回 "Chamahk scored 5"

调用自身的函数我们称之为递归函数。在某种意义上说,递归近似于循环。两者都重复执行相同的代码,并且两者都需要一个终止条件(避免无限循环或者无限递归)。例如以下的循环:

-
var x = 0;
+
var x = 0;
 while (x < 10) { // "x < 10" 是循环条件
    // do stuff
    x++;
@@ -236,7 +236,7 @@ while (x < 10) { // "x < 10" 是循环条件
 
 

可以被转化成一个递归函数和对其的调用:

-
function loop(x) {
+
function loop(x) {
   if (x >= 10) // "x >= 10" 是退出条件(等同于 "!(x < 10)")
     return;
   // 做些什么
@@ -247,7 +247,7 @@ loop(0);
 
 

不过,有些算法并不能简单的用迭代来实现。例如,获取树结构中所有的节点时,使用递归实现要容易得多:

-
function walkTree(node) {
+
function walkTree(node) {
   if (node == null) //
     return;
   // do something with node
@@ -263,7 +263,7 @@ loop(0);
 
 

这种类似堆栈的行为可以在下例中看到:

-
function foo(i) {
+
function foo(i) {
   if (i < 0)
     return;
   console.log('begin:' + i);
@@ -298,7 +298,7 @@ foo(3);
 
 

下面的例子展示了嵌套函数:

-
function addSquares(a, b) {
+
function addSquares(a, b) {
   function square(x) {
     return x * x;
   }
@@ -310,7 +310,7 @@ c = addSquares(4, 5); // returns 41

由于内部函数形成了闭包,因此你可以调用外部函数并为外部函数和内部函数指定参数:

-
function outside(x) {
+
function outside(x) {
   function inside(y) {
     return x + y;
   }
@@ -333,7 +333,7 @@ result1 = outside(3)(5); // returns 8

思考一下下面的例子:

-
function A(x) {
+
function A(x) {
   function B(y) {
     function C(z) {
       console.log(x + y + z);
@@ -360,7 +360,7 @@ A(1); // logs 6 (1 + 2 + 3)

看以下的例子:

-
function outside() {
+
function outside() {
   var x = 5;
   function inside(x) {
     return x * 2;
@@ -380,7 +380,7 @@ outside()(10); // returns 20 instead of 10

此外,由于内部函数可以访问外部函数的作用域,因此当内部函数生存周期大于外部函数时,外部函数中定义的变量和函数的生存周期将比内部函数执行时间长。当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。

-
var pet = function(name) {          //外部函数定义了一个变量"name"
+
var pet = function(name) {          //外部函数定义了一个变量"name"
   var getName = function() {
     //内部函数可以访问 外部函数定义的"name"
     return name;
@@ -395,7 +395,7 @@ myPet();                            // 返回结果 "Vivie"
 
 

实际上可能会比上面的代码复杂的多。在下面这种情形中,返回了一个包含可以操作外部函数的内部变量方法的对象。

-
var createPet = function(name) {
+
var createPet = function(name) {
   var sex;
 
   return {
@@ -431,7 +431,7 @@ pet.getName();                  // Oliver
 
 

在上面的代码中,外部函数的name变量对内嵌函数来说是可取得的,而除了通过内嵌函数本身,没有其它任何方法可以取得内嵌的变量。内嵌函数的内嵌变量就像内嵌函数的保险柜。它们会为内嵌函数保留“稳定”——而又安全——的数据参与运行。而这些内嵌函数甚至不会被分配给一个变量,或者不必一定要有名字。

-
var getCode = (function(){
+
var getCode = (function(){
   var secureCode = "0]Eal(eh&2";    // A code we do not want outsiders to be able to modify...
 
   return function () {
@@ -445,7 +445,7 @@ getCode();    // Returns the secret code
 

尽管有上述优点,使用闭包时仍然要小心避免一些陷阱。如果一个闭包的函数定义了一个和外部函数的某个变量名称相同的变量,那么这个闭包将无法引用外部函数的这个变量。

-
var createPet = function(name) {  // Outer function defines a variable called "name"
+
var createPet = function(name) {  // Outer function defines a variable called "name"
   return {
     setName: function(name) {    // Enclosed function also defines a variable called "name"
       name = name;               // ??? How do we access the "name" defined by the outer function ???
@@ -459,7 +459,7 @@ getCode();    // Returns the secret code
 
 

函数的实际参数会被保存在一个类似数组的arguments对象中。在函数内,你可以按如下方式找出传入的参数:

-
arguments[i]
+
arguments[i]
 

其中i是参数的序数编号(译注:数组索引),以0开始。所以第一个传来的参数会是arguments[0]。参数的数量由arguments.length表示。

@@ -468,7 +468,7 @@ getCode(); // Returns the secret code

例如,设想有一个用来连接字符串的函数。唯一事先确定的参数是在连接后的字符串中用来分隔各个连接部分的字符(译注:比如例子里的分号“;”)。该函数定义如下:

-
function myConcat(separator) {
+
function myConcat(separator) {
    var result = ''; // 把值初始化成一个字符串,这样就可以用来保存字符串了!!
    var i;
    // iterate through arguments
@@ -480,7 +480,7 @@ getCode();    // Returns the secret code
 
 

你可以给这个函数传递任意数量的参数,它会将各个参数连接成一个字符串“列表”:

-
// returns "red, orange, blue, "
+
// returns "red, orange, blue, "
 myConcat(", ", "red", "orange", "blue");
 
 // returns "elephant; giraffe; lion; cheetah; "
@@ -504,7 +504,7 @@ myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");
 
 

在过去,用于设定默认参数的一般策略是在函数的主体中测试参数值是否为undefined,如果是则赋予这个参数一个默认值。如果在下面的例子中,调用函数时没有实参传递给b,那么它的值就是undefined,于是计算a*b得到、函数返回的是 NaN。但是,在下面的例子中,这个已经被第二行获取处理:

-
function multiply(a, b) {
+
function multiply(a, b) {
   b = (typeof b !== 'undefined') ?  b : 1;
 
   return a*b;
@@ -515,7 +515,7 @@ multiply(5); // 5
 
 

使用默认参数,在函数体的检查就不再需要了。现在,你可以在函数头简单地把1设定为b的默认值:

-
function multiply(a, b = 1) {
+
function multiply(a, b = 1) {
   return a*b;
 }
 
@@ -527,7 +527,7 @@ multiply(5); // 5

剩余参数语法允许将不确定数量的参数表示为数组。在下面的例子中,使用剩余参数收集从第二个到最后参数。然后,我们将这个数组的每一个数与第一个参数相乘。这个例子是使用了一个箭头函数,这将在下一节介绍。

-
function multiply(multiplier, ...theArgs) {
+
function multiply(multiplier, ...theArgs) {
   return theArgs.map(x => multiplier * x);
 }
 
@@ -544,7 +544,7 @@ console.log(arr); // [2, 4, 6]

在一些函数模式中,更简洁的函数很受欢迎。对比一下:

-
var a = [
+
var a = [
   "Hydrogen",
   "Helium",
   "Lithium",
@@ -563,7 +563,7 @@ console.log(a3); // logs [ 8, 6, 7, 9 ]

在箭头函数出现之前,每一个新函数都重新定义了自己的 this 值(在构造函数中是一个新的对象;在严格模式下是未定义的;在作为“对象方法”调用的函数中指向这个对象;等等)。以面向对象的编程风格,这样着实有点恼人。

-
function Person() {
+
function Person() {
   // 构造函数Person()将`this`定义为自身
   this.age = 0;
 
@@ -579,7 +579,7 @@ var p = new Person();

在ECMAScript 3/5里,通过把this的值赋值给一个变量可以修复这个问题。

-
function Person() {
+
function Person() {
   var self = this; // 有的人习惯用`that`而不是`self`,
                    // 无论你选择哪一种方式,请保持前后代码的一致性
   self.age = 0;
@@ -594,7 +594,7 @@ var p = new Person();

箭头函数捕捉闭包上下文的this值,所以下面的代码工作正常。

-
function Person(){
+
function Person(){
   this.age = 0;
 
   setInterval(() => {
-- 
cgit v1.2.3-54-g00ecf