理解在Javascript中称为方法和构造函数的函数的私有性和范围

时间:2013-06-02 12:36:46

标签: javascript closures

请考虑以下代码:

function Outer(){
  function Inner(){
    var private="something";
    this.method = function(){    
     //some code here    
   };
  }

 var inner = new Inner(); //Why does this line not throw an error?
 alert(inner.private); // not accessible here
 inner.method();//no errors here
}

我无法理解为什么method()调用不会抛出错误而变量引用会抛出错误?我理解变量的范围只在声明它们的函数中?但是功能的范围呢?

2 个答案:

答案 0 :(得分:3)

没有什么复杂的,它与数据类型无关。

new Inner()创建一个新对象。您正在构造函数

中为该对象分配属性
this.method = function(){...};

另一方面,没有这样的属性private。你永远不会this.private = ...;private只是Inner函数的本地变量。

这是另一个与你的代码等效的例子,但希望更清楚:

function createObject() {
    var someVariable = '42';
    var obj  = {};
    obj.foo = 'bar';
    return obj;
}

var myObject = createObject();
// works, since we assigned the property to the object
console.log(myObject.foo); 
// does not work, we never assigned such a property to the object
console.log(myObject.someVariable); 

createObject内部声明了两个变量,someVariableobjobj是一个对象,我们为它分配一个属性并从函数返回它。 someVariable与对象无关,但可以在函数中用于其他目的。

答案 1 :(得分:1)

line var inner = new Inner()确实会抛出错误,因为内部未定义,它只能在外部函数的主体内访问。

inner.private不能作为inner的属性访问,因为它是closure variable。所以(new Inner())。private不存在。 (私有似乎是JS中的关键字,所以我在示例代码中将其更改为priv)

它可以在Inner函数体中访问,因为函数体内的代码保持对闭包变量的引用。

  function Inner(){
    var priv="something";
    this.method = function(){//wrong, should declare as prototype
     console.log("private from within Inner function body:"
       ,priv)
    };
  }

var inner = new Inner();
console.log(inner.priv); //=undefined
inner.method();//=something

具有许多实例的对象的函数属性;像Inner可以有很多例子:var a = new Inner(); var b = new Inner()...不应该用这个来定义。你应该使用原型代替。

当您使用原型时,您不能在原型函数中使用私有变量,因为私有(闭包)变量只能在主函数体中访问。这就是为什么许多开发人员使用_privateprivate_来表明它是私有的,因为JavaScript没有一个很好的方法来使成员变得私有而不会弄乱原型。

function Inner(){
  var priv="private";//wrong
  this._priv="private"
}
Inner.prototype.method=function(){
  //cannot access priv
  console.log(this._priv);//no problem
}

可能有一种情况,您可以通过这种方式使用私有,即只有一个对象实例。

var Mediator=(function(){
  var events={};//private, other code can't mess this up
  return{
    addEvent:function(eventName){
      events[eventName]=(events[eventName])?
        events[eventName]:[];
    },
    addLisener:function(eventName,func){
      events[eventName].push(func);
      return events[eventName].length-1;
    }
    //more stuff like removeListener, trigger ...
  }
})()

您可以阅读有关原型in this basic example的信息。您可以使用firebug控制台在Chrome或Firefox中运行代码。按F12打开它并粘贴控制台中该链接的代码。然后根据需要调整它,看看你是否得到了预期的输出并理解JS中的原型。