是否有可能在JS中有一个事件,当某个变量的值发生变化时触发?JQuery被接受。


当前回答

//ex:
/*
var x1 = {currentStatus:undefined};
your need is x1.currentStatus value is change trigger event ?
below the code is use try it.
*/
function statusChange(){
    console.log("x1.currentStatus_value_is_changed"+x1.eventCurrentStatus);
};

var x1 = {
    eventCurrentStatus:undefined,
    get currentStatus(){
        return this.eventCurrentStatus;
    },
    set currentStatus(val){
        this.eventCurrentStatus=val;
      //your function();
    }
};

or

/*  var x1 = {
eventCurrentStatus:undefined,
currentStatus : {
    get : function(){
        return Events.eventCurrentStatus
        },
    set : function(status){
        Events.eventCurrentStatus=status;

    },
}*/
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
x1.currentStatus="create"
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
x1.currentStatus="edit"
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
console.log("currentStatus = "+ x1.currentStatus);

or

/* global variable ku*/
    var jsVarEvents={};
    Object.defineProperty(window, "globalvar1", {//no i18n
        get: function() { return window.jsVarEvents.globalvarTemp},
        set: function(value) { window.window.jsVarEvents.globalvarTemp = value; }
    });
    console.log(globalvar1);
    globalvar1=1;
    console.log(globalvar1);

其他回答

这是一个老线程,但我在使用Angular寻找解决方案时偶然发现了第二高的答案(自定义侦听器)。虽然这个解决方案是可行的,但angular有一个更好的内置方法来解决这个问题,使用@Output和事件发射器。在自定义监听器回答中的例子:

ChildComponent.html

<button (click)="increment(1)">Increment</button>

ChildComponent.ts

import {EventEmitter, Output } from '@angular/core';

@Output() myEmitter: EventEmitter<number> = new EventEmitter<number>();

private myValue: number = 0;

public increment(n: number){
  this.myValue += n;

  // Send a change event to the emitter
  this.myEmitter.emit(this.myValue);
}

ParentComponent.html

<child-component (myEmitter)="monitorChanges($event)"></child-component>
<br/>
<label>{{n}}</label>

ParentComponent.ts

public n: number = 0;

public monitorChanges(n: number){
  this.n = n;
  console.log(n);
}

现在每次单击子按钮时都会更新非父按钮。工作stackblitz

一个相当简单和简单的解决方案是只使用函数调用来设置全局变量的值,而不要直接设置它的值。这样你就可以完全控制:

var globalVar;

function setGlobalVar(value) {
    globalVar = value;
    console.log("Value of globalVar set to: " + globalVar);
    //Whatever else
}

没有办法强制执行,它只需要编程纪律……尽管你可以使用grep(或类似的东西)来检查你的代码没有直接设置globalVar的值。

或者你可以把它封装在一个对象和用户getter和setter方法中…只是一个想法。

正如Luke Schafer的回答(注意:这是指他的原始帖子;但是这里的整个观点在编辑之后仍然有效),我还建议使用一对Get/Set方法来访问你的值。

然而,我想建议一些修改(这就是为什么我在这里发帖……)

这段代码的一个问题是对象myobj的字段A是可以直接访问的,所以可以在不触发侦听器的情况下访问/更改它的值:

var myobj = { a : 5, get_a : function() { return this.a;}, set_a : function(val) { this.a = val; }}
/* add listeners ... */
myobj.a = 10; // no listeners called!

封装

因此,为了保证监听器被实际调用,我们必须禁止直接访问字段a。如何做到这一点?使用闭包!

var myobj = (function() { // Anonymous function to create scope.

    var a = 5;            // 'a' is local to this function
                          // and cannot be directly accessed from outside
                          // this anonymous function's scope

    return {
        get_a : function() { return a; },   // These functions are closures:
        set_a : function(val) { a = val; }  // they keep reference to
                                            // something ('a') that was on scope
                                            // where they were defined
    };
})();

现在您可以使用Luke建议的相同方法来创建和添加侦听器,但是您可以放心,没有可能的方法来读取或写入一个未被注意到的对象!

以编程方式添加封装的字段

继续Luke的思路,我现在提出一种简单的方法,通过简单的函数调用将封装的字段和各自的getter /setter添加到对象中。

注意,这只适用于值类型。为了与引用类型一起工作,必须实现某种深度复制(例如,请参阅这个)。

function addProperty(obj, name, initial) {
    var field = initial;
    obj["get_" + name] = function() { return field; }
    obj["set_" + name] = function(val) { field = val; }
}

这与之前的工作相同:我们在函数上创建一个局部变量,然后创建一个闭包。

如何使用它?简单:

var myobj = {};
addProperty(myobj, "total", 0);
window.alert(myobj.get_total() == 0);
myobj.set_total(10);
window.alert(myobj.get_total() == 10);

最近我发现自己也有同样的问题。想要监听变量的变化并在变量变化时做一些事情。

有人提出了一个使用setter设置值的简单解决方案。

声明一个简单的对象来保存变量的值:

var variableObject = {
    value: false,
    set: function (value) {
        this.value = value;
        this.getOnChange();
    }
}

对象包含一个set方法,通过该方法可以更改值。但是它也调用了一个getOnChange()方法。将定义它。

variableObject.getOnChange = function() {
    if(this.value) {
        // do some stuff
    }
}

现在,每当我做variableObject.set(true)时,getOnChange方法就会触发,如果值被设置为所需的值(在我的例子中:true), if块也会执行。

这是我发现的最简单的方法。

我搜索了JavaScript双向数据绑定库,发现了这个库。

我没有成功地使它在DOM到变量的方向上工作,但在变量到DOM的方向上它是工作的,这就是我们在这里需要的。

我稍微重写了一下,因为原始代码(对我来说)很难阅读。它使用 object。defineproperty,这是Eliot b给出的第二多赞的答案,至少有部分错误。

<!DOCTYPE html>
<html>
  <head>
    <title>TODO supply a title</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script>
        const dataBind = (function () {
            const getElementValue = function (selector) {
                let element = document.querySelectorAll(selector)[0];
                return 'value' in element ? element.value : element.innerHTML;
            };
            const setElementValue = function (selector, newValue) {
                let elementArray = document.querySelectorAll(selector);
                for (let i = 0; i < elementArray.length; i++) {
                    let element = elementArray[i];
                    if ('value' in element) {
                        element.value = newValue;
                        if (element.tagName.toLowerCase() === 'select'){
                            let options = element.querySelectorAll('option');
                            for (let option in options){
                                if (option.value === newValue){
                                    option.selected = true;
                                    break;
                                }
                            }
                        }
                    } else {
                        element.innerHTML = newValue;
                    }
                }
            };

            const bindModelToView = function (selector, object, property, enumerable) {
                Object.defineProperty(object, property, {
                    get: function () {
                        return getElementValue(selector);
                    },
                    set: function (newValue) {
                        setElementValue(selector, newValue);
                    },
                    configurable: true,
                    enumerable: (enumerable)
                });
            };
            return {
                bindModelToView
            };
        })();
    </script>
</head>
<body>
    <div style="padding: 20%;">
        <input  type="text" id="text" style="width: 40px;"/>
    </div>
    <script>
        let x = {a: 1, b: 2};
        dataBind.bindModelToView('#text', x, 'a'); //data to dom

        setInterval(function () {
             x.a++;
        }, 1000);
   </script> 
</body>

</html>

JSFiddle.

JSFiddle原始代码。

在提供的示例中,对象x的属性由setInterval更新,文本输入的值也会自动更新。如果这还不够,并且事件是你想要的,你可以在上面的输入中添加onchange监听器。如果需要,输入也可以被隐藏。