Eloquent JavaScript 笔记 三: Functions

来源:互联网 发布:汽车销售行业分析数据 编辑:程序博客网 时间:2024/06/05 16:05

1. Define

var square = function(x) {    return x * x;};console.log(square(12));

参数:函数可以不带参数,也可以带多个参数:

var makeNoise = function() {    console.log('Pling!');}var power = function(base, exponent) {    var result = 1;    for(var count=0; count<exponent; count++) {        result *= base;    }    return result;}

返回值:函数可以返回一个值,也可以没有返回值。当没有return语句,或者return 后面没有值时 (return ; ) ,实际的返回值是 undefined .


1. Variable Scopes

local: 

函数的参数,函数内部声明的变量。 

只有在本函数范围内才可以访问。

避免函数之间的变量互相影响。

每个函数都是一个小宇宙,互不影响。

global:

在任何函数体外面定义的变量。在任何函数中都可以访问。

尽量避免使用global变量。


1. Nested Scope

在函数内部定义函数,看个例子先:

var landscape = function() {  var result = "";  var flat = function(size) {    for (var count = 0; count < size; count++)      result += "_";  };  var mountain = function(size) {    result += "/";    for (var count = 0; count < size; count++)      result += "'";    result += "\\";  };  flat(3);  mountain(4);  flat(6);  mountain(1);  flat(1);  return result;};console.log(landscape());// → ___/''''\______/'\_


flat( ) 和 mountain( ) 可以使用 landscape( ) 内定义的变量,如result,但各自内部的变量互不影响,如count。

lexical scoping: 内层作用域可以访问它所有的外层作用域的内容。

function 是创建scope的唯一方法,只靠花括号不能创建scope,这与其他语言不同。例如:

var something = 1;{   var something = 2;}console.log(something);// -> 2
上面的代码中,第二个 var something 并没有定义一个新的变量,它和第一个var something 是同一个变量,所以,输出结果是 2 。

1. Functions as Values

函数和其他类型的变量没有本质区别,只不过它的值是一段代码。函数可以用在任何表达式中,而不仅仅是调用它。也可以把它作为其他函数的参数。


1. Declaration Notation

function square(x) {  return x * x;}

这种声明方式与变量赋值方式有一点区别,那就是,函数的声明可以写在函数调用的后面。

console.log("The future says:", future());function future() {  return "We STILL have no flying cars.";}

如果用另一种写法,代码执行会出错,如下:



1. The Call Stack

先看一个函数调用的例子:

function greet(who) {  console.log("Hello " + who);}greet("Harry");console.log("Bye");

因为函数本身是一个代码块,那么,调用一个函数时,代码的执行会发生跳转,跳到这个函数内部的代码中。当函数调用执行完之后,再跳回原来的位置,顺序往下执行。这个跳回来的位置和程序当时的状态(叫做 context),需要妥善保存,否则,执行完函数就不知道往哪里跳了。在计算机中,保存context的位置叫做 call stack。

上面这段代码的call stack大概是下面这个样子:

top

   greet

        console.log

   greet

top

   console.log

top


call stack 需要内存空间,当它太大时,计算机会报错,程序也会停止执行。出错信息可能是: out of stack space 或者 too much recursion 。

看一个函数无限递归调用的例子:

function chicken() {  return egg();}function egg() {  return chicken();}console.log(chicken() + " came first.");

在Chrome中执行:



1. Growing Functions

函数产生的两个原因:

    1. 相似的代码写了多次,可以放到一个函数中,避免重复。也可以减少出错的可能性。

    2. 有一个独立的、明确的功能,可以封装到函数中。


函数的命名和优化

用这种格式打印牛和鸡的个数:

007 Cows

011 Chickens

function printFarmInventory(cows, chickens) {    var cowString = String(cows);    while (cowString.length < 3) {        cowString = "0" + cowString;    }    console.log(cowString + " Cows");    var chickenString = String(chickens);    while (chickenString.length < 3) {        chickenString = "0" + chickenString;    }    console.log(chickenString + " Chickens");}printFarmInventory(7, 11);

需求变化了,农场主想把猪的数量也按这种格式打印出来。

我们看到,打印牛和鸡的两段代码非常相似,那么打印猪的代码一定也是一样的,此时,可以定义一个函数,避免重复。


function printZeroPaddedWithLabel(number, label) {  var numberString = String(number);  while (numberString.length < 3)    numberString = "0" + numberString;  console.log(numberString + " " + label);}function printFarmInventory(cows, chickens, pigs) {  printZeroPaddedWithLabel(cows, "Cows");  printZeroPaddedWithLabel(chickens, "Chickens");  printZeroPaddedWithLabel(pigs, "Pigs");}printFarmInventory(7, 11, 3);

上面的函数名称很长,这也说明,该函数所包含的功能太多了(单一职责原则)。

function zeroPad(number, width) {  var string = String(number);  while (string.length < width)    string = "0" + string;  return string;}function printFarmInventory(cows, chickens, pigs) {  console.log(zeroPad(cows, 3) + " Cows");  console.log(zeroPad(chickens, 3) + " Chickens");  console.log(zeroPad(pigs, 3) + " Pigs");}printFarmInventory(7, 16, 3);

1. Functions and Side Effects

一个函数,要么返回一个值,要么对环境产生影响,或者,二者兼有。如果,都二者没有,它也没有存在的必要。

pure function:

1. 一个纯函数,只返回数据,而不会对环境产生影响,也不会受到环境的影响,它的执行结果只与传入的参数有关。

2. 纯函数的 “封装性” 好,执行结果可预期,可测试。想想看,一个 “非纯函数” 如何进行自动化测试?


非纯函数也是必需的,如: console.log( ) 。 而且,有的时候,非纯函数可能更简洁,执行效率更高。 如何取舍要视情况而定。


1. Exercise: Minimum

function min(a, b) {return a < b ? a : b;}

1. Exercise: Recursion

function isEven(n) {    if (n < 0) {        return isEven(-n);    }    else if (n == 0) {        return true;    }    else if (n == 1) {        return false;    }    else {        return isEven(n-2);    }}

1. Exercise: Bean Counting

function countBs(s) {    var ret = 0;    for (var i=0; i<s.length; i++) {        if(s.charAt(i) == 'B') {            ret++;        }    }    return ret;}

function countChar(s, char) {    var ret = 0;    for (var i=0; i<s.length; i++) {        if(s.charAt(i) == char) {            ret++;        }    }    return ret;}function countBs(s) {    return countChar(s, 'B');}


0 0