函数内部属性 — this & arguments

 函数调用时,JS引擎会在函数体内为本地作用域添加两个特殊变量:this、arguments。


this 对象

[ 执行环境和作用域?!] 函数体内,this 是指:函数的执行环境对象( 也叫 context,上下文对象 )。

一般来说,this 指向调用函数的对象,如果没有就是全局对象,在浏览器中就是 window 对象。

var sum = function(){
	// 严格模式下是 undefined
	// 非严格模式下是 Window
	console.log(this);
}

var obj = {
	sum:function(){
		// this 为 obj 对象
		console.log(this);
	}
}
obj.sum();

[ this 绑定机制?!实际上,函数调用不同模式之间的本质区在于:函数本地作用域上的 this 变量的指向上。

  • 函数调用模式:this 指向全局对象
  • 方法调用模式:this 指向调用者
  • 构造函数调用模式:this 指向被构造的对象
  • 间接调用模式:this 指向第一个参数

arguments 对象

JS 中的参数在内部用一个数组表示。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数。

在函数体内,可以通过arguments 对象来访问这个参数数组,从而获取传递给函数的每一个参数(实参)。

简单讲,函数体内,arguments 表示实参列表对象,是一个类数组对象,可通过下标访问对象的实参值。

// arguments对象并不是Array的实例,它是一个类数组对象,可以使用方括号语法访问它的每一个元素。

function sum(a,b){
	return arguments[0] + arguments[1];
}
console.log(sum(1,2));  // 3

[ callee 属性 ] arguments 对象的 callee 属性,是一个指针,指向拥有这个 arguments 对象的函数。

下面是经典的阶乘函数
function factorial(num){
    if(num <=1){
        return 1;
    }else{
        return num* factorial(num-1);
    }
}    
console.log(factorial(5));  // 120

但是,上面这个函数的执行与函数名紧紧耦合在了一起,可以使用arguments.callee可以消除函数解耦

function factorial(num){
    if(num <=1){
        return 1;
    }else{
        return num* arguments.callee(num-1);
    }
}    
console.log(factorial(5));  // 120

但在严格模式下,访问这个属性会抛出TypeError错误
function factorial(num){
    'use strict';
    if(num <=1){
        return 1;
    }else{
        return num* arguments.callee(num-1);
    }
}    
//TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
console.log(factorial(5));

这时,可以使用具名的函数表达式
var factorial = function fn(num){
    if(num <=1){
        return 1;
    }else{
        return num*fn(num-1);
    }
};    
console.log(factorial(5));//120

[ caller属性 ]                                                                 // 有点像 super,实际上有两个 caller 属性

  • 函数的caller:保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值是null
function outer(){
    inner();
}
function inner(){
    console.log(inner.caller);//outer(){inner();}
}
outer();

function inner(){
    console.log(inner.caller);//null
}
inner();

在严格模式下,访问这个属性会抛出TypeError错误
function inner(){
    'use strict';
    //TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context
    console.log(inner.caller);
}
inner();
  • arguments 对象的 caller

该属性始终是 undefined,定义这个属性是为了分清 arguments.caller 和函数的 caller 属性;同样地,在严格模式下,访问这个属性会抛出 TypeError 错误。


// 拓展理解 — 函数重载:JS 函数不能像传统意义上那样实现重载。

在其他语言中,可以为一个函数编写两个定义,只要这两个定义的签名( 接受的参数的类型和数量 )不同即可。

JS函数没有签名,因为其参数是由包含0或多个值的数组来表示的,而没有函数签名,真正的重载是不可能做到的。

// 后面的声明覆盖了前面的声明
function addSomeNumber(num){
    return num + 100;
}
function addSomeNumber(num){
    return num + 200;
}
var result = addSomeNumber(100);//300

只能通过检查传入函数中参数的类型和数量并作出不同的反应,来模仿方法的重载。

function doAdd(){
    if(arguments.length == 1){
        alert(arguments[0] + 10);
    }else if(arguments.length == 2){
        alert(arguments[0] + arguments[1]);
    }
}
doAdd(10);//20
doAdd(30,20);//50