1

我试图理解这个插件系统,但有点困惑。

var obj={};
obj.plugin={
create: function(pluginname){
    var default_value='p1';
    var f1 = function(){
            alert(default_value);
            //define plugin properties
        }
    obj[pluginname] = function(){return new f1();}
    /*
    run other code here
    */
    return {
        //
        f2: function(args){
            default_value=args;
        }                    
    }
}
};
obj.plugin.create('pluginA').f2('pa');
obj.plugin.create('pluginB').f2('pb');
obj.pluginA();  // pa
obj.pluginB();  // pb

我认为结果应该是这样的:

obj.pluginA();  // pb
obj.pluginB();  // pb

另一个问题是:'new f1()' 直到最后两行才会运行。'default_value' 存储在哪里?

4

1 回答 1

0

先来一点源码解释:

var obj={};
obj.plugin={
// object plugin property is an object that has create property defined here
// create property is a function that adds another properties to object in general
create: function(pluginname){
    // this default value has got 'var' modifier - it is local and has scope of 'create'
    var default_value='p1';
    // f1 is a plugin's function - it does what a plugin creator implements
    var f1 = function(){
            // it encloses 'default_value' locally in 'create'
            alert(default_value);
            //define plugin properties
        }
    // the line below is the creation of a new property, which allows the object
    // to call a method of name of a plugin; it assigns to the property of that name
    // the f1 function closure, but local to actual execution of 'create';
    // note the use of 'new' operator which copies the function making it independent
    // from other calls of 'create'
    obj[pluginname] = function(){return new f1();}
    /*
    run other code here
    */
    return {
        // this function allows you to change 'default_value' still in scope
        // of the same call of 'create', thus effectively changing that one (locally - it's 'var');
        f2: function(args){
            default_value=args;
        }                    
    }
// after leaving this brace you leave the 'create' scope
}
// and the plugin object scope
};

现在它将如何工作:

This:obj.plugin.create('pluginA').f2('pa');
询问插件属性create,它是一个函数,用'pluginA'字符串调用。要调用该函数,js 会创建调用的上下文(实际上是堆栈顶部的一些结构化对象)。'pluginA'入栈作为参数,default_valuef1作为f2局部变量入栈。然后create执行函数。首先初始化变量,然后是这个赋值 obj[pluginname] = function(){return new f1();}

这会pluginA在对象中创建属性。请注意,然后局部函数 f1 被传递到范围之外,object作为属性传递给全局。然后有一条return语句从堆栈中弹出所有局部变量和所有实际参数并放入返回值,该值逃脱了调用范围。然后就剩下范围了。

这里发生了一个小技巧。返回的值是一个对象,该对象具有一个函数,该函数从已离开的范围内引用了“default_value”。这是可能的,因为事实上,实际对象存储在堆上,而堆栈上只有对这些对象的引用。这意味着它default_value仍然存在于堆上,并被f2该返回对象中的函数引用。

f2被调用时,控件进入f2调用范围。由于它已在其中定义,create因此它引用default value了堆上的对象。由于它可以访问该对象,因此也可以将其更改为'pa'. 留下thenf2的调用范围,分号后面的返回值也留下。该f1函数还具有对 的引用default_value,现在等于'pa'。该函数在 a 的属性中f1是“封闭的” 。'pluginA'object

这意味着,一个全局object现在有一个属性pluginA,它是一个函数(被命名为f1)。该函数引用了一个对象(名为default_value)。而那个对象是一个字符串'pa'这些值通过始终可访问的间接引用保持可访问object

这:obj.plugin.create('pluginB').f2('pb');
分别对其他参数做同样的事情,因此pluginB在对象中创建属性。这是另一个电话create,所以它有了一个全新的default_value。那是另一个本地实例。同样的魔法object在另一个属性(pluginB)中关闭了全局中的新对象。Create返回一个包含新函数的新对象f2。那个 is 可以访问那个 'newer' default_value,但与上一个调用中的那个无关。当f2在另一个返回的对象上调用时,它会将“新”更改default_value'pb'.

在那之后,下面是不言自明的......

obj.pluginA();  // pa
obj.pluginB();  // pb
于 2012-09-17T09:27:34.297 回答