说在前面 :
我们定义函数有两种方式:1.函数声明式 2.函数表达式
函数声明式:存在函数声明提升,所以可以在声明之前调用
sayHi() //hi
//函数声明式
function sayHi(){
console.log('hi')
}
函数表达式:在使用前必须被赋值
sayHi() //报错
//函数声明式
var sayHi = function(){
console.log('hi')
}
1.递归
说明:递归函数就是函数自己又调自己的情况 ,使用递归实现阶乘 :
function factorial(num){
if(num <= 1){
return 1;
}else{
return num * factorial(num-1)
}
}
但是这样,会有一种情况,执行下面代码时,中间把函数factorial赋值为null,递归调用时内部的factorial已经不函数了 ,报错,解决方式是用argument.calee,他会指向正在执行的函数 (严格模式无法使用)
var fun = factorial;
factorial = null
alert(fun(4))
2.1闭包
说明:闭包是啥?是有权访问另一个函数作用域中的变量的函数,常见闭包方式,一个函数内部创建另一个函数,内部函数访问了外部变量
function createFunction(property){
return function(obj1,obj2){
var val1 = obj1[property];
var val2 = obj2[property];
if(val1>val2){
return 1;
}else{
return -1;
}
}
}
// 创建函数
var compare = createFunction('name')
// 调用函数
var result = compare({name:"nike"},{name:'grays'})
// 解除对匿名函数的引用
compare = null
内部匿名函数 使用着外部函数的参数,是可以使用到的,原因涉及到作用域链的问题 ,一个函数被调用时,会创建一个执行环境和相应的作用链,,使用argumens和其他命名参数初始化活动对象,它的外部函数的对象处在第二位,依次往外类推
2.2闭包与变量
因为保存的是整个变量对象,不是某个特殊的值,会造成一个问题,闭包只能取到函数中任何变量的最后一个值
我们看下面的例子
function createFun(){
var result = new Array()
for(var i = 0;i < 10;i++){
result[i] = function(num){
// return function(){
return num
// };
}
}
return result;
}
数组的每一项都是一个函数,儿每个函数内部存储的值均为 循环结束时的10,解决方法 我们可以利用函数的自执行保存每一个值
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 关于this指向
在闭包中,我们返回的是一个匿名函数,匿名函数的执行环境是全局的,所以该匿名函数里的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指向调用方法的对象,我们可以在return匿名函数之前定义一个属性保留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 内存泄漏
因为内部函数始终使用着外部的属性或者元素,意味着元素无法释放而被销毁,我们有必要在使用结束后,将其设为null,具体见2.1
3.模仿块级作用域
原因:
1.js中不存在块级作用域
2.只要在变量定义在函数的活动对象里,在函数内部随处可以调用
3.多次声明不会报错,对后面的声明忽略
方法:匿名函数模仿块级作用域
(function(){
//块级作用域
})()
实例:
function kuai(count){
(function(){
//块级作用域
for(var i = 0;i < count;i++){
alert(i)
}
})()
alert(i) //出了块级作用域 i undefined
}
4.私有变量
js没有私有成员的概念,每个属性都是对象共有的。但是js有私有变量的定义。任何定义在函数中的变量,都是私有变量,如果我们再函数内部创建一个闭包,闭包通过自己的作用域链访问函数私有变量,
我们把能访问私有变量&私有方法的公有方法称为特权方法
function myObj(){
// 私有变量 私有函数
var priPropoty = 10;
function priFunction(){
return false
}
//特权方法
this.pubFunction = function(){
priPropoty++;
return priFunction();
}
}