2

好吧,我有一个带有一个秘密和一个方法的构造函数:

function Keeper(get) {
    var secretPower = 'wisdom';

    this.get = get ? get : function () { 
        return 'Its secret power is: ' + secretPower; 
    }
    // now this is privileged method only in case that there are no arguments?
}

现在我将创建两个实例,一个具有特权方法...

var yourKeeper = new Keeper();
yourKeeper.get();       // "Its secret power is: wisdom"

...但另一个是不同的。它可以触及它周围的上下文,但不能触及构造函数的私有...

var myKeeper = new Keeper(function() { 
        return 'Its secret power is: ' + secretPower; 
    });
myKeeper.get();         // ReferenceError: secretPower is not defined

...这也不能按我的意愿工作:

myKeeper.get = function() { 
    return 'Its secret power is: ' + secretPower; 
}
myKeeper.get();         // ReferenceError: secretPower is not defined

当然它不会起作用,因为secretPower在这些情况下是全局变量,所以:

var secretPower = 'none';
myKeeper.get();         // "Its secret power is: none"

那么是否可以在构造函数之外定义特权方法?如何?

可以用eval完成吗?(我知道......这是邪恶的......我只是感兴趣)

4

3 回答 3

2

javascript 中作用域背后的想法是,这不应该是可能的,我建议getPrivate在构造函数的范围内添加一个函数并使用它来访问“私有”变量。

function Keeper(get) {
    var semiPrivates = {
        secretPower:'Wisdom'
    }

    this.getPrivate = function (variable){
        return semiPrivates[variable];
    }

    this.get = get ? get : function () { 
        return 'Its secret power is: ' + semiPrivates["secretPower"]; 
    }
}
于 2013-06-25T14:55:38.767 回答
2

是的,可以在构造函数之外定义特权方法。这是如何做到的:

var Keeper = (function (key) {
    function Keeper(get) {
        var private = {
            secretPower: "wisdom"
        };

        this.getPrivate = function (k) {
            if (k === key) return private;
        };

        this.get = get || defaultGet;
    }

    function defaultGet() {
        var private = this.getPrivate(key);
        return "The secret power is: " + private.secretPower;
    }

    return Keeper;
}({}));

下面是它的工作原理:

  1. 我们通过创建立即调用函数表达式 (IIFE)来创建命名空间。
  2. 我们创建一个名为 的对象key。这个对象是我们刚刚创建的命名空间私有的。因此,只有特权函数和构造函数可以访问它。
  3. 在构造函数内部,我们创建了一个名为的对象,该对象private保存每个实例的私有状态。
  4. 我们还创建了一个名为的特权方法getPrivate,该方法接受一个参数,如果是我们在步骤 2 中创建的,k则仅返回私有对象。因此,只有特权函数才能访问私有对象。kkey
  5. 想要访问对象的私有状态的特权函数必须调用getPrivate(key)以获取私有状态对象。

注意:此方法仅在您有多个需要访问对象私有状态的特权函数时有用。此外,该调用getPrivate为特权函数引入了(非常)小的性能开销。


顺便说一句,如果您想在 JavaScript 中编写干净的面向对象代码,请查看该augment库。上面的代码看起来像这样使用augment

var Keeper = Object.augment(function (key) {
    this.constructor = function (get) {
        var private = {
            secretPower: "wisdom"
        };

        this.getPrivate = function (k) {
            if (k === key) return private;
        };

        this.get = get || defaultGet;
    };

    function defaultGet() {
        var private = this.getPrivate(key);
        return "The secret power is: " + private.secretPower;
    }
}, {});
于 2013-06-25T15:49:01.443 回答
1

我永远不会真正这样做,但这里有一个解决方案eval

function test(){
    var private = 'hello';

    this.say = function(){

    }

    this.setSay = function(func){
        eval('this.say = ' + func.toString());
    }
}

var x = new test();
x.setSay(function(){
    console.log(private + ' world');
});
x.say();

例如http://jsfiddle.net/claustrofob/AwMd3/

这是一个与您的Keeper对象相关的示例:

function Keeper(get) {
    var secretPower = 'wisdom';
    var getFunc = function () { 
        return 'Its secret power is: ' + secretPower; 
    };

    var evalFunc = function(variable, val){
        eval(variable + ' = ' + val.toString());
    };

    this.__defineSetter__("get", function(val){
        evalFunc('getFunc', val);
    });

    this.__defineGetter__("get", function(val){
        return getFunc;
    });

    if (get !== undefined){
        evalFunc('getFunc', get);   
    }
}

在这里,我们为您的方法定义了 setter 和 getter,get因此您可以这样初始化对象:

var x = new Keeper(function () { 
    return 'Its secret power is: ' + secretPower; 
});

这样:

var x = new Keeper();
x.get = function () { 
    return 'Its secret power is: ' + secretPower; 
};

现场示例http://jsfiddle.net/claustrofob/yu6VJ/

于 2013-06-25T15:20:45.433 回答