在类构造函数中,为什么"这需要"?为什么我不能使用局部变量?

时间:2016-05-15 01:44:28

标签: javascript

我知道局部变量在测试时起作用,但我不明白这个概念。为什么"这个"工作和局部变量不?澄清一下,为什么我必须使用它并避免局部变量! 代码:

enter

3 个答案:

答案 0 :(得分:1)

您可以在构造函数中使用局部变量,但它们不会自动成为对象的实例变量。相反,你使用它们的方式,它们只是时间局部变量,就像任何函数定义中的局部变量一样。

执行此操作时:

 function Person(job, married) {
    var employ = job;
    var status = married;
 }
 var ray = new Person("student", true);

以下是发生的事情:

  1. 您定义了一个名为Person
  2. 的函数
  3. 在该函数中,您定义了两个名为employstatus的本地变量。
  4. 这些是函数中的正常局部变量。它们仅对该函数中的代码可见。这些对于某些事情可能很有用,但它们不能用于该函数之外的任何代码。它们不适用于对象的原型方法,它们不能用于该函数之外的其他代码。实际上,如果没有某种创建闭包的引用,它们的生命周期就会有限,并且只要Person函数完成执行就会消失并进行垃圾收集。
  5. 因此,如果您打算创建对象的成员变量的C ++等价物,那么这并不能实现。这些变量仅用于Person()函数的持续时间,然后被处理掉并且没有持久存在。
  6. 然后,当您执行var ray = new Person("student", true);时,会发生以下情况。
  7. new导致系统创建一个新对象,将this的值设置为指向该新对象,然后使用您的两个参数调用Person构造函数。
  8. 然后,您的代码会创建两个局部变量,您可以将这两个参数分配给。
  9. 然后Person()函数完成执行并处理掉两个局部变量,因为它们的定义范围已经完成并且是垃圾收集。
  10. 然后,您将新创建的对象分配给变量ray。它确实是一个新对象,但它没有自定义实例数据,因为没有任何东西以持久的方式存储。
  11. 如果你然后执行console.log(ray),那么你只会看到一个没有实例数据的空对象,而不是默认的Object实例。您的自定义数据并未存储在任何持续存在的位置,因此它现在已经消失。
  12. 如果您打算将这两个参数保存在某个持久作为对象的实例数据的地方,那么您有两个选择。更传统的选择是使它们成为对象的可公开访问的属性。你会这样做:

     function Person(job, married) {
        this.employ = job;
        this.status = married;
     }
    

    由于this指向新创建的对象,因此此代码将jobmarried参数分配给新创建的对象的属性。这些属性可以通过对象上的其他方法或构造函数外部的任何代码来访问,如下所示:

    var ray = new Person("student", true);
    console.log(ray.employ);   // "student"
    console.log(ray.status);   //  true
    

    这些属性可公开访问。

    您可以使用这些局部变量执行一些有趣的操作,这些变量可以允许它们在创建对象后保留并使用。要做到这一点,你必须创建一个闭包。我认为闭包是一个函数作用域,通常在函数完成执行时会被丢弃,但由于环境的原因,函数作用域内仍然存在实时引用,因此垃圾收集器在函数完成执行时不会丢弃函数作用域就像在纯粹的基于堆栈的语言(如C ++)中一样。相反,它会持久存在,并且可以在创建对象后通过代码访问。这是一个例子:

     function Person(job, married) {
        var employ = job;
        var status = married;
    
        this.getEmploy = function() {
            return employ;
        }
    
        this.getStatus = function() {
            return status;
        }
     }
     var ray = new Person("student", true);
     console.log(ray.getEmploy());   // "student"
     console.log(ray.getStatus());   // true
    

    这里构造函数中的函数赋值创建了一个闭包。私有局部变量employstatus仍然是Person函数范围内的私有变量。但是,因为getEmploygetStatus属性现在公开公开,并且可以在将来的某个时间调用,并且这些函数引用employstatus变量,垃圾收集器意识到它无法对employstatus变量进行垃圾收集,因此它们会在这个新创建的Person对象的生命周期内持续存在。

    使用其他面向对象语言(如C ++)所熟悉的术语,employstatus局部变量为您提供了私有实例变量的一些功能。有些人称这是一个黑客,以填补Javascript不直接提供的功能的空白。但是,我不认为这是一个黑客行为。该语言提供了闭包作为一个非常有用的功能,可以在很多方面使用,这只是使用闭包创建一个好处的一种方式,私有实例数据的好处。

    外部世界只能访问公开指定的媒体资源getEmploygetStatus,但通过调用它们,我们可以访问私有变量employstatus。如果我们在这个新模型中console.log(ray),我们仍然看不到employstatus,因为就控制台而言,它们仍然不具备属性ray个对象。但是,由于闭包,它们可以通过ray对象上的方法唯一访问。

    此外,由于每次调用Person构造函数时都会创建一个新的闭包,因此这些employstatus变量与Person的每个新实例唯一关联。宾语。他们的行为和工作就像对象的私人成员。

    有关此类结构的更多示例以及更多解释,请参阅此经典讨论:http://javascript.crockford.com/private.html

      

    为什么"这个"工作和局部变量不?

    除非创建某种持久闭包,否则局部变量是暂时的。它们仅在包含函数执行时才会持续,然后进行垃圾回收。仅仅因为它们是在一个你作为构造函数使用的函数中声明它们并不会使它们变得特殊。它们只是局部变量,除了只是局部变量之外没有神奇的力量。

      

    在类构造函数中为什么“需要”?   澄清一下,为什么我必须使用它并避免本地化   变量!

    如果要为对象指定属性,则this指向构造函数中的对象,因此分配给对象属性的唯一方法是将对象引用为{{1} }。这就是语言的运作方式。 Javascript中的所有属性引用都需要一个对象作为访问的第一部分。并且,在构造函数中,新创建的对象的引用是this.someProperty = xxxx。这就是语言的设计方式。

    来自其他一些面向对象语言的那些可能你可以声明一个类的实例变量,然后只使用该名称,并且解释器将以某种方式知道它是一个实例变量名,而不是变量名。在其他一些语言中可能也是如此。在Javascript中不是这样。所有属性引用,无论是在构造函数中,在某些方法中,还是从外部作为对象的属性访问,都必须使用对象作为引用的基础。并且,在构造函数内部和方法内部,该基数是this的值。因此,this是您在当前实例上引用该属性的方式。

答案 1 :(得分:0)

这样想:

一个类基本上是一个对象,对吧?好吧,当你声明一个新的Person实例时,你要说"让我们创建一个具有属性x,y和z的新对象。"使用"这个"允许您稍后访问该实例的属性,而局部变量不会被视为对象的属性。

答案 2 :(得分:0)

当一个函数作为构造函数调用时(使用new关键字),创建一个新对象(实例对象),在函数的prototype属性的对象值上进行原型化,并使用它调用构造函数this值设置为刚刚创建的新实例对象。

构造函数代码可以在this(实例对象)上设置属性和方法,这是构造函数调用的返回值(...除非构造函数显式返回其他对象)。

如果构造函数中定义的变量由嵌套函数访问,这些函数在构造函数返回后仍然存在,则它们不会被垃圾收集,因为它们仍然可以被访问。如果在构造函数返回后它们不可访问,则它们基本上被丢弃并可用于垃圾收集。

对象创建是JavaScript行为的基础:尝试查阅和阅读构造函数的使用。

通过搜索“JavaScript中的闭包”,可以在外部函数退出后找到有关在嵌套函数范围内保留变量的更多信息。