作为传入参数的变量的作用域
发布于 12 年前 作者 willwen 7997 次浏览 最后一次编辑是 8 年前

今晚在写connect的Response Pipelining的时候发现,若在函数内把该函数的传入参数进行重新定义的时候,该对象的指针不会起作用,即函数以外的那个传入的对象不会受影响。

var foo = "foo";
function reset (arg) {
    arg = "bar";
    console.log(arg);
}
reset(foo);   //  bar
console.log(foo);    //   foo

大家来讨论下。

27 回复
var array= [1,2];
function reset (arg) {
    arg.push(3);
    console.log(arg);
}
reset(array);   //  [1,2,3]
console.log(array);    //   [1,2,3]

嗯,若只是调用参数方法来改变参数值是有效的,只有直接对参数赋值会出现该问题。应该说是特性吧。

@WillWen 哦去,你也是夜猫子!再看看这个,放在一块看更有意思

var foo = "foo";
function reset () {
    foo= "bar";
    console.log(foo);
}
reset(foo);   //  bar
console.log(foo);    //   bar

很多语言里面都有这样的现象或者说问题,

似乎叫做值参数, 引用参数这样的概念吧.

@WillWen 的例子是值参数的情况, 传递的是一个简单类型, 比如字符串, 数字等

@sumory 的例子在node中估计是引用参数的例子, 所以会改变原变量值.

就我所接触到的语言范围来看, 对象这种一般都是引用参数

  • 有传值、传引用和查找,js是查找,这个跟java等面向对象的语言有很大不一样
  • 具体得搞清楚作用域和原型链

@sumory 原来都木有睡啊.

@sumory 嗯, 你说的是.

实际上可以这样理解:当我们运行某个函数并传入参数时,解析器就会新生成一个映像,这个映像拥有所以对应原传入参数各属性的getter(而没有setter),因为对象的方法处在该函数的作用域之外,所以方法中对该对象的重新赋值是有效的,而在函数作用域内的参数是没有setter的,故set动作无效。 PS:这就是为什么Backbone会选择用方法来改变值,而不是直接使用对象字面量。

@sumory 解析器现在该函数的代码块(作用域)内寻找foo,找不到后就会冒泡到上一层(即进程层)查找,找到了然后对它赋值。

arg 是一个引用而不是一个指针.

js中有指针的概念?貌似没有吧

我指的是这个引用的值指向,一种单向获取值而不能赋值的引用。。坑爹啊,要把一系列中间件改一遍。。

@WillWen 玩不同的语言有时会被它的特性所吸引,有时也会被折磨…

js 中 数组和对象师引用的 你的例子中foo是字符串 是值传递不是引用传递

var foo = {a:2}; 
function reset(arg) { 
   arg.a = 1; 
   console.log(arg.a); //1
} 
reset(foo); 
console.log(foo.a); //1
var obj = {foo: "foo"};
function reset (arg) {
  arg.foo = "bar";
  console.log(arg.foo);
}
reset(obj);             //  bar
console.log(obj.foo);   //   foo

嗯,凡是在函数作用域意外的东西都不受限制,只有在传参后对参数本身进行赋值才会出现问题。

基本类型传的是值的拷贝,引用类型传的是引用的拷贝。和java一样

这时的obj.boo是bar

这个是正确的,记得字符串只有在赋值的时候是按照引用类型处理。其他时候都是按照值传递。这点在周爱民的那本书里有说明

@olddog js 语言精粹与编程实践 嗯

ECMAScript中的所有参数传递的都是值,不可能通过引用传递传数。

@leolovenodejs 对啊…我没说错呀…

@jin52yang 如果传递的是引用类型的值,这个值其实是不是就是内存地址啊?

@leolovenodejs 不是指针哇,是引用地址而已哇…

@jin52yang 引用地址:即堆内存地址;而这个引用地址是被保存在栈内存中的。 引用传递其实传递的是栈中的值,即值传递,值为堆内存地址。 这么理解对不?

回到顶部