說在前面 :
我們定義函數(shù)有兩種方式:1.函數(shù)聲明式 2.函數(shù)表達式
函數(shù)聲明式:存在函數(shù)聲明提升,所以可以在聲明之前調(diào)用
sayHi() //hi
//函數(shù)聲明式
function sayHi(){
console.log('hi')
}
函數(shù)表達式:在使用前必須被賦值
sayHi() //報錯
//函數(shù)聲明式
var sayHi = function(){
console.log('hi')
}
1.遞歸
說明:遞歸函數(shù)就是函數(shù)自己又調(diào)自己的情況 ,使用遞歸實現(xiàn)階乘 :
function factorial(num){
if(num <= 1){
return 1;
}else{
return num * factorial(num-1)
}
}
但是這樣,會有一種情況,執(zhí)行下面代碼時,中間把函數(shù)factorial賦值為null,遞歸調(diào)用時內(nèi)部的factorial已經(jīng)不函數(shù)了 ,報錯,解決方式是用argument.calee,他會指向正在執(zhí)行的函數(shù) (嚴格模式無法使用)
var fun = factorial;
factorial = null
alert(fun(4))
2.1閉包
說明:閉包是啥?是有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù),常見閉包方式,一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù),內(nèi)部函數(shù)訪問了外部變量
function createFunction(property){
return function(obj1,obj2){
var val1 = obj1[property];
var val2 = obj2[property];
if(val1>val2){
return 1;
}else{
return -1;
}
}
}
// 創(chuàng)建函數(shù)
var compare = createFunction('name')
// 調(diào)用函數(shù)
var result = compare({name:"nike"},{name:'grays'})
// 解除對匿名函數(shù)的引用
compare = null
內(nèi)部匿名函數(shù) 使用著外部函數(shù)的參數(shù),是可以使用到的,原因涉及到作用域鏈的問題 ,一個函數(shù)被調(diào)用時,會創(chuàng)建一個執(zhí)行環(huán)境和相應(yīng)的作用鏈,,使用argumens和其他命名參數(shù)初始化活動對象,它的外部函數(shù)的對象處在第二位,依次往外類推
2.2閉包與變量
因為保存的是整個變量對象,不是某個特殊的值,會造成一個問題,閉包只能取到函數(shù)中任何變量的最后一個值
我們看下面的例子
function createFun(){
var result = new Array()
for(var i = 0;i < 10;i++){
result[i] = function(num){
// return function(){
return num
// };
}
}
return result;
}
數(shù)組的每一項都是一個函數(shù),兒每個函數(shù)內(nèi)部存儲的值均為 循環(huán)結(jié)束時的10,解決方法 我們可以利用函數(shù)的自執(zhí)行保存每一個值
function createFun(){
var result = new Array()
for(var i = 0;i < 10;i++){
result[i] = (function(num){
return function(){
return num
};
}(i))()
}
return result;
}
console.log(createFun()) //[0,1,2...9]
2.3 關(guān)于this指向
在閉包中,我們返回的是一個匿名函數(shù),匿名函數(shù)的執(zhí)行環(huán)境是全局的,所以該匿名函數(shù)里的this 是通常指向window,一般下面的情況 ,this就指向window
var name = "window";
var obj ={
name :"obj",
getName : function(){
return function(){
return this.name
}
}
}
console.log("name====>",obj.getName()()) //window
想要this指向調(diào)用方法的對象,我們可以在return匿名函數(shù)之前定義一個屬性保留this指向
var name = "window";
var obj ={
name :"obj",
getName : function(){
var that = this
return function(){
return that.name
}
}
}
console.log("name====>",obj.getName()()) //obj
2.4 內(nèi)存泄漏
因為內(nèi)部函數(shù)始終使用著外部的屬性或者元素,意味著元素無法釋放而被銷毀,我們有必要在使用結(jié)束后,將其設(shè)為null,具體見2.1
3.模仿塊級作用域
原因:
1.js中不存在塊級作用域
2.只要在變量定義在函數(shù)的活動對象里,在函數(shù)內(nèi)部隨處可以調(diào)用
3.多次聲明不會報錯,對后面的聲明忽略
方法:匿名函數(shù)模仿塊級作用域
(function(){
//塊級作用域
})()
實例:
function kuai(count){
(function(){
//塊級作用域
for(var i = 0;i < count;i++){
alert(i)
}
})()
alert(i) //出了塊級作用域 i undefined
}
4.私有變量
js沒有私有成員的概念,每個屬性都是對象共有的。但是js有私有變量的定義。任何定義在函數(shù)中的變量,都是私有變量,如果我們再函數(shù)內(nèi)部創(chuàng)建一個閉包,閉包通過自己的作用域鏈訪問函數(shù)私有變量,
我們把能訪問私有變量&私有方法的公有方法稱為特權(quán)方法
function myObj(){
// 私有變量 私有函數(shù)
var priPropoty = 10;
function priFunction(){
return false
}
//特權(quán)方法
this.pubFunction = function(){
priPropoty++;
return priFunction();
}
}