JavaScript闭包和类实现

JavaScript闭包和类实现,javascript,closures,Javascript,Closures,我编写了以下代码来理解JavaScript中类实现和闭包 1. 在这里,当我实例化Person时,我得到以下输出- Person Fired!! EchoMyName - Self Called ReferenceError: EchoMyName is not defined 但它就在那里,我在调用它之前就定义了它?为什么会出错 2. 另外,当我修改代码以删除以前的错误并对某人调用CallMe时,它似乎无法访问EchoMyName function Person(name) { th

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

1. 在这里,当我实例化
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的网站上找到了这个链接:

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

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

区别在于如何计算
函数
定义

在第一个代码段中,
EchoMyName
是一个字符串,因为它周围有括号。允许立即调用它们,但只能在它们自己的主体中通过它们的名称引用它们

在第二个示例中,
EchoMyName
是一个。这些都是受限制的,允许他们在自己的身体之外被他们的名字引用

它似乎无法访问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!");
}
这是因为
EchoMyName
绑定到
Person
内的范围。除此之外,
EchoMyName
不存在

您需要通过
this
Person.prototype
EchoMyName
附加到实例,以便
CallMe
可以访问它:

this.EchoMyName = function EchoMyName(temp) {
    console.log("EchoMyName - " + temp);
};
或者,如果您希望保持
EchoMyName
的作用域,以便其他代码无法调用它,那么
CallMe
也需要在相同的作用域
函数中定义。不过,这不一定是
个人

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;
})();
参考:

这是一个函数表达式,不是函数定义;名称
EchoMyName
仅指函数本身内部的函数,因此以后不能使用它。(除了IE的JScript,它是有缺陷的。)

你的第二个问题源于这样一个事实:你所拥有的不是一门课;这是一个函数。可以在JavaScript中的函数中声明函数,并且它的作用域将限定为该函数,就像正则变量一样(但被提升,以便可以在函数中的任何点使用)。原型只是一个对象,不能访问构造函数的局部变量

总之,在ECMAScript 5中:

  • 只有三个作用域:
    • 全球的
    • 作用
    • catch
  • 在命名函数表达式中,名称只能由该函数访问
  • 对于正则变量,范围没有例外;如果原型上的函数需要目标函数的某些内容(如果它们不需要,为什么它们在原型上?)
  • 如果没有括号,函数表达式看起来像函数声明,它的作用类似于同一范围内的变量,但被“提升”,因此无论它出现在函数中的何处,它的作用就像它在开始时出现一样
代码片段#1 发生引用错误的原因是以下代码:
EchoMyName(“被人调用”)

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

在JavaScript中,函数实际上是对象。声明函数时,您正在创建对象的实例

下面是声明函数的几种不同方法

//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构造函数将在名为prototype的属性中存储一个阴影对象。Person的每个实例都将引用相同的原型。此外,原型的原型是对象


我邀请您阅读来自Mozilla开发者网络的文章,以了解更多信息。

在第一个版本中,
EchoMyName
名称的作用域是函数本身,在封闭的作用域中不可用。这是因为它是一个命名函数表达式,而不是函数声明。在第二个版本中,您试图在创建它的变量范围之外的变量范围内调用
EchoMyName
.prototype
方法不继承构造函数的变量范围。。。实际上,最后定义的函数不是有效的语法。@CrazyTrain:谢谢你更正了语法。你应该返回函数。这很清楚,谢谢。但我有一个疑问。如果我使用
this
创建
EchoMyName
它将可以访问
Person()
中的局部变量,但是如果我将它定义为
Person()
之外的原型,我就无法访问这些局部变量,对吗?
Person()
中定义的原型是否可以访问其局部变量?
prototype
上的@AbijeetPatro方法应独立于与它们相关的任何实例或闭包。因此,您需要避免从构造函数内部更改
原型。如果方法依赖于构造函数作为
//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)
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!