arguments
- 函数的实参被保存在一个类似数组的arguments对象中。
arguments
变量只是 ”类数组对象“,并不是一个数组。称其为类数组对象是说它有一个索引编号和Length
属性。尽管如此,它并不拥有全部的Array对象的操作方法。- 函数参数的默认值是
undefined
。 - 参数支持设置不同的默认值:function test(arg1, arg2 = 5) {}。
- 原始参数(比如一个具体的数字)被作为值传递给函数。
- 对象参数,传递的是对象的应用。
常用:
- arguments[n]
- arguments.length
- arguments.callee(ECMAScript (ES5) forbids use of
arguments.callee()
in strict mode.)
递归函数
形式1: 通过使用函数名
function factorial(num){ if(num <=1) { return 1; } else { return num * factoral(num-1); } };
缺点:
var anotherFactorial = factorial; factorial = null; alert(anotherFactorial(4)); //VM367:5 Uncaught ReferenceError: factoral is not defined
function factorial2(num){ if(num <=1) { return 1; } else { return num * arguments.callee(num-1); } }; var anotherFactorial = factorial2; factorial2 = null; alert(anotherFactorial(4)); //24
闭包与变量
- 假设,函数A内部声明了个函数B,函数B引用了函数B之外的变量,并且函数A的返回值为函数B的引用。那么函数B就是闭包函数。
- 内部函数可以访问定义在外部函数中的所有变量和函数,以及外部函数能访问的所有变量和函数。
- 当内部函数生存周期大于外部函数时,由于内部函数可以访问外部函数的作用域,定义在外部函数的变量和函数的生存周期就会大于外部函数本身。
特点:
- 函数定义时的作用域链到函数执行时依然有效
- 闭包只取得包含函数中任何变量的最终值
形式1:
function func1() { var result = new Array(); for (var i = 0; i < 10 ;i++) { result[i] = function(){ // 外部函数变量得生命周期大于函数本身,闭包取到的总是外部函数最后的变量值 10 return i; } }; return result; }; res = func1(); res[1](); //10 res[9](); //10
形式2:
function func2() { var result = new Array(); for (var i = 0; i < 10 ;i++) { result[i] = function(num){ return function(){ return num; } }(i); // 创建一个匿名函数并立即执行,将执行结果赋值给变量,匿名函数的参数复制i的值并又在它的闭包中保持 }; return result; }; res = func2(); res[1](); //1 res[9](); //9
this对象
this对象是在函数运行时基于函数执行环境绑定的:
- 在全局函数中,this等于window。
- 函数作为某个对象得方法调用时,this等于那个对象。
- 匿名函数的执行环境具有全局性。
this等于window示例:
/* 每个函数在被调用时,会自动获取两个特殊变量:this、arguments 内部函数在搜搜这两个变量时只会搜索到其活动对象为止 因此永远不可能直接访问外部函数中的这两个变量 */ var name = "the Window"; var object = { name: "the Object", getNameFunc: function(){ return function(){ return this.name; } } }; alert(object.getNameFunc()()); //the Window
this等于Object, that等于this示例:
var name = "the Window"; var object = { name: "the Object", getNameFunc: function(){ that = this; //getNameFunc作为object的方法,在getNameFunc中this等于object return function(){ return that.name; } } }; alert(object.getNameFunc()()); //the Object
模仿块级作用域
javascript没有块级作用域:
function outputNumbers(count){ for (var i=0; i < count; i++) ; //do nothing alert(i); //块语句中定义的变量,在所在函数内都有效 }
模拟块级作用域:
function outputNumbers(count) { (function(){ for (var i = 0; i<count; i++){ alert(i); } })(); //定义匿名函数并立即执行,执行完后其定义的变量也会销毁 alert(i); //VM1909:7 Uncaught ReferenceError: i is not defined }
访问私有变量
普通方式:
特点:
- 私有变量 name 在所有实例中都不同
- 每一个实例都会重新创建同样的一组私有方法(缺点)
function MyObject(){ //私有变量 var privateVariable = 10; //私有方法 function privateFunction(){ return false; } //特权方法 this.publicMethod = function(){ privateVariable++; return privateFunction(); } } var test = MyObject(); test.publicMethod(); //访问私有变量
静态私有变量:
特点:
- 只有1个私有作用域
- 特权方法是在原型上定义的,因此所有实例都使用同一个函数
- 特权方法,作为一个闭包,总是保存着对包含作用域的引用
- 由1和3结合,所以任何一个实例改了私有变量,所有实例都感应变化
var Person; (function(){ var name = ""; Person = function(value){ name = value; }, Person.prototype.getName = function(){ return name; }, Person.prototype.setName = function(value){ name = value; } } )(); var person1 = new Person("Nicholas"); alert(person1.getName()); //Nicholas var person2 = new Person("Michael"); alert(person1.getName()); //Michael alert(person2.getName()); //Michael
call()和apply()
- call( thisArg[, arg1, arg2, ...]); //参数列表
- call( thisArg[, argArray ]); //参数数组
两个函数内部的this指针,都会被赋值为 thisArg 对象,这可实现将函数作为另外一个对象的方法运行的目的。
obj = { x: 2, y: 5 }; function func(){ return this.x * this.y; } func.call(obj); // 10 func.apply(obj); // 10