function foo(){
function bar(a){
i = 3;
console.log(i)
}
for(var i = 0;i<10;i++){
bar(i);
}
}
foo()//结果是死循环
下面这段代码只是将foo的参数改了一下
function foo(){
function bar(i){
i = 3;
console.log(i)
}
for(var i = 0;i<10;i++){
bar(i);
}
}
foo()//结果是死10个3
想不明白??????
众所周知,js中变量的基本类型和引用类型保存方式是不同的,这也就导致变量复制时也就不同了。如果从一个变量向另一个变量复制基本类型的值时,会将前者的值克隆一个,然后将克隆的值赋值到后者,因此这两个值是完全独立的,只是他们的value相同而已。
你下面那个Function bar(i)找的是i的克隆,没有对i产生影响
第一个代码中bar函数内没有声明i变量,在bar函数内使用的i是外层作用域中的循环变量i,循环变量每次都重新赋值为3当然死循环了。
只要用var在bar函数内声明自己的i变量就可以了,
var i = 3;
第二个代码中bar函数的参数名改成了i,就等同用var在bar函数内声明了自己的i变量
js会提升局部变量作用域到函数的开头
所以你的第一个函数相当于这样子
function foo(){
var i
function bar(a){
i = 3;
console.log(i)
}
for(i = 0;i<10;i++){
bar(i);
}
}
更改之后相当于这样
function foo(){
function bar(a){
a = 3;
console.log(a)
}
for(var i = 0;i<10;i++){
bar(i);
}
}
JavaScript传递参数是按值传递的,基本类型的传递如同基本类型变量的复制一样
第一段代码,内外部变量 i,是同一个,运行时每次都会赋值3,恒小于10。
function foo(){
function bar(a){
i = 3; // 这里的i跟外面是同一个
console.log(i)
}
for(var i=0; i<10; i++){
bar(i);
}
}
第二段代码,bar函数内的变量i,每次都赋值为3,所以才会输出10个3。
function foo(){
function bar(i){
i = 3; // 这里的i是bar函数体内的,但每次都赋值3
console.log(i)
}
for(var i=0; i<10; i++){
bar(i);
}
}
foo()
根据程序结构可知,作用链时window-foo-bar;
1.js变量的查询时沿着作用链进行查找的
2.变量会在方法结束时销毁
3.当作用域链中出现多个同名变量时,自己作用域中的变量优先级高
分析第一个函数:
foo作用域中有变量 i;
bar作用域中有变量 a,i
当程序执行时,它会沿着window-foo-bar链去查找变量i,由于在bar作用域中没有定义i(没有var i,i变量也没
有在形参中),所以它使用的是foo作用域中的i,所以程序每次赋值时,实际赋的是foo作用域中的i,因此出现
死循环。
而在第二段程序中,i变量出现在了bar的形参中,也就是相当于在bar作用域中创建了变量i,因此在window-foo-bar
链中查找是是给bar作用域中的变量赋值,而bar中的i在bar执行结束后就销毁了,与foo作用域中的i没有任何关系,而foo
循环中使用的是foo变量,因此循环十次。
关键要弄清楚参数传递意味着什么
在执行bar(i)的时候,实际上存在着一个隐式赋值,即 var 形参 = 你传的实参,所以在当第一次循环(i=0)时,
第一串代码的bar(i)实际上可以理解为:
bar(){
var a = 0;
i = 3;
console.log(i)
}
bar()
在执行i = 3会进行变量查找(查找i的声明),最近的i是在for循环中声明的,于是查找到的i就是for循环中的i,然后将i赋值为3,同时for循环中的i也是3,于是就是死循环了,而a其实只是个迷惑。
同样在第一次循环(i=0)时,第二串代码可以理解为:
bar(){
var i = 0 ;
i = 3;
console.log(i)
}
bar()
在执行i = 3会进行变量查找(i的声明),最近的i是在for循环中声明的,于是查找到的i就是bar中的i,然后将i赋值为3,而for循环的i并不受影响,因为他们不是一个i,所以for循环正常进行
function foo(){
function bar(a){
a= 3; // 将i改成a好理解一点
console.log(a)
}
for(var i = 0;i<10;i++){
bar(i);
}
}