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

时间:2013-06-25 14:49:36

标签: javascript

我有这个构造函数有一个秘密和一个方法:

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"

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

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

3 个答案:

答案 0 :(得分:2)

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

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"]; 
    }
}

答案 1 :(得分: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. 我们通过创建Immediately Invoked Function Expression (IIFE)来创建命名空间。
  2. 我们创建了一个名为key的对象。此对象是我们刚刚创建的命名空间的私有对象。因此,只有特权函数和构造函数才能访问它。
  3. 在构造函数中,我们创建了一个名为private的对象,它保存每个实例的私有状态。
  4. 我们还创建一个名为getPrivate的特权方法,该方法接受参数k,并且只有k是我们在步骤2中创建的key时才返回私有对象。因此只有特权函数才能访问私有对象。
  5. 想要访问对象私有状态的特权函数必须调用getPrivate(key)来获取私有状态对象。
  6. 注意:此方法仅在您有多个特权函数需要访问对象的私有状态时才有用。此外,调用getPrivate会给特权函数带来(非常)小的性能开销。


    BTW如果你想在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;
        }
    }, {});
    

答案 2 :(得分: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);   
    }
}

这里我们为您的get方法定义setter和getter,这样您就可以通过这种方式初始化对象:

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/