JavaScript是通过引用传递还是通过值传递?

下面是一个来自JavaScript: The Good Parts的例子。我对矩形函数的参数很困惑。它实际上是未定义的,并在函数内部重新定义。没有原始参考文献。如果我从函数参数中删除它,内部区域函数就不能访问它。

它是一个闭包吗?但是没有返回函数。

var shape = function (config) {
    var that = {};
    that.name = config.name || "";
    that.area = function () {
        return 0;
    };
    return that;
};

var rectangle = function (config, my) {
    my = my || {};
    my.l = config.length || 1;
    my.w = config.width || 1;
    var that = shape(config);
    that.area = function () {
        return my.l * my.w;
    };
    return that;
};

myShape = shape({
    name: "Unhnown"
});

myRec = rectangle({
    name: "Rectangle",
    length: 4,
    width: 6
});

console.log(myShape.name + " area is " + myShape.area() + " " + myRec.name + " area is " + myRec.area());

当前回答

你可以这样想:

无论何时在ECMAscript中创建一个对象,这个对象都是在一个神秘的ECMAscript通用的地方形成的,没有人能够得到。你只能得到这个神秘地方的那个物体的参考。

var obj = { };

即使obj也只是对对象的引用(它位于那个特殊的位置),因此,你只能传递这个引用。实际上,任何访问obj的代码段都会修改很远很远的对象。

其他回答

在人们试图证明这一点的例子中,我看不到参考传递。我只看到值传递。

对于包含对象引用的变量,引用就是那些变量的值,因此引用被传递,然后被值传递。

在这样的陈述中,

var a = {
  b: "foo",
  c: "bar"
};

“a”的值不是对象,而是(到目前为止唯一的)对它的引用。换句话说,对象不在变量a中——对它的引用在。我认为这对于只熟悉JavaScript的程序员来说似乎很难。但是对于懂Java、c#和C的人来说,这是很容易的。

与C语言一样,最终,所有内容都是通过值传递的。不像C语言,你不能实际备份和传递变量的位置,因为它没有指针,只有引用。

它所引用的都是对象,而不是变量。有几种方法可以达到相同的结果,但它们必须手工完成,而不仅仅是在调用或声明站点上添加关键字。

函数参数通过值或共享传递,但在JavaScript中从来不通过引用!

"值

基元类型按值传递:

var num = 123, str = “foo”; 函数 f(num, str) { 数字 += 1; str += “bar”; console.log(“inside of f:”, num, str); } f(数字, str); console.log(“Out of f:”, num, str);

函数作用域中的重赋在周围的作用域中是不可见的。

这也适用于string,它是一个复合数据类型,但不可变:

Var STR = "foo"; 函数f(str) { Str [0] = "b";//不起作用,因为字符串是不可变的 Console.log ("in of f:", str); } f (str); Console.log ("outside of f:", str);

Call-by-Sharing

对象,也就是说所有不是基元的类型,都是通过共享传递的。保存对象引用的变量实际上只保存该引用的副本。如果JavaScript采用引用调用求值策略,则变量将保存原始引用。这是共享和引用之间的关键区别。

这种区别的实际后果是什么?

Var o = {x: "foo"}, p = {y: 123}; 函数f(o, p) { O.x = "bar";/ /突变 P = {x: 456};/ /重新分配 Console.log ("o within f:", o); Console.log ("p inside of f:", p); } f (o p); Console.log ("o outside of f:", o); Console.log ("p outside of f:", p);

突变是指修改现有对象的某些属性。变量所绑定的引用副本和引用该对象的引用副本保持不变。因此,突变在调用者的作用域中是可见的。

重赋值意味着替换绑定到变量的引用副本。由于它只是一个副本,持有同一引用副本的其他变量不受影响。因此,重赋在调用者的作用域中是不可见的,就像在引用调用求值策略中那样。

关于ECMAScript中评估策略的进一步信息。

我的两分钱....JavaScript是通过引用还是值传递参数无关紧要。真正重要的是赋值还是变异。

我在这个链接里写了一个更长的,更详细的解释。

当你传递任何东西(无论是一个对象还是一个原语)时,JavaScript所做的只是在函数内部分配一个新变量……就像使用等号(=)一样。

这个参数在函数内部的行为和你用等号赋值一个新变量的行为是完全一样的。举几个简单的例子。

var myString = '测试字符串1'; //赋值-指向myString相同位置的链接 var sameString = myString; //如果我改变了sameString, myString将不会改变, //它只是重新赋值给一个全新的字符串 sameString = '新字符串'; console.log (myString);//记录'测试字符串1'; console.log (sameString);//记录'新字符串';

如果我将myString作为参数传递给一个函数,它的行为就好像我简单地将它赋给了一个新变量。现在,让我们做同样的事情,但是用一个函数而不是简单的赋值

函数myFunc(sameString) { / /重置手术……同样,它不会修改myString sameString = '新字符串'; } var myString = '测试字符串1'; //它的行为与sameString = myString相同 myFunc (myString); console.log (myString);//再次,日志'测试字符串1';

当你将对象传递给函数时,你可以修改对象的唯一原因是你没有重新赋值…相反,对象可以更改或突变....同样,它的工作方式是一样的。

var myObject = { name: 'Joe'; }

// Assignment - We simply link to the same object
var sameObject = myObject;

// This time, we can mutate it. So a change to myObject affects sameObject and visa versa
myObject.name = 'Jack';
console.log(sameObject.name); // Logs 'Jack'

sameObject.name = 'Jill';
console.log(myObject.name); // Logs 'Jill'

// If we re-assign it, the link is lost
sameObject = { name: 'Howard' };
console.log(myObject.name); // Logs 'Jill'

如果我将myObject作为参数传递给一个函数,它的行为就好像我简单地将它赋给了一个新变量。同样的事情,同样的行为,但是是一个函数。

函数myFunc(sameObject) { //我们改变了对象,所以myObject也得到了改变…就像以前一样。 sameObject.name = 'Jill'; //但是,如果我们重新分配它,链接就丢失了 sameObject = { 名称:“霍华德” }; } var myObject = { 名称:“乔” }; //这就像我们说sameObject = myObject一样; myFunc (myObject); console.log (myObject.name);//日志'Jill'

每次将变量传递给函数时,你都是在“赋值”给参数的名称,就像使用等号一样。

永远记住等号=表示赋值。 将参数传递给函数也意味着赋值。 它们是相同的两个变量以完全相同的方式连接在一起。

修改一个变量影响另一个变量的唯一情况是底层对象发生变化。

区分对象和原语是没有意义的,因为它的工作方式就像你没有一个函数,只是用等号赋值给一个新变量一样。

你可以这样想:

无论何时在ECMAscript中创建一个对象,这个对象都是在一个神秘的ECMAscript通用的地方形成的,没有人能够得到。你只能得到这个神秘地方的那个物体的参考。

var obj = { };

即使obj也只是对对象的引用(它位于那个特殊的位置),因此,你只能传递这个引用。实际上,任何访问obj的代码段都会修改很远很远的对象。