每個函數都是Function類型的實例,而且都與其他引用類型一樣具有屬性和方法.函數名實際上是指向函數對象的指針.
函數聲明:
function sum( num1,num2) {
	return num1+num2;
}
var sum = sum(1,2);  //3
 
        函數聲明提升: 上面這個例子是函數聲明在前,調用在后,但是js引擎能把函數聲明提到頂部.
函數表達式:
var sum = function(num1,num2) {
	return num1+num2;
}
console.log(sum(1,2)); 
        function后面沒有變量名,sum就相當於變量名,直接調用.但是不能在調用之后才定義,會報 "Uncaught TypeError: undefined is not a function"錯誤.
說說函數名后面的 ( )
以上面的sum(num1,num2)為例
- sum(); 執行函數
 - sum: 沒有括號是訪問函數的指針不執行函數
 
arguments對象和this對象
- arguments對象存放着函數的所有參數,類似數組但不是數組,
 - 函數內部的this引用的是函數據以執行的環境變量,當在全局作用域中調用函數時,this對象引用的就是window對象.
 
arguments.callee屬性:指向擁有這個arguments對象的函數.在遞歸的時候用到
function fac(num) {
	if(num<=1){
		return 1;
	}else {
		return num* arguments.callee(num)
	}
}
 
        使用arguments.callee,函數內部調用和函數本身的名字不會有耦合.
函數傳參:
題目描述
輸入例子:
argsAsArray(function (greeting, name, punctuation) {return greeting + ', ' + name + (punctuation || '!');}, ['Hello', 'Ellie', '!']) 
         輸出例子:
Hello, Ellie!
function argsAsArray(fn, arr) {
	return  fn(arr[0], arr[1], arr[2]);
} 
         題目描述 考察:call() apply() bind() 改變上下文this
輸入例子:
speak(function () {return this.greeting + ', ' + this.name + '!!!';}, {greeting: 'Hello', name: 'Rebecca'}) 
          輸出例子:
Hello, Rebecca!!!
//三種方案
//apply
function speak(fn, obj) {    return fn.apply(obj);}
//call
function speak(fn, obj) {    return fn.call(obj);}
//bind
function speak(fn, obj) {    return fn.bind(obj)();} 
          注意:在JavaScript中,函數是一種對象,其上下文是可以變化的,對應的,函數內的this也是可以變化的,函數可以作為一個對象的方法,也可以同時作為另一個對象的方法,可以通過Function對象中的call或者apply方法來修改函數的上下文,函數中的this指針將被替換為call或者apply的第一個參數。將函數 fn 的執行上下文改為 obj 對象,只需要將obj作為call或者apply的第一個參數傳入即可。
題目描述 考察:var obj = {},var obj = new Object();
1、返回一個對象
2、對象的 greeting 屬性值等於 str1, name 屬性值等於 str2
3、對象存在一個 sayIt 方法,該方法返回的字符串為 greeting屬性值 + ', ' + name屬性值
function createModule(str1,str2) {
	var newObj = {
		greeting:str1,
		name:str2,
		sayIt:function(){
			return  this.greeting+', '+this.name; //注意this
		}
	}
	return newObj;
} 
           題目描述
輸入例子:
var C = function(name) {this.name = name; return this;}; var obj1 = new C('Rebecca'); alterObjects(C, 'What\'s up'); obj1.greeting; 
            輸出例子:
What's up
function alterObjects(constructor, greeting) {
	constructor.prototype.greeting = greeting;
}
 
           原型鏈:bhggg
題目描述 考察:遞歸 arguments.callee()函數
function fibonacci(n) {
    if(n==1||n==2) {
    	return 1;
    } else {
    	return arguments.callee(fibonacci(n-1))+arguments.callee(fibonacci(n-2));
    }
}
 
            注意: 函數遞歸應該始終使用 argument.callee來遞歸調用自身,不要使用函數名-----函數名可能會變化.
閉包
先來講一講"作用域"的概念,再了解閉包是什么."作用域",舉個例子,簡單來說就是,外部函數包含內部函數,內部函數可訪問外部的變量,而外部的卻不能訪問內部的.在函數中訪問一個變量時,就會從作用域中搜索具有相應名字的變量,作用域鏈本質上是 一個指向變量對象的指針列表,訪問是線性的有次序的. 閉包會攜帶包含它的函數的作用域,內部函數可以訪問外部環境變量對象.但是閉包也因比其他函數占用更多的內存帶來了不好的一面,應慎重使用閉包.
函數中聲明的變量是局部變量,在函數外部是沒有辦法訪問的.下面拿自增的舉例
function box(){
	var age = 100;
	return age;
}
alert(age);   // "Uncaught ReferenceError: age is not defined"
 
            而利用閉包可以返回局部變量:
//使用匿名函數實現局部變量駐留內存
function box() {
	var age = 100;
	return function(){
		age++;
		return age;
	};
}
var b = box();
alert(b());   //100
alert(b());   //101
alert(b());   //102
alert(b());   //103
alert(b());   //104
b = null; //解除引用,等待垃圾回收
 
            
