Js函数深入理解-内部属性与递归
函数里面有两个特殊的对象:arguments与this
arguments详解
用于保存参数
function a(num1,num2){
console.log(num1) //123
console.log(num2) //456
console.log(arguments) ?
}
a(123,456)
console.log(arguments) 打印出来是这样的
arguments是个类数组对象,传的参数都存储到这个数组中,因此可以这么访问
function a(num1,num2){
console.log(arguments[0]) //123
console.log(arguments[1]) //456
}
a(123,456)
由此可知,num1,num2两个参数可以不写
有时候我们需要根据参数的个数进行判断它执行哪个条件语句,这时我们可以用到arguments.length这个属性
function a(){
if(arguments.length == 1){//传一个参数时执行
console.log(arguments[0]);
}
if(arguments.length == 2){//两个参数时执行
console.log(arguments[0]+arguments[1]);
}
}
a(10); //10
a(10,20); //30
arguments还有个属性callee,它指向的是函数自己,递归里面用得到
this详解
var name='lisi';
function a(){
console.log(this); //window
console.log(this.name); //lisi
}
a();
简单的说,谁调用a这个函数,this就指向谁。这里的a()可以看成是window.a(),所以this引用的是window
再看下面的例子
var name='lisi';
var str = {name:'zhsan'};
str.a = a;
function a(){
console.log(this); //Object {name: "zhsan"}
console.log(this.name); //zhsan
}
str.a();
这里把函数赋给对象str,因此str调用a时,this指向的是str这个对象。
注意:函数名只是个指针,window.a()与str.a()都指向的是同一个函数
apply()与call的用法
函数有两个参数,第一个是作用域(全局或者个别对象),第二个是数组/对象
function sum(num1, num2){
return num1 + num2;
}
function callSum1(num1, num2){
return sum.apply(this, arguments); // 传入 arguments对象
}
function callSum2(num1, num2){
return sum.apply(this, [num1, num2]); // 传入数组
}
console.log(callSum1(10,10)); //20
console.log(callSum2(10,10)); //20
这里的this指向谁呢?指向sum这个函数??
NO!,callSum1(10,10)调用它的是全局对象,因此this指向window
注意:在严格模式下,未指定环境对象而调用函数,则 this值不会转型为 window。除非明确把函数添加到某个对象或者调用apply()或call(),否则this 值将是undefined。
apply与call强大之处是扩展作用域,简单的说指定执行该函数的环境
前面的例子可以改成下面:
var name='lisi';
var str = {name:'zhsan'};
function a(){
console.log(this.name);
}
a.call(this) //lisi
a.call(window) //lisi
a.call(str) //zhsan
函数递归
例子:
function sum(x){
if(x<1){
return x;
}
return x+sum(x-1);
}
console.log(sum(10)) //55
再看下面例子
function sum(x){
if(x<=1){
return 1;
}
return x+sum(x-1);
}
var test = sum;
sum = null; //销毁这个函数名
console.log(test(10)) //Uncaught TypeError: sum is not a function
但如果写成这样:
function sum(x){
if(x<=1){
return 1;
}
console.log(this)
return x+arguments.callee(x-1);
}
var test = sum;
sum = null;
console.log(test(10)) //55
之前提到过arguments.callee的callee属性,它指向函数本身,sum被销毁,只是销毁名字,而函数依然存在
因此写递归的话使用arguments.callee比较好,但是在严格模式下不能访问arguments.callee这个属性,因此也会报错。
下面是最完善的写法:
var sum = (function f(x){
if(x<=1){
return 1;
}
return x+f(x-1);
})
var test = sum; //已经把test指向了f(x)
sum = null; //销毁后并不影响 test
console.log(test(10)) //55