一、定义方式
- function语句式:可以提前调用,对于function语句式的函数,JavaScript解析器会优先解析。
- 函数的直接量
- function构造函数式var f = new Function(“a”,”b”,”return a+b;”); (括号内是参数加函数体)此方式,效率创建效率较低,但内存占用较少。
对比三种方式:
关于解析顺序的一个例子:
function f() {
return 1;
};
alert(f()); // 4
var f = function () {
return 2;
};
alert(f()); //2
var f = new Function("return 3;");
alert(f()); //3
function f() {
return 4;
};
alert(f()); //3
var f = function () {
return 5;
};
alert(f()); //5
var f = new Function("return 6;");
alert(f());
关于作用域的一个例子:
var k = 1;
var t1 = function () {
var k = 2;
// var test = function () { // 方式1 弹出 2
// return k;
// };
//
// function test() { //方式2 弹出2
// return k;
// };
var test = new Function("return k;"); //方式3 弹出1 因为这是顶级函数 和在t1外面定义的效果一样
alert(test());
};
t1();
二、函数的参数arguments对象
JavaScript中的参数:形参和实参
函数名.length :返回函数形参的个数;
arguments.length: 返回函数实参的个数。(只能在函数内部使用。)
arguments对象使用得最多的场合是 递归操作:
arguments.callee: 表示函数自身。
一个递归操作的例子:
function fact(num){
if(num<=1){
return 1;
}else{
return num*fact(num-1); //安全的做法是:return num*arguments.callee(num-1);
}
}
三、this关键字
this对象是在运行时基于函数的执行环境绑定的。在全局函数中,this等于window,二当函数被作为某个对象的方法调用时,this等于那个对象。
也就是说this关键字总是指代调用者。
四、call和apply方法
每一个函数都包含两个非继承而来的方法:call和apply。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
call、apply的用途之一就是传递参数,但事实上,它们真正强大的地方是能够扩充函数赖以运行的作用域。
使用call()、apply()来扩充作用域的最大好处就是对象不需要与方法有任何耦合关系。
五、执行环境和作用域链
执行环境(execution context)是JavaScript中最为重要的一个概念。执行环境定义了变量或者函数有权访问的其他数据,决定了它们各自的行为。
每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们的代码无法访问这个对象,但是解析器在处理数据时会在后台执行它。全局执行环境是最外围的一个执行环境。根据ECMAScript实现所在的宿主环境(web开发中的JavaScript其宿主环境就是浏览器的window对象了)不同,表示执行环境的对象也不一样。
每一个函数都有自己的执行环境。当执行流进一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返还给之前的执行环境。当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope
chain)。作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问。- 环境变量一层一层向上追溯 可以访问它的上级 环境(变量和函数)
六、垃圾收集和块级作用域
JavaScript中的 () 表示执行;
JavaScript中没有块级作用域,可以用下面的方式模拟块级作用域:
(function () {
for(var i =0;i<3;i++){
// TODO
}
})();
//这样for块里的 i 就相当于块级作用域了。
七、闭包closure
概念:
- 闭包与函数有着紧密的关系,它是函数代码在运行过程中的一个动态环境,是一个运行期的、动态的概念。
- 所谓闭包,是指词法表示包括不必计算的变量的函数。也就是说,该函数能够使用函数外定义的变量。
- 在程序语言中,所谓闭包,是指语法域位于某个特定的区域,具有持续参照(读写)位于该区域内自身范围之外的执行域上的非持久型变量值能力的段落。这些外部执行域的非持久型变量神奇地保留他们在闭包最初定义(或创建)时的值。
简洁明了的概念:一个函数可以访问另外一个函数作用域中的变量。
这样做的目的:封闭性:类似于private,起到一个保护变量的作用。
一个闭包的例子:
var name = "Xiao A";
var obj = {
name:"Xiao B",
getName: function () {
return function () {
return this.name;
}
} ,
getNameClosure: function () {
var that = this;
return function () {
return that.name;
}
}
};
alert(obj.getName()()); //返回值:Xiao A
alert(obj.getNameClosure()()); //返回值:Xiao B obj.getNameClosure()返回的是一个匿名函数,但这个匿名函数可以访问obj.getNameClosure()里的变量。
一个实际应用:
function f(x) {
var temp = x;
return function (x) {
temp += x;
return temp;
}
}
var a = f(50);
alert(a(5));
alert(a(10));
alert(a(20));
八、利用chrome调试工具查看闭包内容
打开chrome开发者工具,在控制台中输入如下内容:(换行时使用shift+enter、直接按enter会执行代码)
//1
function A(a,b,c){
var arr= [a,b,c];
return function B(i){
return arr[i];
}
}
//2
var a = A("大","中","小");
//3
console.log(a(1)); //输出的结果是“中”;
然后我们利用 Watch Expressions 工具查看 函数a是如何使用已经返回的变量arr的
在函数的作用域里我们看到了Closure,里面保存了arr。