Javascript范围引用外部对象

时间:2013-01-10 21:12:41

标签: javascript jquery closures encapsulation joose

基本上,我使用一个名为Joose的元类框架用于Javascript,它允许我使用更优雅的类语法 - 但我不知道如何引用对象的范围来自更深层次的类声明方法。我还使用require.js进行dependemcy管理...

这是一个示例类定义:

   define([
      'jquery',
      'handlebars',
   ], function($, Handlebars){

      var MyClass = Class("MyClass", {

         //inheritance         
         isa: SuperClass,

         //instance vars
         has: {

            hello:{
               is: 'r',
               init: 'Hi There!',
            },

            someVarToBeSetUsingAjax:{
               is: 'rw',
               init: false,
            },
         },

         //methods
         methods: {

            init: function () {

               var self = this;
               self.getAjaxVar();

            },

            getAjaxVar: function() {

               var self = this;

               //HOW CAN I REFERENCE 'self' THROUGHOUT MY OBJECT?

               $.get('ajax/test.html', function(response) {
                 self.someVarToBeSetUsingAjax = response.value;
               });
            },

            //lots more methods...

         }
    });

   return MyClass;

});

好吧,我的问题是 - 在AJAX函数中我必须编写var self = this来使我的对象进入AJAX调用的范围 - 没问题。但是,我发现自己在我的班级声明中几乎每一个方法都这样做!如何以干净有效的方式在所有方法中引用self?我知道你可以通过设置一个参数来使用AJAX中的范围,假设它不仅仅是AJAX,而是将范围关闭到外部的其他函数。

感谢。

4 个答案:

答案 0 :(得分:2)

每次嵌套函数时,都必须考虑this。但是如果你没有嵌套一个函数,或者该函数没有使用this,你就不需要考虑它了。

        init: function () {
           var self = this;
           self.getAjaxVar();
        },

所以在这种情况下没有必要。这完全一样:

        init: function () {
           this.getAjaxVar();
        },

但是在这里:

        getAjaxVar: function() {
           var self = this;

           $.get('ajax/test.html', function(response) {
             self.someVarToBeSetUsingAjax = response.value;
           });
        },

您创建了一个内部函数,并希望引用this的原始值,因此您必须将this别名设为self才能使其可访问。

没有办法将this修复为您班级中任何地方的值。


那就是说,你确实有一些选择。

Function.prototype.bind()可以提供帮助。

var func = function() { return this.name };
var obj = { name: 'Bob' };
var boundFunc = func.bind(obj);
boundFunc(); // 'Bob'

bind将返回一个新函数,this始终设置为特定对象。

所以:

        getAjaxVar: function() {
           $.get('ajax/test.html', function(response) {
             this.someVarToBeSetUsingAjax = response.value;
           }.bind(this));
        },

请注意,并非所有浏览器都支持此功能,您可能需要使用旧版本的垫片。

或者只是习惯self = this


我想对coffeescript进行一次轻微的点头,因为它支持声明在运行时不会改变上下文的函数。

obj = {
  name: "bob"
  sayHello: ->
    doSomeAjax({
      success: =>
        alert "successfully made " + this.name + " say hello!"
    })
}

obj.sayHello()

->发挥正常作用。但是胖箭=>将保留函数内外this的值。它在实例方法中的回调非常方便。当编译为JS时,它基本上为你做了self = this别名,每次在内部函数中使用self来引用this。它很漂亮。

在简单的JS中,最常见的模式只是self = this,坚持下去。

答案 1 :(得分:1)

答案是使用this。你只需要创建一个闭包(当你有一个将被称为对象外部的函数时,你可以用var self = this;创建一个闭包。(正如你在这里用ajax调用返回的那样)。

没有其他方法可以创建闭包。


要清楚(因为有些人会在任何轻微的技术手上挥动),你不需要“创造”闭合。但我认为你应该 - JavaScript设计用于闭包,它们运行良好,并且其他JavaScript程序员也很好理解。

答案 2 :(得分:0)

  

我发现自己在我的班级声明中几乎每一个方法都这样做了!如何以干净有效的方式在所有方法中引用自我?

你做不到。 self的值(this引用的实例)仅在调用方法时才知道。

如果您在构造函数(您的self方法中)声明了这个变量并且在那里创建了所有回调函数,那么您只能解决这个问题并使用一个常见的init变量。但是,可能不是最节省内存的方法:

return Class("MyClass", {
     // …

     methods: {
         init: function () {
             var self = this;
             this.ajaxVarCallback = function(response) {
                 self.someVarToBeSetUsingAjax = response.value;
             };
             // and other functions that use "self"

             this.getAjaxVar();
         },
         getAjaxVar: function() {
             $.get('ajax/test.html', this.ajaxVarCallback);
         },
         // …
     }
});

答案 3 :(得分:0)

除了始终将MyClass的所有实例保留在范围内(或作为全局变量)之外,我没有看到任何解决方案。但是,您可以通过使用self

取消在任何地方声明Function.prototype.bind
$.get('ajax/test.html', function(response) {
  this.someVarToBeSetUsingAjax = response.value;
}.bind(this));

这不仅限于$ .get(),您可以在使用回调函数的任何地方使用它。