É possível ter um evento em JS que é acionado quando o valor de uma determinada variável é alterado? JQuery é aceito.
javascript
jquery
dom-events
rashcroft22
fonte
fonte
variable
, mas todas as respostas aqui se referemproperty
. Eu me pergunto se podemos ouvirlocal variable
mudanças.Respostas:
Sim, isso agora é completamente possível!
Sei que esse é um thread antigo, mas agora esse efeito é possível usando acessadores (getters e setters): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters
Você pode definir um objeto como este, no qual
aInternal
representa o campoa
:Em seguida, você pode registrar um ouvinte usando o seguinte:
Portanto, sempre que algo mudar o valor de
x.a
, a função de ouvinte será acionada. A execução da seguinte linha exibirá o pop-up de alerta:Veja um exemplo aqui: https://jsfiddle.net/5o1wf1bn/1/
Você também pode usar uma matriz de ouvintes em vez de um único slot de ouvinte, mas eu queria dar o exemplo mais simples possível.
fonte
this.aListener(val)
, você terá que percorrer todas as funções do ouvinte e chamar cada uma delas de passagemval
. Normalmente, o método é chamado emaddListener
vez deregisterListener
.A maioria das respostas a esta pergunta está desatualizada, ineficaz ou requer a inclusão de grandes bibliotecas inchadas:
Hoje, agora você pode usar o objeto Proxy para monitorar (e interceptar) as alterações feitas em um objeto. Foi desenvolvido especificamente para o que o OP está tentando fazer. Aqui está um exemplo básico:
Os únicos inconvenientes do
Proxy
objeto são:Proxy
objeto não está disponível em navegadores mais antigos (como o IE11) e o polyfill não pode replicar totalmente aProxy
funcionalidade.Date
) - oProxy
objeto é melhor emparelhado com objetos ou matrizes simples.Se você precisar observar as alterações feitas em um objeto aninhado , precisará usar uma biblioteca especializada, como o Observable Slim (que publiquei), que funciona assim:
fonte
target.hello_world = "test"
)you don't actually watch changes on the target object but only on proxy object
- isso não é bem preciso. OProxy
objeto não é modificado - ele não possui sua própria cópia do destino.you just want to know when a property change on the target object
- você pode fazer isso com aProxy
, esse é um dos principais casos de uso de proxies.target
, precisará fazê-lo através de um proxy. No entanto,proxy.hello_world = "test"
isso não significa que você está modificando o proxy, o proxy permanece inalterado,target
é modificado (se o manipulador de conjunto estiver configurado para isso). Parece que o seu ponto é que você não pode observar diretamentetarget.hello_world = "test"
. Isso é verdade. Designações de variáveis simples não emitem nenhum tipo de evento. É por isso que temos que usar ferramentas como as descritas nas respostas a esta pergunta.It sounds like your point is that you cannot directly observe target.hello_world = "test". That is true.
Esse é exatamente o meu ponto. No meu caso, eu tenho um objeto criado em outro lugar e fui atualizado por outro código ... um proxy, nesse caso, não é útil, pois as alterações serão feitas no destino.Não.
Mas, se é realmente tão importante, você tem 2 opções (a primeira é testada, a segunda não):
Primeiro, use setters e getters, assim:
então você pode fazer algo como:
defina o ouvinte como:
Em segundo lugar, eu realmente esqueci, vou enviar enquanto penso sobre isso :)
EDIT: Ah, eu me lembro :) Você pode colocar um relógio no valor:
Dado myobj acima, com 'a':
fonte
Usando
Prototype
: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/definePropertyOutro exemplo
fonte
varw
requer 2 argumentos, mas parte do seu exemplo mostra a função sendo chamada apenas com o parâmetro value.Desculpe trazer um tópico antigo, mas aqui está um pequeno manual para quem (como eu!) Não vê como o exemplo de Eli Grey funciona:
Espero que isso possa ajudar alguém
fonte
Como resposta de Luke Schafer ( nota : isso se refere ao seu post original; mas todo o ponto aqui permanece válido após a edição ), eu também sugeriria um par de métodos Get / Set para acessar seu valor.
No entanto, eu sugeriria algumas modificações (e é por isso que estou postando ...).
Um problema com esse código é que o campo
a
do objetomyobj
é diretamente acessível, portanto, é possível acessá-lo / alterar seu valor sem acionar os ouvintes:Encapsulamento
Portanto, para garantir que os ouvintes sejam realmente chamados, teríamos de proibir esse acesso direto ao campo
a
. Como fazer isso? Use um fechamento !Agora você pode usar o mesmo método para criar e adicionar os ouvintes que Luke propôs, mas tenha certeza de que não há como ler ou escrever para
a
passar despercebido!Adicionando campos encapsulados programaticamente
Ainda na trilha de Luke, proponho agora uma maneira simples de adicionar campos encapsulados e os respectivos getters / setters aos objetos por meio de uma simples chamada de função.
Observe que isso só funcionará corretamente com tipos de valor . Para que isso funcione com tipos de referência , algum tipo de cópia profunda teria que ser implementado (veja este , por exemplo).
Isso funciona da mesma maneira que antes: criamos uma variável local em uma função e, em seguida, criamos um fechamento.
Como usá-lo? Simples:
fonte
Se você estiver usando jQuery {UI} (que todo mundo deveria usar :-)), poderá usar .change () com um elemento <input /> oculto.
fonte
<input/>
elemento oculto ?<input type="hidden" value="" id="thisOne" />
e com jQuery$("#thisOne").change(function() { do stuff here });
e, em$("#thisOne").val(myVariableWhichIsNew);
seguida, o.change()
irá disparar.var1 = 'new value';
, você definirá o valor dessa entrada oculta e adicionará um ouvinte para alterar a variável.$("#val1").on('change', function(){ val1 = this.val(); ... do the stuff that you wanted to do when val1 changed... }); $("#val1").val('new value');
AngularJS
(Eu sei que isso não éJQuery
, mas isso pode ajudar. [JS puro é bom apenas em teoria]):onde "dados" é o nome da sua variável no escopo.
Há um link para doc.
fonte
$scope.$apply()
é executadoPara aqueles que sintonizam alguns anos depois:
Está disponível uma solução para a maioria dos navegadores (e IE6 +) que usa o evento onpropertychange e a especificação mais recente defineProperty. O problema é que você precisará tornar sua variável um objeto dom.
Detalhes completos:
http://johndyer.name/native-browser-get-set-properties-in-javascript/
fonte
A funcionalidade que você procura pode ser alcançada através do uso do método "defineProperty ()" - disponível apenas para navegadores modernos:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Eu escrevi uma extensão jQuery que possui algumas funcionalidades semelhantes se você precisar de mais suporte entre navegadores:
https://github.com/jarederaj/jQueue
fonte
Não diretamente: você precisa de um getter / setter de pares com uma interface "addListener / removeListener" de algum tipo ... ou um plug-in NPAPI (mas isso é outra história).
fonte
ou
ou
fonte
Uma solução bastante simples e simplista é usar apenas uma chamada de função para definir o valor da variável global e nunca definir seu valor diretamente. Dessa forma, você tem controle total:
Não há como impor isso, apenas requer disciplina de programação ... embora você possa usar
grep
(ou algo semelhante) para verificar se em nenhum lugar o seu código define diretamente o valor deglobalVar
.Ou você pode encapsulá-lo em um objeto e métodos getter e setter do usuário ... apenas um pensamento.
fonte
var
nos módulos ES6 - essa é a única solução.Por favor, lembre-se de que a pergunta inicial era para VARIÁVEIS, não para OBJETOS;)
além de todas as respostas acima, criei uma pequena biblioteca chamada forWatch.js , que usa da mesma maneira para capturar e chamadas para alterações nas variáveis globais normais em javascript.
Compatível com variáveis JQUERY, não é necessário usar OBJETOS, e você pode transmitir diretamente um ARRAY de várias variáveis, se necessário.
Se puder ser útil ...: https://bitbucket.org/esabora/forthewatch
Basicamente, basta chamar a função:
watchIt("theVariableToWatch", "varChangedFunctionCallback");
E desculpe antecipadamente, se não for relevante.
fonte
A maneira mais fácil que encontrei, partindo desta resposta :
E depois:
fonte
No meu caso, eu estava tentando descobrir se alguma biblioteca que eu estava incluindo no meu projeto estava redefinindo o meu
window.player
. Então, no início do meu código, eu apenas fiz:fonte
Não é diretamente possível.
No entanto, isso pode ser feito usando o CustomEvent: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
O método abaixo aceita uma matriz de nomes de variáveis como uma entrada e adiciona um ouvinte de evento para cada variável e aciona o evento para qualquer alteração no valor das variáveis.
O método usa pesquisa para detectar a alteração no valor. Você pode aumentar o valor do tempo limite em milissegundos.
Chamando o método:
Ele detectará as alterações nas variáveis username e userid.
fonte
Com a ajuda de getter e setter , você pode definir uma classe JavaScript que faz isso.
Primeiro, definimos nossa classe chamada
MonitoredVariable
:Suponha que desejamos ouvir as
money
alterações, vamos criar uma instância doMonitoredVariable
com dinheiro inicial0
:Então poderíamos obter ou definir seu valor usando
money.val
:Como não definimos nenhum ouvinte para isso, nada de especial acontece após as
money.val
alterações em 2.Agora vamos definir alguns ouvintes. Temos quatro ouvintes disponíveis:
beforeSet
,beforeChange
,afterChange
,afterSet
. O seguinte ocorrerá sequencialmente quando você usarmoney.val = newValue
para alterar o valor da variável:Agora, definimos o
afterChange
ouvinte que será acionado somente após amoney.val
alteração (whileafterSet
será acionado mesmo que o novo valor seja o mesmo que o antigo):Agora defina um novo valor
3
e veja o que acontece:Você verá o seguinte no console:
Para obter o código completo, consulte https://gist.github.com/yusanshi/65745acd23c8587236c50e54f25731ab .
fonte
Este é um tópico antigo, mas me deparei com a segunda resposta mais alta (ouvintes personalizados) enquanto procurava uma solução usando o Angular. Enquanto a solução funciona, o angular tem uma maneira melhor construída de resolver esse problema usando
@Output
emissores e eventos. Saindo do exemplo na resposta do ouvinte personalizado:ChildComponent.html
ChildComponent.ts
ParentComponent.html
ParentComponent.ts
Agora, isso será atualizado
n
no pai cada vez que o botão filho for clicado. Stackblitz de trabalhofonte
fonte