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');}
- Eloquent JavaScript 笔记 三: Functions
- Eloquent JavaScript 笔记 五: High-Order Functions
- 《Eloquent JavaScript》笔记--函数;
- Eloquent JavaScript 笔记 十: Modules
- Eloquent JavaScript 笔记 十三:DOM
- Eloquent JavaScript 笔记 十七:HTTP
- 《Eloquent JavaScript》笔记--对象与数组
- 《Eloquent JavaScript》笔记--程序的结构;
- Eloquent JavaScript 笔记 二:Program Structure
- Eloquent JavaScript 笔记 四:Objects and Arrays
- Eloquent JavaScript 笔记 七: Electronic Life
- Eloquent JavaScript 笔记 十一:A Programming Language
- Eloquent JavaScript 笔记 十四:Handling Event
- Eloquent JavaScript 笔记 十五:A Platform Game
- Eloquent JavaScript 笔记 十六:Drawing on Canvas
- Eloquent JavaScript 笔记 十九:Node.js
- Eloquent JavaScript 笔记 二十:略有遗憾
- Eloquent JavaScript 笔记 十二:Javascript and the Browser
- Backtracking
- Dynamic Programming
- 这也算不错?
- git cherry-pick 出错
- Contest Review
- Eloquent JavaScript 笔记 三: Functions
- eclipse使用技巧
- 26. Remove Duplicates from Sorted Array
- Eclipse中将Java项目转换成Web项目的方法
- css锚伪类
- iOS开发之总结几个提高开发效率的小技巧
- Thread
- Linux常用指令---grep(搜索过滤)
- Android 动画属性详解