“特权”方法调用成员方法问题

时间:2011-06-10 23:08:24

标签: javascript javascript-framework

请考虑以下代码:

function Dog()
{
    this.foo = function() {};

    this.walk = function()
    {
        if(canWalk())
        {
            alert('walking');
            return;
        }

        alert('I have no legs!');
    }

    canWalk = function()
    {
        this.foo();
        return false;
    }
}

var instance = new Dog();
instance.walk();

使用“特权”canWalk()方法的代码中存在一个错误,假设this指针指向Dog的实例。它实际上似乎指向令我困惑的全球对象!我已经读过,由于闭包,我可以在构造函数的范围内获取对this的引用,然后在我的“特权”方法中使用该引用,但这看起来像是一个黑客。

我几乎没有掌握this指针在各种情况下的行为。我知道“附加”到对象的方法将收到指向附加对象的this。例如,foo.doStuff()会有一个this指向foo个实例。

令人不安的是,虽然我认为自己很聪明并且在我的OBJECT上创建了“特权”方法,但似乎我实际上将功能转移到全球范围内!也许有一个名为init()的全局方法(很可能)来自另一个库或文件而不是我自己的创建。如果我然后使用名为init()的“特权”方法定义了一个漂亮的小封装对象,我将替换另一个全局init()方法。

我的问题是,创建“特权”方法(以及相关字段)的最佳做法是什么,这些方法的作用域是它们所属的对象?我的示例对象的其他方法将提供私有或特权方法,同时还适当地确定范围。我不是在寻找符合要求的模糊解决方案,而是寻求最佳实践。

3 个答案:

答案 0 :(得分:4)

请勿使用this。将var self = this;放在Dog函数的顶部并使用self。这样你就会对狗有一个“安全”的引用。

在您的示例this中应指向Dog,除非我也遗漏了某些内容。

至于您的特权方法,您忘了定义变量。添加var canWalk;

还有另一种方式:关闭。我举一个例子:

function create_dog() {
    function canWalk() {
        return false;
    }
    function walk() {
        if (canWalk()) {
            alert("walking");
            return;
        }
        alert("I have no hands!");
    }
    return {
        "walk": walk // points to the function walk()
    }; // this the API of dog, like public functions (or properties)
}
var dog = create_dog();
dog.walk();

现在您不需要thisnew。另外你可以这样做:

function create_dog() {
    function canWalk() {
        return false;
    }
    function walk() {
        if (canWalk()) {
            alert("walking");
            return;
        }
        alert("I have no hands!");
    }
    var dog = {
        "walk": walk
    };
    return dog;
}
var dog = create_dog();
dog.walk();

因此,您可以在priveledges函数中引用dog如果您不打算使用原型设计,我会建议关闭方法。

顺便说一下。为避免混淆:

function my_func() {}

var my_func = function () {};

是等同的。如果你在两个函数之间有一个循环引用,并且你想强制使用define-before-use,那么后者可能很有用。

答案 1 :(得分:1)

首先,您需要在var前面canWalk。这样,canWalk函数仅限于dog()的范围,而不是隐式全局。

this指向该函数的“所有者”。使用new运算符时,该函数会创建自己的范围。因此,在dog()的主体内,this指的是狗实例对象。在walk函数中,this也引用了dog实例,因为您将walk函数设置为dogthis.walk = function () { ... })的实例。但是,在canWalk中,没有所有者,因此this指向全局对象window

我意识到我的解释可能会令人困惑,所以这里是我解释的代码注释版本:

var obj = {
    'f': function () {
        // this === obj, because obj "owns" this function
        // In other words, this function is callable by obj.f()
    },
    'o': {
         'f': function () {
             // this === obj.o, because obj.o "owns" this function
             // In other words, this function is callable by obj.o.f()
         }
    }
};

// The new operator essentially sets "this" within the 
// function to an empty object and returns that object
var instance = new Dog();

function Dog() {
    // this === instance, because of the "new" operator

    // For demonstration
    var self = this;

    this.walk = function () {
        // this === instance === self, because self/instance "owns" this function
        // In other words, this function is callable by self.walk()
    };

    var canWalk = function () {
        // What's the owner of this object? Nothing,
        // so it defaults to the global object, window
        // this === window

        // Instead, we can access the Dog instance by
        // using the "self" variable we set earlier.
        // self === instance
    };
}

希望能够解决问题。

答案 2 :(得分:1)

正如您所收集的那样,直接调用canWalk就意味着'this'关键字被设置为该函数调用的全局对象。

如果你想在当前狗的上下文中运行调用,你可以这样明确地这样做:

canWalk.call(this)