javascript - 将变量设置为全局变量时,变量指向何处?

标签 javascript

这是一个简单的例子:

  1| window.gamelogic = {};
  2| var g = gamelogic;
  3| g.points = 1;
  4| g.array = ["foo","bar"];
  5| var b = g.points;
  6| b = b + 1;
  7| console.log(window.gamelogic);
  8| console.log(b);

这将打印:
Object { points=1, array=[2] }
2

所以这里有两件事要注意:
  • 一个(看似本地的)变量-g-设置为全局对象并进行更新时,还会更新全局对象-window.gamelogic。 (更新g还更新了window.gamelogic)。
  • 局部 int b(设置为全局int,点)在更改时不会更新全局变量。 (更新b不会更新window.gamelogic.points)

  • 基于第一点,可能会认为,当var指向全局对象时,您实际上只是在创建指向该全局对象相同内存位置的另一个指针。这可以解释为什么更新g也会更新window.gamelogic。

    但是,不更新window.gamelogic.points似乎可以解决这个问题。

    这里发生了什么?

    最佳答案

    在JavaScript中,变量(和属性)包含值。值可以具有许多不同的类型(数字,字符串, bool(boolean) 值),其中之一是对象引用,它是对对象的引用,但不是实际的对象本身。想到对象引用的一种简单方法是,它只是一个数字,就像一个很大数组的索引一样,告诉我们对象在哪里。 (从字面上看,这不是真的,但这是一种有用的思考方式。)或者用非编程的方式,Joe可能会在纸上写上“123 Any St.”。上面写着,这是乔的家。纸张是变量(或属性); “123 Any St.”是一个值(在这种情况下是对象引用),而房子是一个对象。

    对象不是值,因此不能将它们存储在变量或属性中(或作为函数参数传递)。只能引用它们。

    当您将值分配给变量或属性(或将其作为参数传递给函数)时,就是从源将值复制到其中。因此a = b将值从b复制到a中。当b包含对象引用时,将复制该引用,而不是对象。然后ab都引用同一个对象。就像玛丽拿出一张纸(a)并抄写乔的纸(b)上的内容一样。现在两张纸都说乔的房子在哪里。房子不是被复制的,只是信息告诉我们它在哪里。

    考虑到这一点,让我们看一下您的代码。当你做

    window.gamelogic = {};
    

    它创建一个对象并将其引用(一个值)复制到属性gamelogic中。这是此时内存中的粗略草图,省略了很多不必要的细节:
                     +-------------------+
                     | (stuff omitted)   |       +-----------+
    window:ref429--->| gamelogic: ref758 |------>|           |
                     +-------------------+       +-----------+
    

    Then you do this:

    var g = gamelogic;
    

    (挥手)创建一个变量(我将在稍后说明挥手),并为其分配(复制)gamelogic中的值。由于该值是对象引用,因此ggamelogic现在指向同一位置;也就是说,它们引用相同的对象:
                     +-------------------+
                     | (stuff omitted)   |    
    window:ref429--->| gamelogic: ref758 |---+
                     +-------------------+   |   +-----------+
                                             +-->|           |
                                             |   +-----------+
    g: ref758--------------------------------+
    

    Then you do

    g.points = 1;
    

    它在该对象上创建一个名为points的属性,并将值1复制到其中:
                     +-------------------+
                     | (stuff omitted)   |    
    window:ref429--->| gamelogic: ref758 |---+
                     +-------------------+   |   +-----------+
                                             +-->| points: 1 |
                                             |   +-----------+
    g: ref758--------------------------------+
    

    Let's highlight what we've done here: We haven't changed the value in g in any way, it's still the same as it was: A reference to the object that gamelogic also references. What we've done is changed the state of that object (by adding a property to it). This is one of the key things about objects: They have state that can be changed. When that state is changed, it doesn't matter which copy of the reference to it you have when you look at it; you'll see the same object, with its (updated) state, regardless.

    Okay, continuing:

    g.array = ["foo","bar"];
    

    这将创建一个数组(是一个对象),并在我们的对象上创建一个名为array的属性,并将该数组的引用值复制到该属性中:
                     +-------------------+
                     | (stuff omitted)   |    
    window:ref429--->| gamelogic: ref758 |---+
                     +-------------------+   |   +---------------+     +----------+
                                             +-->| points: 1     |     | 0: "foo" |
                                             |   | array: ref804 |---->| 1: "bar" |
    g: ref758--------------------------------+   +---------------+     +----------+
    

    Then you do:

    var b = g.points;
    

    (挥手)创建一个变量并将值从g.points(1)复制到其中:
                     +-------------------+
                     | (stuff omitted)   |    
    window:ref429--->| gamelogic: ref758 |---+
                     +-------------------+   |   +---------------+     +----------+
                                             +-->| points: 1     |     | 0: "foo" |
                                             |   | array: ref804 |---->| 1: "bar" |
    g: ref758--------------------------------+   +---------------+     +----------+
    b: 1
    

    Then

    b = b + 1;
    

    1获取值b,向其中添加1,并将新值(2)存储在b中。 g.points完全不受影响:

    + ------------------- +
    | (省略的东西)
    窗口:ref429 ---> | gamelogic:ref758 | --- +
    + ------------------- + | + --------------- + + ---------- +
    +-> |点:1 | | 0:“foo” |
    | |数组:ref804 | ----> | 1:“栏” |
    g:ref758 -------------------------------- + + ------------- -+ + ---------- +
    b:2

    上面的关键点是:
  • 变量和属性(以及函数参数)包含值。
  • 值具有类型,例如字符串,数字, bool(boolean) 值或对象引用。
  • 对象引用只是一个表明对象在哪里的值。
  • 对象不是值;对对象的引用是值。
  • 对象的状态可以更改。*

  • (*如果允许的话。可以创建一个不允许更改其状态的对象;这些对象称为“不可变的”对象。这样做非常方便,强大。在JavaScript中,您可以使用 Object.freeze 和类似的方法可以做到这一点,因为默认情况下对象是非常松散的,您可以通过赋值来向它们添加属性。不能定义任何更改对象状态的公共(public)方法。)

    关于那“创造一个变量”的挥舞着,我在那儿忽略了两个细节,因为那时它们并不重要:
  • 在JavaScript中,在代码开始运行之前先处理var声明,因此在逐步代码的第一行运行之前就已经创建了gb变量。最初,它们中的值为undefined
  • 因为您是在全局范围内使用var的,所以bg成为全局对象的属性,这是window所指向的。实际上,window本身是全局对象的属性。直到ES5,所有全局变量都是全局对象的属性。 (在ES6 / ES2015中,我们没有一个新的全局类别:使用letconstclass创建的。)

  • 因此从技术上讲,我们的第一个图应该看起来像这样:

    + -------------------------- +
    | + ------------------- + |
    | | (省略的东西) |
    +-> |窗口:ref429 |-+ + ----------- +
    | gamelogic:ref758 | ------> | |
    | g:未定义| + ----------- +
    | b:未定义|
    + ------------------- +

    ...但是,看来这没什么用。 :-)

    关于javascript - 将变量设置为全局变量时,变量指向何处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34534471/

    相关文章:

    javascript - 为什么 vue 3 在第一次加载项目时导入所有页面的所有 js 文件

    javascript - 默认情况下如何更改绘图管理器选择选项?

    javascript - 循环内 Lodash Throttle 或 Debounce 的问题

    javascript - 你能用 jquery 定位类吗?

    javascript - 检查一个数组是否存在于数组的数组中?

    javascript - document.querySelector 通过 textContent

    php - 使用 include 时,php 将 ""添加到 html

    javascript - Jquery - 一次循环一个同级元素

    javascript - jQuery :not() Selector iOS5 compatible?

    javascript - TVML/tvOS : Template background?