2015-08-19 4 views
7

у меня есть что-то похожее на это:Как сохранить javascript «этот» контекст внутри одноэлементного шаблона?

var a = (function() { 

    return { 

     b: 1, 
     c: function() { 

      console.log(this.b); 
     } 
    }; 
})(); 

Так,

a.c(); // = 1 

Но если я

b = 2; 
a.c.apply(this); // = 2 

Можно ли сохранить контекст "этого" внутри «ас() ", не меняя (слишком много) структуру" a "объекта? У меня нет контроля над вызовом функции, поэтому мне нужно обходное решение, чтобы справиться с этим внутри самого объекта.

UPDATE:

Чтобы быть более точным, это структура моих файлов:

Структура 1 (Singleton как шаблон):

var a = (function() { 

    var _instance; 

    function init() { 

     return { 

      b: 1, 
      c: function() { 

       console.log(this.b); 
      } 
     }; 
    } 

    return { 

     getInstance: function() { 

      if (_instance === undefined) { 
       _instance = init(); 
      } 

      return _instance; 
     } 
    } 
})(); 

Структура 2:

var b = { 

    c: 1, 
    d: function() { 
     console.log(this.c); 
    } 
}; 

РЕШЕНИЕ:

Я реализовал решение, основанное на ответе Маху, и разделил оператор return внутри init(), поэтому он остается безопасным для контекста объекта (и экземпляра) в любой ситуации.

Для одноплодной схеме:

var a = (function() { 

    var _instance, 
     self; 

    function init() { 

     return self = { 

      b: 1, 
      c: function() { 

       console.log(self.b); 
      } 
     }; 
    } 

    return { 

     getInstance: function() { 

      if (_instance === undefined) { 
       _instance = init(); 
      } 

      return _instance; 
     } 
    }; 
})(); 

Для литерала объекта:

var b = (function() { 

    var self; 

    return self = { 
     c: 1, 
     d: function() { 
      console.log(self.c); 
     } 
    }; 
})(); 

Так

a.getInstance().c(); // 1 
a.getInstance().c.apply(this); // 1 
setTimeout(a.getInstance().c, 1); // 1 
$.ajax({ complete: a.getInstance().c }); // 1 
+0

The * аналогичный * код дает ошибку: 'Uncaught SyntaxError: Неожиданный маркер:'. –

+2

'a.c()' не возвращает функцию, поэтому вы не можете вызвать метод 'apply'. Вы имели в виду 'a.c.apply (this)'? – Barmar

+0

@SpencerWieczorek это просто причина, по которой 'return' находится в другой строке –

ответ

2

Вы можете немного изменить способ вы возвращаете объект из анонимной функции:

var a = (function() { 
    var result = {}; 
    result.b = 2; 
    result.c = function() { 
    console.log(result.b); 
    }; 
    return result; 
})(); 

Это должно иметь тот же эффект, однако это приводит к удалению использования this.

Если вы не можете позволить себе изменить структуру a этого много, то вы можете поочередно (много) более опасно использовать:

a.c.apply = function() { // Stops the apply function working on a.c by overriding it 
    return a.c(); 
} 

Если вы выбираете это, хотя вы должны быть осторожны, что в любое время a.c.apply является его использование больше не будет работать «как ожидалось», однако оно будет исправлять проблему, представленную здесь.

+0

Спасибо, это может быть решение, и я постараюсь применить это завтра. a.c.apply был предназначен только для показа тестового примера. Более близким примером является передача функции в качестве функции обратного вызова в jQuery или js-функциях, таких как setTimeout() –

+0

В этом случае использование 'acbind' для обеспечения' a' задано корректным контекстом 'this' – Mahout

+0

Я не могу реорганизовать вся система (например, изменение всех объектных вызовов всех объектов), вот моя главная проблема. Я ищу объектно-ориентированное решение, которое работает для обратных вызовов jQuery (например, $ .ajax ({success: ac)) или setTimeout (ac, 1) или даже call()/apply(), поскольку я динамически переписываю некоторые функции браузера, такие как «alert» –

0

Вы можете сделать это:

var a = (function() 
{ 
    return { 
     b: 1, 
     c: function() 
     { 
      console.log(this.b); 
     } 
    } 
})(); 

var decorator = function() { return a; }; 

var b = 2; 

decorator.call(this).c(); // => 1 

В основном это выглядит, как вы хотите, чтобы связать IIFE и не объект, который возвращается к внешнему сферы, так что вложенный возвращаемый объект сохраняет значение внутренней b.

+0

Спасибо. В «функции decorator = function ..» есть синтаксическая ошибка (вы можете удалить «функцию» в начале). BTW «.apply()» должен был только продемонстрировать изменение области, но таким образом я больше не смогу назвать «a.c()» или «decorator.c()». Более того, такие вещи, как «setTimeout (decorator.call (this) .c, 1)», будут по-прежнему получать доступ к глобальной области. –

1

Я сделал эту ручку, чтобы проиллюстрировать разницу, я надеюсь, что это помогает:

http://codepen.io/dieggger/pen/BNgjBa?editors=001

var a = (function() { 
    return { b: 1, 
      c: function() { 
       console.log(this.b); 
      } 
    }; 
})(); 


a.c(); //prints 1 


b = 2; // global variable "b" which is being hoisted BTW 


// The following will act like this: 

//it throws "cannot read property 'apply' from undefined" 
//though it prints "1" since the first part invokes the "c" function 
//inside of the"a" module which has the console.log 

a.c().apply(this); 


//In this case "this" is the window object which has the variable "b" 
a.c.apply(this); // it'll print 2 
+0

Извините, я исправил код. –

+0

Итак ... можете ли вы подробно рассказать о том, что вы хотите сделать? Теперь я смущен ... –

+0

Идея состоит в том, чтобы сохранить шаблон singleton (я обновил вопрос) и нотацию объекта, так как это сложный env, и я не могу реорганизовать все, чтобы справиться с этим. Моим обходным решением теперь (ужасающим) является вызов objectName.getInstance(). functionName () "или просто" objectName.functionName() "внутри области функций, то же самое для возвращаемых значений (для цепочки). –

Смежные вопросы