2015-02-10 1 views
-1

Так как методы в Javascript можно легко отскочить, некоторые (многие?) Разработчики прибегают к использованию лексического охвата JS для достижения инкапсуляции объектов (то есть, состояния частного объекта, независимо от объекта, к которому привязан метод в настоящее время). Я нашел это особенно удобно при работе с обещаниями, как это:Как я могу достичь инкапсуляции объектов с использованием классов EcmaScript 6?

function Something() { 
    const that = this; // optional 
    that.state = 0; 
    this.doSomething = function() { 
     console.log(that.state++); 
    }; 
    return this; 
} 

const instance = new Something; 
new Promise(resolve => resolve(instance)).then(instance.doSomething); 
//output: 0 

К сожалению, это не похоже, чтобы быть совместимым с текущим проектом ECMAScript 6 классов. Этот код:

class SomethingES6 { 
    constructor(){ 
     this.state = 0; 
    } 
    doSomething(){ 
     console.log(this.state++); 
    } 
} 

const instanceES6 = new SomethingES6; 
new Promise(resolve => resolve(instanceES6)).then(instanceES6.doSomething); 

Выдает, поскольку метод doSomething не связан с экземпляромES6 при его выполнении. Есть ли способ достичь такого поведения, как тот, который появляется при использовании лексического охвата «этого» в предыдущем фрагменте?

Я хочу решение, которое обеспечивает такое поведение при определении класса - bluebird (и другие) Promise.bind не является решением! Лично мне хотелось бы решение, которое работает в узле, но, конечно, предпочтительным является общее решение.

+0

'bind' абсолютно решение. Предварительная привязка раздражает. Вы также, кажется, рассматриваете обетования как завернутую версию обратных вызовов, а это не так; попробуйте 'Promise.resolve (instanceES6) .then (instance => instance.doSomething())', например – Ryan

+0

Важное примечание: 'instance.doSomething' --- эта ссылка на функцию не является экземпляром' instance', когда он вызывается по обещанию. – zerkms

+0

@minitech: то, что вы предлагаете, создает много шаблонов кода, в частности, для долговечных цепей. И, как и все шаблоны, он довольно хрупкий: я (или кто-то еще) забывает или случайно удаляет «разрешение/привязку», и я трачу на полчаса отслеживание странной ошибки. Вот почему мне нравится «предварительная» версия. Тем не менее, мои личные предпочтения не имеют значения (и их тоже нет). Мне просто интересно, если новый стандарт сломал то, что раньше работало. – Holger

ответ

0

Заменить

new Promise(resolve => resolve(instanceES6)).then(instanceES6.doSomething);

с

new Promise(resolve => resolve(instanceES6)).then(_ => _.doSomething());

Это короче и достигает того, что вы хотите с имеющимися инструментами.

Если это так, как вы отметили в комментариях, слишком хрупкие для ваших предпочтений, вы можете заменить. Затем с помощью специальной функции с помощью функции из прототипа проверяется, что экземпляр имеет ее (используя свойство function.name для обратного поиска + контрольная проверка идентификации), а затем вызывает его в экземпляре. В основном добавление проверки времени выполнения в цепочку обещаний.

Так как JavaScript не имеет ссылки на методе :: оператора как java8 мы будем иметь псевдоним прототипа, который:

class SomethingES6 { 
    ... 
} 

const SomethingClass = SomethingES6.prototype 

... 

new Promise(...).checkedThen(SomethingClass.doSomething); 

Где .checkedThen это пользовательская функция с проверкой типов. Так как расширение встроенных модулей является плохой практикой можно также подкласс Promise первого или составить его функционально путем импорта пользовательских затем в текущей области:

then(then(new Promise(...), SomethingClass.doSomething), SomethingClass.doSomethingElse)

+1

На мой взгляд, это плохое решение несуществующей проблемы. –

+0

Самое первое, что я сделал, это просто использовать лямбды. Все, что выше этого, больше похоже на ответ «если вы все еще настаиваете». – the8472