function的特殊性用法和其变量
一、内部对象
1、arguments
arguments对象用于访问函数参数列表 , 我们知道 ECMAScript 中函数是不在乎参数类型和参数数量的(函数最大能接受的参数数量是 ?),这一切都要归功于 函数的参数是一个数组 , 而函数接收到的始终是这个参数数组 , arguments对象可以访问这个数组 , 我们可以用方括号语法访问数组的每一个元素(函数参数)
function arg(test1,test2) {
console.log(arguments.length); // 2
console.log(arguments[0]); // ->test1的值 = 1
}
arg(1,2);
arguments.callee 属性
该属性是一个指针 指向的是 拥有这个arguments对象的函数 在上例中即是 arg(),为什么会有这个属性,一部分原因是所有函数名都是指向引用的引用 ,并不是引用本身。一下代码
function factor(num) {
if(num<=1){
return 1;
}else{
return num * arguments.callee(num-1); //如果改为factor(num-1) 会发生什么?
//arguments的callee属性指向的是factor(callee 的父亲arguments的拥有者)
}
}
var factory = factor;
factor = function () {
return 0;
}
console.log(factor(5));
console.log(factory(5));
2、函数属性和方法
caller 、这个属性保存着调用当前函数的函数的引用,一个比较好用的方法是可以使用caller属性 找到调用当前函数的函数的源码
function outer(){
console.log("你能不能看见我?");
inner();
}
function inner() {
console.log(inner.caller.toString());//看看这里是什么?
console.log(inner.arguments.callee.toString());
}
outer();
//输出结果 console.log(inner.caller.toString());
function outer(){
console.log("你能不能看见我?");
inner();
}
// console.log(inner.arguments.callee.toString());
function inner() {
console.log(inner.caller.toString());
console.log(inner.arguments.callee.toString());
//console.log(inner.length + "-------" +inner.prototype.toString());
}
apply()和call()方法
这两个方法的作用是在特定的作用域中调用函数,实际上等于设置函数体的this,它们有两个参数 一个是 函数执行的作用域(如this),另一个是函数的参数数组。
window.color = "red";
var o = {color:"blue"};
function sayColor(){
console.log(this.color);
}
sayColor.call(this);
sayColor.apply(o);
二、闭包和匿名函数
函数作用域链:当某个函数被调用时,会创建一个执行环境以及相应的作用域链,初始化函数内的对象使用的是 arguments和其他参数函数。但是在作用域链中,外部函数的活动对象始终是处于第二位的,外部函数的外部函数的活动对象处于第三位。。。
闭包: 如果一个函数A访问另一个函数内部B的属性(函数A称为闭包)
那么函数A必然会将函数B的作用域添加到函数A的作用域链中,当函数B执行完成后,其执行环境的作用域链会被销毁,但是函数B的活动对象依然会被留在内存中,因为函数A仍然在引用B的活动对象,直到A被销毁后,B的活动对象才会被销毁。代码:
function createfunctions(){
var results = [];
for(var i=0;i<10;i++){
results[i] = function () {
return i;
};
}
console.log(results.toString());
}
createfunctions();
这段代码的输出结果 为10个相同的函数
function () {
return i;
},function () {
return i;
}....
函数数组的返回值并不是 从0到9 ,这10函数的返回值全部都是10.
因为这是个函数引用的是同一个变量 i ,最后i的值变为了10,虽然,在for循环执行完之后,createFunctions函数的执行函数会被销毁,但是i的值却仍然在内存中,因为有匿名函数正在调用i,所以最后10个函数的输出值全部都是10。
改进方法
function createfunctions(){
var results = [];
for(var i=0;i<10;i++){
results[i] = function () {
return i;
}();
}
console.log(results.toString());
}
createfunctions();
这里使用了匿名函数自调用在每一次for循环的同时,将执行function(){return i}(),虽然i仍然还是在内存中,并且还是等于10,但是数组result现在并没有再引用这个i。
- 匿名函数和闭包之间的区别
var name = "window";
var object = {
name:'objectName',
getName:function () {
var name = this.name;
return function () {
console.log(this.name); //undefined
console.log(name);
return name; //输出objectName
};
// 箭头函数 更改了this的指向函数的调用者 object
// return ()=>{
// console.log(this.name); 输出objectName
// return name; //输出window
// 函数的作用链域中:
// 外部函数的活动对象处于第二位,外部的外部函数处于第三位,根本不会去找到object对象的name
// };
}
};
// 是里面的匿名函数 function(){}
console.log(object.getName().toString());
// 执行这两个 匿名函数
console.log(object.getName()());