为什么 JavaScript 函数 returns 对象通过引用(对其参数)执行它?

Why does a JavaScript function that returns an object does it by reference (to its arguments)?

我有一个函数 returns 一个对象,其属性之一是作为参数(argument)传递给它的日期对象的值。

当这个函数在一个循环中被调用时,改变发送到它的日期参数并且所有返回的对象都被添加到一个数组中 - 我注意到数组中的所有对象都以日期对象的相同值 - 这是循环内日期的最终值。

为了演示,我有一个函数 (theFunction) returns 字符串表示形式以及日期参数本身作为返回对象的两个属性。

此函数是从另一个函数 (theLoop) 调用的,该函数在循环中使用不同的日期值调用 theFunction,并将函数调用的结果存储到数组中。

var theFunction = function (inputDate) {
    /* The string representation and the date itself as properties on the returned object */
    return {
        string: inputDate.toLocaleString(),
        original: inputDate
    };
};

var theLoop = function (startDate) {
    // declare an array for the output
    var dates = [];

    for (var minute = 0; minute < 1440; minute = minute + 30) {
        var newHour = minute % 60,
            newMinute = minute - newHour * 60;
        // loop and increment the time by a half-hour starting from midnight until minutes < 1440
        startDate.setHours(newHour, newMinute);
        // record the output from theFunction into the array
        dates.push(theFunction(startDate));
    }
    // return the array
    return dates;
};

// get the array
var datesArray = theLoop(new Date());

// console.log the array
console.log(datesArray);

this fiddle至运行以上代码。

问题 1:为什么从名为 theFunction 的函数中返回的对象包含对在 theLoop 循环中递增的日期变量的引用?

问题 2:如何更改 theFunction 以便它 returns 传递给它的日期副本?

  1. 因为每个对象仍然引用同一个 startDate 对象。因此,随着 startDate 的变化,每个对象都会受到该变化的影响。

  2. 将循环更改为此

    var theLoop = function (startDate) {
    // declare an array for the output
    var dates = [];
    
    for (var minute = 0; minute < 1440; minute = minute + 30) {
        var newHour = minute % 60,
            newMinute = minute - newHour * 60;
        // loop and increment the time by a half-hour starting from midnight until minutes < 1440
        startDate.setHours(newHour, newMinute);
        var newDate = new Date(startDate.getTime());
        // record the output from theFunction into the array
        dates.push(theFunction(newDate));
    }
    // return the array
    return dates;
    };
    

您有一个 Date 对象 (startDate),您使用 setHours 对其进行修改,并在每次迭代中将引用传递给函数。

要解决此问题,请从 inputDate (updated fiddle) 创建一个新日期:

var theFunction = function (inputDate) {
    /* The string representation and the date itself as properties on the returned object */

    var inputDateClone = new Date(inputDate.getTime()); // the cloned date

    return {
        string: inputDateClone.toLocaleString(),
        original: inputDateClone
    };
};

对于问题 1:Javascript 中的 DateObject;在Javascript中,ObjectFunction是一个指针,所以,对象值只是一个指针。当您将对象(或函数)作为参数传递(或将对象值分配给另一个变量)时,您传递(或分配)了指向内存中 "real" 对象的指针。在这种情况下:

//get the array
var datesArray = theLoop(new Date());

你传递了new Date()作为参数来调用theLoop,你只是传递了一个指针,你没有传递对象的新副本 .所以,修改"several"日期就是简单的修改一个内存位置的一个日期,通过它的指针的多个拷贝

对于问题2:要解决这个问题,只需在theLoop:

var theLoop = function (startDate) { // 'startDate' should be renamed, but I still use this for ease of explain.
  ...
  for (...) {
    startDate = new Date(startDate); // HERE!!
    ...
  }
  return dates;
}

因为new Date(startDate) 将创建原始日期的新副本。更多详细信息:Date in Javascript 包含一个无符号整数,称为时间戳; new Date(startDate) 在这种情况下完全等同于 new Date(parseInt(startDate))new Date(startDate.valueOf()).

重要提示: 同样,Javascript 参数不是通过引用传递的,这是错误的,它们总是通过值传递任何类型的值。对于对象(或函数),它们也不是通过引用传递的!相反,它们是指针,假设指针(指向对象)是按值传递的。

此外,现在您可能知道运算符 new 的实际含义了。我认为,就像C++一样,它意味着"create a pointer to an allocated memory region"。