函数表达式
- 定义函数的方式有两种:
- 函数声明
sayHi(); function sayHi() { alert('hi'); }
- 函数表达式
var functionName = function(a,b,c){}
- 注意
- 匿名函数
- 使用前必须先赋值
//错误代码
sayHi();
var sayHi = function() {
alert('hi');
}
//另一个例子
var sayHi; //如果不赋值在js中属于无效语法
if(condition) {
sayHi = function() { alert('hi');}
}else {
sayHi = function() { alert('aha');}
}
递归
- 问题1
var diguiA = digui; digui = null; alert(diguiA(4));
-
arguments.callee
是一个指向正在执行的函数的指针,以此来替代函数名,调用函数。
-
问题2
严格模式下,访问这个属性会产生错误
- 解决(命名函数表达式)
var digui = (function d(num) { if (num <= 1) { return 1; } else { return num * f(num-1); } })
闭包
有权访问另一个函数作用域中的变量的函数。
创建闭包的常用方式,就是在一个函数内部创建另一个函数。
function out(outX) {
return function (object1,object2) {
var a = object[outX]
var b = object[outX]
//函数代码
}
}
- 作用域链
- 本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。
- 在创建A()函数的时候,会创建一个预先包含全局变量的作用域链,这个作用域链被包含在内部的[[Scope]]属性中。当调用A()函数时,会为函数创建一个执行环境,然后通过啊复制函数的[[Scope]]属性中的对象构建起执行环境中的作用域链。
- 函数执行完后,局部活动对象就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)。
- !!!闭包与此不同!!!另一个函数内部定义的函数回京包含函数(即外部函数)的活动对象添加到他的作用域链中。换而言之,匿名函数可以访问在out()中定义的所有变量。
-
副作用
闭包只能取得包含函数中任何变量的最后一个值
//解决function A() { var result = new Array(); for(var i = 0;i < 10;i++) { result[i] = function(){ return i; }; } }
function A() { var result = new Array(); for(var i = 0;i < 10;i++) { result[i] = function(num){ return function() { return num; } }; } }
-
this对象
匿名函数的执行环境具有全局性,因此其this对象通常指向window。
-
内存泄漏
闭包的作用链中包含html元素
模仿块级作用域
- JS没有块级作用域的概念。JS不会告诉你是否多次声明了同一个变量,他会对后续的声明视而不见但会执行初始化。
- 这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中的所有变量。
function A(count) { for(var i = 0;i < count;i++) { alert(i); } alert(i); }
- 实现
(function() { //这里是块级作用域 })(); var A = function () { //这里是块级作用域 } A();
私有变量
- JS中没有私有成员的概念,所有对象属性都是共有的。
- 私有变量:定义在函数中的变量。
- 特权方法:有权访问私有变量和私有函数的公有方法。
-
静态私有变量
在一个私有作用域下,定义私有变量或函数。
- 模块模式
- 为只有一个实例的对象创建私有变量和特权方法
- 如果必须创建一个对象并以某些数据对其进行分初始化,同时还要公开一些能够访问这些私有数据的方法,那就可以使用模块模式。
var A = { name : value, method : function () { //这里是方法的代码 } }
-
增强的模块模式
在返回对象之前加入对其增强的代码。比如,能够访问私有变量的公有方法。