10

这是一个带有公共和私有方法的简单 Javascript 类的示例(小提琴:http: //jsfiddle.net/gY4mh/)。

function Example() {
    function privateFunction() {
       // "this" is window when called.
       console.log(this);
    }

    this.publicFunction = function() {
       privateFunction();
    }
}

ex = new Example;
ex.publicFunction();

从公共调用私有函数会导致“this”成为窗口对象。我应该如何确保使用类上下文而不是窗口调用我的私有方法?这是不可取的吗?

4

8 回答 8

9

使用闭包。基本上,在函数中声明的任何变量,仍然可用于该函数内的函数:

var Example = (function() {
    function Example() {
        var self = this; // variable in function Example
        function privateFunction() {                  
            // The variable self is available to this function even after Example returns. 
            console.log(self);
        }

        self.publicFunction = function() {
            privateFunction();
        }
    }

    return Example;
})();

ex = new Example;
ex.publicFunction();
于 2013-04-26T00:19:21.983 回答
3

另一种方法是使用“应用”来明确设置“this”应该绑定的方法。

function Test() {
    this.name = 'test';
    this.logName = function() {
        console.log(this.name);
    }
}

var foo = {name: 'foo'};

var test = new Test();
test.logName()
// => test
test.logName.apply(foo, null);
// => foo

另一种方法是使用“调用”:

function Test() {
    this.name = 'test';
    this.logName = function() {
        console.log(this.name);
    }
}

var foo = {name: 'foo'};

var test = new Test();
test.logName()
// => test
test.logName.call(foo, null);
// => foo

“应用”和“调用”都将要绑定“this”的对象作为第一个参数,并将参数数组作为第二个参数传递给您正在调用的方法。

于 2013-04-26T00:33:33.513 回答
3

this除了让某人告诉您代码修复之外,还值得了解如何确定 javascript 中的值。在javascript中,this是通过以下方式确定的:

  1. 如果你通过对象属性调用函数object.method(),那么this将被设置为方法内的对象。

  2. 如果你直接调用一个没有任何对象引用的函数,例如function(),那么this将被设置为全局对象(window在浏览器中)或在严格模式下,它将被设置为undefined.

  3. 如果您使用new运算符创建一个新对象,则该对象的构造函数将被调用,并将值this设置为新创建的对象实例。你可以认为这和上面的第 1 项一样,创建了对象,然后调用了它上面的构造方法。

  4. .call()如果您使用or调用函数.apply()function.call(xxx)那么您可以准确确定this传递给.call()or的参数所设置的内容.apply()。你可以在 MDN 上阅读更多关于.call()这里.apply()这里的信息。

  5. 如果你使用function.bind(xxx)它会创建一个小的存根函数,以确保你的函数被调用时使用所需的this. 在内部,这可能只是使用.apply(),但它是当您想要一个回调函数时的快捷方式,该函数将在调用时具有正确的值this(当您不是该函数的直接调用者时)。

  6. 在回调函数中,回调函数的调用者负责确定所需的值this。例如,在事件处理回调函数中,浏览器通常设置this为正在处理事件的 DOM 对象。

MDN 上对这些不同的方法进行了很好的总结。

因此,就您而言,当您调用privateFunction(). 因此,正如预期的那样, 的值this设置为上面的选项 2。

如果你想this在你的方法中明确地设置它的当前值,那么你可以这样做:

var Example = (function() {
    function Example() {
        function privateFunction() {
            // "this" is window when called.
            console.log(this);
        }

        this.publicFunction = function() {
            privateFunction.call(this);
        }
    }

    return Example;
})();

ex = new Example;
ex.publicFunction();

其他方法,例如使用闭包和定义var that = this,最好用于回调函数的情况,当您不是函数的调用者,因此不能使用 1-4。在您的特定情况下,没有理由这样做。我会说使用.call()是一种更好的做法。然后,您的函数实际上可以使用this并且可以像私有方法一样运行,这似乎是您寻求的行为。

于 2013-04-26T00:56:38.530 回答
2

我想最常用的方法是通过简单地缓存(存储)this本地上下文变量中的值

function Example() {
    var that = this;
    // ...
    function privateFunction() {
        console.log(that);
    }

    this.publicFunction = function() {
       privateFunction();
    }
}

一种更方便的方法是调用Function.prototype.bind将上下文绑定到函数(永远)。然而,这里唯一的限制是这需要一个支持 ES5 的浏览器,并且绑定的函数会稍微慢一些。

var privateFunction = function() {
    console.log(this);
}.bind(this);
于 2013-04-26T00:18:17.423 回答
1

我想说正确的方法是使用原型设计,因为它毕竟是 Javascript 的设计方式。所以:

var Example = function(){
  this.prop = 'whatever';
}

Example.prototype.fn_1 = function(){
  console.log(this.prop); 
  return this
}

Example.prototype.fn_2 = function(){
  this.prop = 'not whatever';  
  return this
}

var e = new Example();

e.fn_1() //whatever
e.fn_2().fn_1() //not whatever

这是一个小提琴http://jsfiddle.net/BFm2V/

于 2013-04-26T01:24:23.903 回答
0

如果您不使用 EcmaScript5,我建议您使用 Underscore 的(或 LoDash 的)绑定函数。

于 2013-04-26T00:24:21.473 回答
0

除了这里给出的其他答案之外,如果您没有支持 ES5 的浏览器,您可以使用如下代码非常简单地创建自己的“永久绑定函数”:

function boundFn(thisobj, fn) {
   return function() {
      fn.apply(thisobj, arguments);
   };
}

然后像这样使用它:

var Example = (function() {
    function Example() {
        var privateFunction = boundFn(this, function() {
            // "this" inside here is the same "this" that was passed to boundFn.
            console.log(this);
        });

        this.publicFunction = function() {
            privateFunction();
        }
    }

    return Example;
}()); // I prefer this order of parentheses

瞧——this神奇地是外部上下文this而不是内部上下文!

如果您的浏览器中缺少类似 ES5 的功能,您甚至可以获得类似 ES5 的功能(如果您已经拥有它,这将不起作用):

if (!Function.prototype.bind) {
   Function.prototype.bind = function (thisobj) {
      var that = this;
      return function() {
         that.apply(thisobj, arguments);
      };
   }:
}

然后使用var yourFunction = function() {}.bind(thisobj);完全相同的方式。

完全兼容(尽可能)、检查参数类型等的类 ES5 代码可以在mozilla Function.prototype.bind中找到。如果您正在使用功能做一些不同的高级事情,那么有些差异可能会让您感到困惑,因此如果您想走这条路,请在链接上阅读。

于 2013-04-26T00:27:52.163 回答
0

我会说分配selfthis是一种常见的技术:

function Example() {
    var self = this;

    function privateFunction() {
        console.log(self);
    }

    self.publicFunction = function() {
        privateFunction();
    };
}

使用apply(正如其他人所建议的那样)也有效,尽管在我看来它有点复杂。

它可能超出了这个问题的范围,但我也建议考虑一种不同的 JavaScript 方法,你实际上根本不使用this关键字。我在 ThoughtWorks 的前同事 Pete Hodgson 写了一篇很有帮助的文章,无类 JavaScript,解释了一种方法来做到这一点。

于 2013-04-26T01:09:59.027 回答