JavaScript函数及作用域的小结(4)

由于js中语句结束的分号可以省略,js引擎会认为function(a,b){ return a+b;}是一句语句结束,因此匿名函数只声明了没有被调用,如果语句没有传参(1,2)写成(),还会导致错误,js中空括号是语法错误。

下面这种写法是正确的。

var  ab = function(a,b){ return a+b;}(1,2);  // ab=3

js 解析语法时,如果表达式出现在赋值运算或操作符运算中,是"贪婪匹配"的(尽量求值)

function(t){ return 1+t;}(); //error
var f = function(t){ return t+1;}(); // ok

~ function(t){return t+1;}();  //ok
+ function(t){return t+1;}(); //ok

如果你只是想把一个匿名函数赋给一个变量,记得在赋值语句后面加上分号,否则,如果后面跟了小括号就变成了函数调用了,尤其是小括号与函数结尾之间分隔了多行时,这种错误往往很难发现。

实际开发中,匿名函数可能以运算值的方式返回,这种情况可能不容易看出,比如

var a =1;
var obj = {a:2,f:function(){ return this.a;}};

(1,obj.f)(); //1 逗号表达式反悔了一个匿名函数,当这个匿名函数被调用时,函数体内的 thsi 指向 window

声 明并立即运行匿名函数被称为”自执行函数“,自执行函数经常用于封装一段js代码。由于函数作用域的特点,自执行函数内的变量无法被外部访问,放在函数内 的代码不会对外面的代码产生影响,可以避免造成变量污染。js开发很容易造成变量污染,在开发中经常引入其他编码人员开发的代码,如果不同的编码人员定义 了同名称不同含义的全局变量或函数,便造成了变量污染,同一作用域内出现同名的变量或函数,后来的将覆盖前面的。

(function(){

//自己的代码.....

})();匿名函数还可以使内存及时释放:因为变量被声明在匿名函数内,如果这些变量没有在匿名函数之外被引用,那么这个函数运行完毕,里面的变量所占据的内存就会立即释放。

函数的name:在firefox等浏览器,函数有一个name属性,就是该函数的函数名,但是这个属性在IE中不存在,另外,匿名函数的name为空值。

var a=function(){}
alert(a.name); //undefined,a是一个存储了一个匿名函数的变量
function b(){}
alert(b.name); //b ,but undefined for IE

七、函数被调用时,运行在他被定义时的环境中

无论函数在哪里被调用,被谁调用,都无法改变其被声明时的语法环境,这决定了函数的运行环境。

代码如下:


var x=99;

var inerFun=null;

function fun1(){

alert(x);

}

function holder(){

var x = 100;

var fun2 = fun1;

inerFun = function(){ alert(x);}

fun1(); //99

fun2();//99

inerFun(); //100

}

holder();

fun1(); //99

inerFun(); //100

//另一个例子:

var x = 100;
var y=77;
var a1={
x:99,
xx:function(){
  //var y=88;  //如果注释这个变量,y将是全局变量的77
  alert(y); //没有使用this指针,调用函数的对象无法影响y的值,函数运行时将从这里按作用域链逐级搜索取值
  alert(this.x);  //使用了 this 指针,调用函数的
}
}

a1.xx();
a1.xx.call(window);

var jj = a1.xx;

jj(); //效果跟a1.xx.call(window); 一样//试试下面代码

var x=99;
function xb(){
this.x=100;
this.a = (function(){return this.x}).call(this); //new 的时候执行了,匿名函数被 实例化的对象 调用
this.b = (function(){return this.x})(); //new 的时候执行了,匿名函数被window调用
this.method = function(){return this.x;}
}


var xbObj = new xb();
console.log(xbObj.x);
console.log(xbObj.a);
console.log(xbObj.b);
console.log(xbObj.method());


注意区分调用函数的对象、函数声明时的语法环境、函数调用语句的语法环境这几个概念

1、调用函数的对象(或者说函数的调用方式)决定了函数运行时函数体内的this指针指向谁。

2、函数声明时的语法环境决定了函数运行时的访问权限。

3、函数调用语句的语法环境决定了函数是否真的能够被调用及何时被调用(只有函数在某个语法环境是可见的,这个函数才能被调用)。

函数在运行时,产生一个 arguments 对象可以访问传入函数内的参数,arguments 有一个属性可以指向函数自身:arguments.callee。

函数运行时,函数的 caller 属性可以指向本函数调用语句所在函数,比如,a函数在b函数体内被调用,则当a函数运行时,a.caller就指向了b函数,如果a 函数在全局环境中被调用则 a.caller=null

arguments 和a.caller 的值与函数的每一次调用直接关联,他们都是在函数运行时产生的,只能在函数体内访问。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/ac1c531387274afa27ca18113ddd6789.html