一个Javascript模块中的变量在它之外可见? [英] Variables in a Javascript module visible outside of it?

查看:146
本文介绍了一个Javascript模块中的变量在它之外可见?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我来自一个.NET世界,那里有静态类(C#,也称为VB中的模块)和实例类 - 可以实例化的类。



这个问题是关于Javascript,我试图重新创建我已经知道的模式,并创建一个模块/静态类。这里是代码:

  var MyModule = {
variable1:0,
variable2:1,
method1:function(){
// code goes here
},
method2:function(){
// mode code goes here
},
method3:function(){
//和更多只是为了证明模式
}
}

method1(); //错误 - 没有这样的方法 - 好吧,我期望
variable1 = 5; //默默地将MyModule中的变量赋值给5?

请解释为什么在命名空间内声明的方法不可见,但变量是?另外,是否有办法阻止这些变量在 MyModule 之外可见,即使在同一个脚本中?

解决方案

我会先尝试解决一些误解 - 你的模块实际上是一个纯JavaScript对象使用文字初始化。一个对象不隐藏任何信息 - JavaScript没有 private 和 public 的作用范围与Java所说的一样。此外,访问对象属性的唯一方法是通过它访问它们。

  method1(); 

这个失败是因为您试图获取名为 method1 并执行它。这不存在,因此错误。然而,你可以做的是 MyModule.method1()。这是因为 MyModule 是一个实际的对象。在Java中,这与使用 Object MyModule = new Object()类似。因此,您可以调用它的方法,如 MyModule.toString() - 唯一的非常规的事情是,该实例以大写字母命名 - Java中的变量和JavaScript通常以小写开头,但仅限于惯例 - 没有任何语言功能强制它。



接下来,有这样一行:

  variable1 = 5; //默默地将MyModule中的变量赋值给5? 

要回答关于该行的评论 - 否,它不会。上面的这一行相当于做 window.variable1 = 5 。你在那里有什么被称为隐含的全球。这个名字是相当自我描述性的,但只是澄清 window.foo = 42 是一个明确的全局 foo = 42 暗指,因为它回落到窗口对象。但是, var foo = 42 不是全局 - var 关键字不附加或使用全局窗口对象。如果您使用严格使用指令,会导致JavaScript引擎在遇到隐含的全局时发出错误。



现在,除了这些误解之外,还有另外一个小例子,它实际上是一个重要的事情 - MyModule.method1 等等都是函数而不是方法。一个方法是一个面向对象的术语,用于一个子程序,它也带有一个隐含状态,它是分配给它的对象。然而,函数是一个自由浮动的可执行代码,它本质上不属于某个对象。这种区别可能看起来颇具学术性,但却有很大的影响。不过,我会请你相信我,因为这个主题太笼统了。



所以,那是错的。我们如何使它正确 ?首先,在作用域上,这是其余部分所需要的:



JavaScript有两个范围 - 全局和功能。这是什么意思,完全是:

  var foo = 42; 

功能栏(输入){
var foo =输入;
返回foo;
}

console.log(bar(5)); // 5
console.log(foo); // 42

我们有太多变量叫做 foo - 一个函数里面没有。分配一个不会改变另一个 - 这是因为它们在不同的范围内。这要归功于 var 关键字 - 如果在函数内省略了这个关键字,那么我们就会访问同一个事物

  var foo = 42; 

功能栏(输入){
foo =输入;
返回foo;
}

console.log(bar(5)); // 5
console.log(foo); // 5

这是因为内部 foo 没有被声明在功能范围内,所以它访问外部(并且没有外部 - window.foo 属性)。



这很简单。然而,这里有一个隐藏的方面,它并不是很明显,但它提到了:只有 两个范围。这里是我的意思是

pre $ 功能栏(条件){
var foo = 5;
if(condition){
var foo = 42;
}
return foo;
}

console.log(bar(false)); // 5
console.log(bar(true)); // 42

因此,即使我们似乎声明了一个新的 foo if语句中的属性实际上与第一个属性相同。其他语言在 {} 中有一个块范围,所以在那里声明的变量停留在那里。在JavaScript中不是这样。容易错过,所以需要注意。



现在,解决您的问题。关于JavaScript模块模式有很多优秀的资源,只提一些: Addy Osmani的学习JavaScript设计模式一书有非常好的描述,同样 Todd Motto 有,我相信是一篇适合初学者的好文章,而充足的好文章更深入,但仍然可以访问。它们都覆盖了模块模式。实际上你会发现许多模块模式 - 在这些资源和网络中。模块允许您执行的操作与其他语言中的 public private 类似。我不会试图解释它,因为我认为其他人做得比我更好。但是,我只是简单地解释一下Module是什么。再次,其他资源可以更好地覆盖这一点。



模块利用称为Closure的JavaScript特性更多信息这里这里(最有争议的StackOverflow问题之一)。还记得我说过,JavaScript中有两个范围?简单来说,封闭提供了一个功能范围。下面是它的样子:

 (function(){/ * your code goes here * /})()

简单地分析一下这个函数,你的代码中包含一个函数( / *函数在这里* /)()。实际上,它所执行的是执行该功能,因此内部的所有内容都被放入功能范围。这是非常强大的,然而,这是一个例子

  var closure =(function(){
var privateVar =secret;
return {
publicVar:42,
getPrivateVar(){return privateVar;}
}
})()

console.log(closure.publicVar); // 42
console.log(closure.getPrivateVar()); //secret
//让我们改变这个
closure.publicVar = 5;
closure.privateVar =已更改;

console.log(closure.publicVar); // 5
console.log(closure.getPrivateVar()); //secret

就像我们拥有(类似于)私人领域一样。同样, var privateVar 将在函数范围内保持瓶装状态,并且不会在外部访问。顺便提一句,这是模块模式的一个例子。而不是 var闭包我可以称它为 myModule 。这是一个相当简单的承担,但是,这是事情 - 它并没有变得更加复杂。所有不同的模块归结为非常相似的东西 - 你只是以不同的方式暴露数据。然而,这个概念是相似的 - 私人领域留在里面,而公共领域,你可以从其他地方访问。



这很长,但希望能涵盖你需要做的基本工作。


To start, I'm coming from a .NET world, where there are static classes (C#, also known as modules in VB) and instance classes - those you can instantiate.

This question is about Javascript, where I'm trying to recreate the pattern I already know and make a module / static class. Here is the code:

var MyModule = {
    variable1: 0,
    variable2: 1,
    method1: function() {
        //code goes here
    },
    method2: function() {
        //mode code goes here
    },
    method3: function() {
        //and some more just to prove the pattern        
    }
}

method1(); //error - no such method - ok, good, I expect that
variable1 = 5; //silently assigns a variable inside MyModule to 5 ?

Please explain why methods declared inside a namespace are not visible, but variables are ? Also, is there a way to prevent those variables from being visible outside of MyModule, even in the same script ?

解决方案

I will start by trying to address some misconceptions - your module is actually a plain JavaScript object initialised using a literal. An object does not hide any information - JavaScript does not have private and public scope the same way as, say Java does. Furthermore, the only way to access properties of an object is to access them through it

method1();

This fails because you are trying to get a variable called method1 and execute it. This does not exist, hence the error. What you can do, however, is MyModule.method1(). This is because MyModule is an actual object. In Java, this would be similar to having Object MyModule = new Object(). You can thus call methods on it, like MyModule.toString() - the only "unconventional" thing, is that the instance is named with a capital letter - variables in Java and JavaScript normally start with lower case but only by convention - there is no language feature that mandates it.

Next, there is this line:

variable1 = 5; //silently assigns a variable inside MyModule to 5 ?

To answer the comment on the line - no, it doesn't. The above line is equivalent to doing window.variable1 = 5. What you have there is called an "implied global". The name is fairly self descriptive, but just to clarify window.foo = 42 is an explicit global foo = 42 is implied because it falls back to the window object. However, var foo = 42 is not a global - the var keyword does not attach to or use the global window object. If you use the "use strict" directive you will cause the JavaScript engine to throw an error when it encounters an implied global.

Now, with these misconceptions aside, there is another minor one that I will merely gloss over but it's actually a major thing - MyModule.method1 and so on are functions rather than methods. A method is an Object Oriented terminology for a subroutine that also carries an implied state, which is the object it's assigned to. A function, however, is a free floating executable code that does not intrinsically "belong" to an object. The distinction may seem rather academic, but it has a big impact. However, I'll ask you to trust me on this one, as this is too broad a topic to cover here.

So, that's what's wrong. How do we make it right? First, on scopes, as that is needed for the rest of it:

JavaScript has two scopes - global and functional. Here is what this means, exactly:

var foo = 42;

function bar(input) {
    var foo = input;
    return foo;
}

console.log(bar(5)); //5
console.log(foo); //42

We have too variables called foo - one inside a function one not. Assigning one does not change the other - it's because they are in different scopes. That's thanks to the var keyword - if that was omitted inside the function, then we would be accessing the same thing

var foo = 42;

function bar(input) {
    foo = input;
    return foo;
}

console.log(bar(5)); //5
console.log(foo); //5

This is because the inner foo is not declared to be in the functional scope, so it accesses the outer (and with no outer - the window.foo property).

That's simple enough. However, there is a hidden aspect here that is not immediately obvious yet it bears mentioning: there are only two scopes. Here is what I mean

function bar(condition) {
    var foo = 5;
    if (condition) {
        var foo = 42;
    }
    return foo;
}

console.log( bar(false) ); //5
console.log( bar(true) ); //42

So, even though we seemingly declare a new foo property inside the if statement that's actually the same one as the first one. Other languages have a block scope inside { } so, variables declared there, stay there. Not true in JavaScript. Easy to miss, so it's important to note.

Now, onto your problem. There are excellent resources about the JavaScript module pattern, to mention but a few: Addy Osmani's "Learning JavaScript Design Patterns" book has a very good description, Todd Motto also has, what I believe is, a good article for beginners while the Adequately Good post goes more in-depth yet it's still accessible. They all cover the Module pattern. You will actually found many Module patterns - in those resources and around the web. What the Module allows you to do is have something similar to public and private from other languages. I will not try to explain it, since I think other people have done it way better than I can. However, I will just do a very brief explanation what a Module is. Again, other resources can cover this better.

A Module leverages a JavaScript feature called Closure more information here and here (one of the most upvoted StackOverflow questions). Remember how I said, there are two scopes in JavaScript? A closure, to put it simply, provides a functional scope. Here is how it looks like:

 (function() { /* your code goes here */ })()

To dissect this briefly you have a function with your code an that is enclosed in (/* function goes here */)(). In effect what this does is that executes the function so everything inside is put into functional scope. It is very powerful, however, and here is an example

var closure = (function() { 
    var privateVar = "secret";
    return {
       publicVar: 42,
       getPrivateVar() { return privateVar; }
    }
})()

console.log(closure.publicVar); //42
console.log(closure.getPrivateVar()); //"secret"
//let's change this
closure.publicVar = 5;
closure.privateVar = "changed";

console.log(closure.publicVar); //5
console.log(closure.getPrivateVar()); //"secret"

And just like that we have (something resembling) a private field. Again, var privateVar will stay "bottled up" inside the function scope and would not be accessible outside. Incidentally, this is an example of the Module pattern. Instead of var closure I could have called it myModule. It is a rather simplistic take on it but, here is the thing - it doesn't get more complicated. All the different Modules boil down to very similar things - you just expose data in different manners. Yet, the concept is similar - the "private" fields stay inside, and the "public" ones, you can access from elsewhere.

This is long, but hopefully should cover the basics you need to get going.

这篇关于一个Javascript模块中的变量在它之外可见?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆