前言
上次牛客网作到这样一个题,很是有意思,陷阱很是多,当时以为搞明白了,如今再看到,又糊涂了,发现了新的点,看一下:函数
var foo={n:1}; (function (foo) { console.log(foo.n); foo.n = 3; var foo = {n:2}; console.log(foo.n); })(foo); console.log(foo.n);
乍一看,是局部和全局变量的一些区分问题,其实坑不少,下面咱们一点点分析下;lua
变量的定义(宣告)和赋值
首先咱们看一段代码:指针
var a = 1; var a; console.log(a);//1
这里第二行对a是一个重复宣告,而不是赋值,变量只有定义(宣告)后未赋值的状况下才会输出undefined,除非手动赋值undefined;那么这里,JS引擎对于重复宣告的规定以最近的变量指定(也就是赋值)做为变量在执行时的值,因此第二行的var a;其实至关于无效;code
函数中形参和局部变量同名
在咱们本身写代码时,通常不会作这种蠢事情,把形参和局部变量定义为同名,可若是真的这样作了呢?
那就要分析下JS执行上下文中的变量对象了,这个知识点不牢固的同窗能够移步这里:重拾ECMAScript基础——变量、做用域;
做用域链对变量的保存都是在变量对象中的,那么ES5对形参在变量对象中是如何保存的呢,请看规范:对象
10.5 Declaration Binding Instantiation
Every execution context has an associated VariableEnvironment. Variables and functions declared in ECMAScript code evaluated in an execution context are added as bindings in that VariableEnvironment‘s Environment Record. For function code, parameters are also added as bindings to that Environment Record.ip
就是说,不管是形参仍是函数中声明的变量,JS对他们的处理是没有区别的,都是保存在这个函数的变量对象中做为局部变量进行处理;那么结合上面咱们说到的变量的重复宣告,接下来同名的问题就很简单了,看代码:内存
(function fun (param) { var param; console.log(param);//1 param = 2; console.log(param);//2 })(1);
在这里,同名的局部变量和形参实际上是同一个东西,都是在函数的变量对象里的保存的那个变量;ci
若是变量是引用类型呢?
那么若是变量是个对象的话,就是咱们文章一开始提到的题目了,下面咱们分析下:作用域
var foo = {n : 1}; (function(foo) { console.log(foo.n); foo.n = 3; var foo = {n : 2}; console.log(foo.n); })(foo); console.log(foo.n);
var foo = {n : 1}; function fun(foo) { var foo; console.log(foo.n); foo.n = 3; foo = {n : 2}; console.log(foo.n); }; fun(foo); console.log(foo.n);
上下两段代码,意思是同样的,我把匿名当即执行函数换成了普通函数并在下一行调用,方便你们理解;io
其实分析一下,就是这么几个问题;
内部foo变量提高;
内部foo和形参同名;
内部foo重复宣告;
因此内部var的那个foo和形参foo是同一个东西,并无发生变化;
而后重复宣告不影响以前的赋值,因此第一个为1;
接下来,foo.n=3,因为形参为对象,因此是传进来的是一个对象的引用(指针);
对这块知识点不牢固的同窗仍是请移步我以前那篇文章;
那么这个引用指向的堆内存的那块空间里的n改变为3;
接下来,foo={n:2};这个就颇有意思了,咱们刚才也说了,传进来的是个引用;
如今给这个引用赋值,实际上就是让它指向新开辟的空间,存放着{n:2}这个对象;
那么以前的引用就断掉了,也就是说形参foo已经不指向全局里那个foo指向的空间了;
当然,在函数里,会输出新空间里的2;
而在函数外,旧空间仍然没有改变,故为3;
总结
其实这个题目考了不少知识点,最后就是参数传递中引用类型的用法,这个也是ECMAScript中基础的一个难点,结合前面的一些,变量提高,重复宣告,形参与局部变量同名,算是解释清楚了。
如有错误,欢迎指出。