由面试经常问的对象赋值引发的思考

1.

var a = 1;
var b = a;
a = 2;
console.log(b); // 1

var c = [1,2,3];
var d = c;
c.shift();
console.log(d); // [2,3]

我们知道基本对象的赋值是拷贝值,所以改变a不影响b,复杂对象赋值拷贝的是指针,所以改变c影响d

2.
但是现在有一些奇怪的现象

var a = [1,2,3];
var b = a;
a = [1,2,3,4];
console.log(b); // [1,2,3]

在这里改变了a 但是b没有改变,并不知道这中间发生了什么,难道又开辟了一个地址a存放[1,2,3,4]?b还是指向之前的a?

3.

var factorial = function() {
  return 1
};
var trueFactorial = factorial;
factorial = function () {
  return 2;
}
console.log(trueFactorial()); // 1

哎 奇怪了,不是对factorial 重新赋值了吗?function的赋值不是浅拷贝吗?

4.

var factorial = function() {
  return factorial();
};
var trueFactorial = factorial;
factorial = function () {
  return 2;
}
console.log(trueFactorial()); // 2

哎 在这里能正常调用到第二次赋值的那个函数

阅读 1.7k
3 个回答

2,a = [1,2,3,4];创建了一个新的数组对象,然后把a指向它
3,var trueFactorial = factorial;factorial指向的对象赋值给trueFactorial,所以trueFactorial指向的是最初声明的方法

复合类型(Function、Object 等)的赋值是引用传递,他们都指向了同一个内存地址,

// a变量现在存了一个数组的内存块地址在栈内。
// a变量本身也需要一个内存块存放数组的地址
var a = [1, 2, 3, 4];

// a把地址传给了b,b现在也指向了 [1,2,3,4]。
// a和b没啥关系,只是指向同一个堆内存块而已
var b = a;

// a变量被重新赋值,a的内存块中存放的地址发生变化,不再指向原来的数组
a = [5,6,7];

// a被重新赋值并不会改变b的指向,因为二者在栈内是不同的内存块
console.log(b); // [1,2,3,4]

欢迎拍砖!!

{
    "type": "Program",
    "start": 0,
    "end": 41,
    "body": [
        {
            "type": "VariableDeclaration",
            "start": 0,
            "end": 16,
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "start": 4,
                    "end": 15,
                    "id": { "type": "Identifier", "start": 4, "end": 5, "name": "a" },
                    "init": {
                        "type": "ArrayExpression",
                        "start": 8,
                        "end": 15,
                        "elements": [
                            { "type": "Literal", "start": 9, "end": 10, "value": 1, "raw": "1" },
                            { "type": "Literal", "start": 11, "end": 12, "value": 2, "raw": "2" },
                            { "type": "Literal", "start": 13, "end": 14, "value": 3, "raw": "3" }
                        ]
                    }
                }
            ],
            "kind": "var"
        },
        {
            "type": "VariableDeclaration",
            "start": 17,
            "end": 27,
            "declarations": [
                {
                    "type": "VariableDeclarator",
                    "start": 21,
                    "end": 26,
                    "id": { "type": "Identifier", "start": 21, "end": 22, "name": "b" },
                    "init": { "type": "Identifier", "start": 25, "end": 26, "name": "a" }
                }
            ],
            "kind": "var"
        },
        {
            "type": "ExpressionStatement",
            "start": 28,
            "end": 41,
            "expression": {
                "type": "AssignmentExpression",
                "start": 28,
                "end": 41,
                "operator": "=",
                "left": { "type": "Identifier", "start": 28, "end": 29, "name": "a" },
                "right": {
                    "type": "ArrayExpression",
                    "start": 32,
                    "end": 41,
                    "elements": [
                        { "type": "Literal", "start": 33, "end": 34, "value": 1, "raw": "1" },
                        { "type": "Literal", "start": 35, "end": 36, "value": 2, "raw": "2" },
                        { "type": "Literal", "start": 37, "end": 38, "value": 3, "raw": "3" },
                        { "type": "Literal", "start": 39, "end": 40, "value": 4, "raw": "4" }
                    ]
                }
            }
        }
    ],
    "sourceType": "script"
}

这个就是你要的程序。请分清赋值语句做了什么。赋值语句会更改Identifier的值。pop语句算是一个成员方法,不会改变Identifer的指向。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题