javascript 函数中的静态变量及其背后的工作原理

static variables within javascript functions and how it works under the hood

我很难理解 JavaScript 中的一些基本概念,所以我希望有人能给我一个很好的解释,说明这些示例中发生的事情。

案例 1:

在这种情况下,我在构造函数中使用 'this' 关键字:

function Counter() {
    this.c = 0;
    this.incC = function() {
        return this.c++;
    };
}

显然,现在我可以实例化函数并调用 incC 函数来递增 c,并且 c 的记录将保存在创建的实例中,因为 'this' 指的是正在创建的实际对象。根据我在 C 中的(有限)编程经验,我想当我这样做时:

var counter = new Counter();

-代码有效地为对象分配 space,然后将指向该分配内存的指针传递给构造函数,该指针是 'this'.

但我想知道我是否错了,因为万一 2 事情有点不同。

案例 2:

在这个函数中,我可以使用 'this' 关键字创建一个持久变量。但是,我不打算实例化它,所以它不能指向一个对象,而且它似乎不是 counter 的属性(显然函数本身是一个对象)作为 counter.c returns未定义。

function counter() {
    this.c = this.c || 1;
    return this.c++;
}

console.log(counter.c); // undefined

那么这个例子中到底发生了什么?为什么以及如何在我们退出函数时不丢失 c,以及在这个例子中 'this' 指向什么?

案例 3:

最后只是为了让事情变得更有趣。

我在一个非常古老的代码库中遇到了这个问题(我知道有更准确的继承方法,但发现这个例子很有趣,因为它是如何工作的):

function CounterChild() {
    Counter();
}

CounterChild.prototype = new Counter();
CounterChild.constructor = CounterChild;

var child = new CounterChild();

console.log(child.c); // 0

这里的 this 关键字与正在实例化的对象相关,但是对 Counter() 构造函数的调用究竟是如何传递对正在创建的对象的引用的呢?我的意思是解释器怎么知道应该向这个函数传递一个指针,因为没有使用新的关键字?

关于 this 最重要的一点是,它的值由 如何 函数 调用 决定(预计对于 ES6 箭头函数,其中 this 是词法作用域,以及通过 .bind).

绑定的函数

调用 new Counter() 与调用 Counter() 非常不同,因此 this 指的是不同的值。

总体而言,我建议阅读 MDN - this 以了解有关 this 的更多信息。


案例一

案例二

由于函数调用"normally",即foo()this指的是全局对象,在浏览器中是window。代码相当于

function counter() {
    window.c = window.c || 1;
    return window.c++;
}

案例三

how exactly does the call to the Counter() constructor get passed a reference to the object being created?

没有。在 CounterChild() 中调用 Counter 在这里没有可见效果 (*),您可以简单地删除它。

c 属性 来自 CounterChild.prototype.c,因为您将 Counter 实例分配给 CounterChild.prototype。您可以通过检查 console.dir(child).

来验证这一点

CounterChild.prototype是通过new CounterChild()创建的所有实例的原型。在对象的原型链中查找对象本身不存在的任何 属性。

如果想让Counter里面的this引用新创建的对象,必须显式传递:

function CounterChild() {
    Counter.call(this);
}

*:事实并非如此。就像情况 2 一样,它确实更改了 全局变量 c,但这绝对不是您想要的。