2

我编写了以下代码来理解 JavaScript 中的类实现和闭包。

1

function Person(name) {
    this.Name = name;
    console.log("Person Fired!!");
    
    (function EchoMyName(temp) {
        console.log("EchoMyName - " + temp);
    }("Self Called"));
    EchoMyName("Called by Person!");
}
Person.prototype.CallMe = function(){
    console.log("Call Me Fired!");
    EchoMyName("Called by CallMe!");
}

在这里,当我实例化时Person,我得到以下输出-

Person Fired!!
EchoMyName - Self Called
ReferenceError: EchoMyName is not defined

但它就在那里,我在调用它之前定义了它?为什么会出错?

2

此外,当我修改代码以删除以前的错误并调用CallMe一个人时,它似乎无权访问 EchoMyName

function Person(name) {
    this.Name = name;
    console.log("Person Fired!!");
    
    function EchoMyName(temp) {
        console.log("EchoMyName - " + temp);
    };
}
Person.prototype.CallMe = function(){
    console.log("Call Me Fired!");
    EchoMyName("Called by CallMe!");
}

称呼:

new Person().CallMe();

输出

Person Fired!!
Call Me Fired!
ReferenceError: EchoMyName is not defined

更新#1

感谢所有的答案。我在 Douglas Crockford 的网站上找到了这个链接:http: //javascript.crockford.com/private.html

它提供了对隐藏在 JavaScript 中的信息的非常清晰的理解。

4

3 回答 3

3

代码片段#1

由于以下代码,出现引用错误:EchoMyName("Called by Person!");

EchoMyName是一个自调用函数,位于名为Person. 一旦它被自调用,它就不再存在。如果我们使用另一种编程语言,我们可以类比为匿名对象。

在 JavaScript 中,函数实际上是对象。当你声明一个函数时,你正在创建一个Function对象的实例。

以下是声明函数的几种不同方式。

//function statement
function x (a, b) { return a + b;  }

//function expression, this will store an anonymous function into a variable
var y = function (a, b) { return a + b;  };

//Function constructor 
var z = new Function ("a", "b", "return a + b;"); // avoid this form, it will prevent certain optimizations from the browser's JS engine because of the strings (this is just an example)

代码片段#2

当您在 JavaScript 函数中声明变量或函数时,它仅限于函数的范围。对于构造函数也是如此。

您需要声明一个函数表达式并将其存储在Person构造函数的属性中。

下面的小例子。

function Person(name) {
    this.Name = name;
    console.log("1 Person Fired!!");

    // notice that function is stored in this.EchoMyName
    this.EchoMyName = function(temp) {  
       console.log("2 EchoMyName - " + temp);
    };

    console.log("3 Still in Person!")
}

Person p = new Person("Bob");
p.EchoMyName("Hello World!");

输出:

1 Person Fired!!
3 Still in Person!
2 EchoMyName - Hello World!

原型

在 JavaScript 中,没有像在许多其他面向对象语言(C++、C#、Java)中那样的传统继承。相反,您拥有的是对象链接。

如果我们以您的代码为例,Person 构造函数将有一个阴影对象存储在名为原型的属性中。每个 Person 实例都会引用同一个原型。此外,原型的原型是Object。

我邀请您阅读来自 Mozilla 开发者网络的文章继承和原型链以获取更多信息。

于 2013-08-30T00:58:22.140 回答
2
(function EchoMyName(temp) {
    console.log("EchoMyName - " + temp);
}("Self Called"));

这是一个函数表达式,而不是函数定义;名称EchoMyName只指函数本身内部的函数,所以以后不能使用。(除了 IE 的 JScript,它是错误的。)

你的第二个问题源于你所拥有的不是一个类。这是一个功能。可以在 JavaScript 中的函数内部声明一个函数,它的作用域将限定为该函数,就像一个常规变量一样(但被提升,因此它可以在函数中的任何位置使用)。原型只是一个对象,不能访问构造函数的局部变量。

总而言之,在 ECMAScript 5 中:

  • 只有三个范围:
    • 全球的
    • 功能
    • catch
  • 在命名函数表达式中,名称只能由该函数访问
  • 对于常规变量,范围没有例外;如果原型上的函数this需要目标的某些东西,就应该使用它们(如果不需要,为什么它们在原型上?)
  • 没有括号,函数表达式看起来就像一个函数声明,它在同一范围内就像一个变量,但是被“提升”了,所以无论它出现在函数中的什么位置,它的行为就像它在开始时出现一样
于 2013-08-30T00:34:14.913 回答
1

但它就在那里,我在调用它之前定义了它?为什么会出错?

不同之处在于function定义的评估方式。

在第一个片段中,EchoMyName是一个函数表达式,因为它周围有括号。允许立即调用它们,但只能在它们自己的体内通过它们的名称来引用。

在第二个中,EchoMyName是一个函数声明。这些都受到提升,允许他们在他们自己的身体之外被他们的名字引用。

似乎它无权访问 EchoMyName

这是因为EchoMyName是绑定到范围里面的Person。除此之外,EchoMyName不存在。

您需要通过或附加EchoMyName到实例,以便可以访问它:thisPerson.prototypeCallMe

this.EchoMyName = function EchoMyName(temp) {
    console.log("EchoMyName - " + temp);
};
Person.prototype.EchoMyName = function EchoMyName(temp) {
    console.log("EchoMyName - " + temp);
};
Person.prototype.CallMe = function(){
    console.log("Call Me Fired!");
    this.EchoMyName("Called by CallMe!");
};

或者,如果您想保持EchoMyName作用域,使其不能被其他代码调用,那么CallMe也需要在同一个作用域内定义function。虽然,这不一定是Person

var Person = (function () {
    function Person(name) {
        this.Name = name;
        console.log("Person Fired!!");
    }

    function EchoMyName(temp) {
        console.log("EchoMyName - " + temp);
    }

    Person.prototype.CallMe = function () {
        console.log("Call Me Fired!");
        EchoMyName("Called by CallMe!");
    };

    return Person;
})();

参考:揭示模块模式

于 2013-08-30T00:33:49.083 回答