Object.prototype.watch()

  • Revision slug: Web/JavaScript/Reference/Global_Objects/Object/watch
  • Revision title: Object.prototype.watch()
  • Revision id: 493755
  • Created:
  • Creator: fscholz
  • Is current revision? No
  • Comment

Revision Content

{{JSRef("Global_Objects", "Object")}}
Warning: Generally you should avoid using watch() and {{jsxref("Objec.unwatch", "unwatch()")}} when possible. These two methods are implemented only in Gecko, and they're intended primarily for debugging use. In addition, using watchpoints has a serious negative impact on performance, which is especially true when used on global objects, such as window. You can usually use setters and getters or proxies instead. See {{ anch("Browser compatibility") }} for details.

Summary

The watch() method watches for a property to be assigned a value and runs a function when that occurs.

Syntax

obj.watch(prop, handler)

Parameters

prop
The name of a property of the object on which you wish to monitor changes.
handler
A function to call when the specified property's value changes.

Description

Watches for assignment to a property named prop in this object, calling handler(prop, oldval, newval) whenever prop is set and storing the return value in that property. A watchpoint can filter (or nullify) the value assignment, by returning a modified newval (or by returning oldval).

If you delete a property for which a watchpoint has been set, that watchpoint does not disappear. If you later recreate the property, the watchpoint is still in effect.

To remove a watchpoint, use the {{jsxref("Object.unwatch", "unwatch()")}} method. By default, the watch method is inherited by every object descended from Object.

The JavaScript debugger has functionality similar to that provided by this method, as well as other debugging options. For information on the debugger, see Venkman.

In Firefox, handler is only called from assignments in script, not from native code. For example, window.watch('location', myHandler) will not call myHandler if the user clicks a link to an anchor within the current document. However, window.location += '#myAnchor' will call myHandler.

Note: Calling watch() on an object for a specific property overrides and previous handler attached for that property.

Examples

Example: Using watch and unwatch

var o = { p: 1 };

o.watch("p", function (id, oldval, newval) {
    console.log( "o." + id + " changed from " + oldval + " to " + newval );
    return newval;
});

o.p = 2;
o.p = 3;
delete o.p;
o.p = 4;

o.unwatch('p');
o.p = 5;

This script displays the following:

o.p changed from 1 to 2
o.p changed from 2 to 3
o.p changed from undefined to 4

Example: Using watch to validate an object's properties

You can use watch to test any assignment to an object's properties. This example ensures that every Person always has a valid name and an age between 0 and 200.

Person = function(name,age) {
  this.watch("age", Person.prototype._isValidAssignment);
  this.watch("name", Person.prototype._isValidAssignment);
  this.name = name;
  this.age = age;
}

Person.prototype.toString = function() {
  return this.name + ", " + this.age;
};

Person.prototype._isValidAssignment = function(id, oldval, newval) {
  if (id === "name" && (!newval || newval.length > 30)) {
    throw new RangeError("invalid name for " + this);
  }
  if (id === "age"  && (newval < 0 || newval > 200)) {
    throw new RangeError("invalid age for " + this);
  }
  return newval;
}

will = new Person("Will", 29);
print(will);   // Will, 29

try {
  will.name = "";
} catch (e) {
  print(e);
}

try {
  will.age = -4;
} catch (e) {
  print(e);
}

This script displays the following:

Will, 29
RangeError: invalid name for Will, 29
RangeError: invalid age for Will, 29

Specifications

Not part of any specifications. Implemented in JavaScript 1.2.

Browser compatibility

  • This Polyfill that offers watch to all ES5 compatible browser
  • Using a {{jsxref("Global_Objects/Proxy", "Proxy")}} enables you do that even deeper changes to how property assignments work

{{ CompatibilityTable() }}

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support {{ CompatNo() }} {{ CompatVersionUnknown() }} {{ CompatNo() }} {{ CompatNo() }} {{ CompatNo() }}
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support {{ CompatNo() }} {{ CompatNo() }} {{ CompatVersionUnknown() }} {{ CompatNo() }} {{ CompatNo() }} {{ CompatNo() }}
Note: Calling watch() on the {{ domxref("Document") }} object throws a {{jsxref("Global_Objects/TypeError", "TypeError")}} since Firefox 23 ({{ bug(903332) }}). This regression has been fixed with Firefox 27.

See also

  • {{jsxref("Object.unwatch()")}}

Revision Source

<div>
 {{JSRef("Global_Objects", "Object")}}</div>
<div class="warning">
 <strong>Warning:</strong> Generally you should avoid using <code>watch()</code> and {{jsxref("Objec.unwatch", "unwatch()")}} when possible. These two methods are implemented only in Gecko, and they're intended primarily for debugging use. In addition, using watchpoints has a serious negative impact on performance, which is especially true when used on global objects, such as window. You can usually use <a href="/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters">setters and getters</a> or proxies instead. See {{ anch("Browser compatibility") }} for details.</div>
<h2 id="Summary" name="Summary">Summary</h2>
<p>The <code><strong>watch()</strong></code> method watches for a property to be assigned a value and runs a function when that occurs.</p>
<h2 id="Syntax" name="Syntax">Syntax</h2>
<pre class="syntaxbox">
<code><em>obj</em>.watch(<em>prop</em>, <em>handler</em>)</code></pre>
<h3 id="Parameters" name="Parameters">Parameters</h3>
<dl>
 <dt>
  <code>prop</code></dt>
 <dd>
  The name of a property of the object on which you wish to monitor changes.</dd>
 <dt>
  <code>handler</code></dt>
 <dd>
  A function to call when the specified property's value changes.</dd>
</dl>
<h2 id="Description" name="Description">Description</h2>
<p>Watches for assignment to a property named <code>prop</code> in this object, calling <code>handler(prop, oldval, newval)</code> whenever <code>prop</code> is set and storing the return value in that property. A watchpoint can filter (or nullify) the value assignment, by returning a modified <code>newval</code> (or by returning <code>oldval</code>).</p>
<p>If you delete a property for which a watchpoint has been set, that watchpoint does not disappear. If you later recreate the property, the watchpoint is still in effect.</p>
<p>To remove a watchpoint, use the {{jsxref("Object.unwatch", "unwatch()")}} method. By default, the <code>watch</code> method is inherited by every object descended from <code>Object</code>.</p>
<p>The JavaScript debugger has functionality similar to that provided by this method, as well as other debugging options. For information on the debugger, see <a href="/en-US/docs/Venkman" title="Venkman">Venkman</a>.</p>
<p>In Firefox, <code>handler</code> is only called from assignments in script, not from native code. For example, <code>window.watch('location', myHandler)</code> will not call <code>myHandler</code> if the user clicks a link to an anchor within the current document. However, <code>window.location += '#myAnchor'</code> will call <code>myHandler</code>.</p>
<div class="note">
 <strong>Note:</strong> Calling <code>watch()</code> on an object for a specific property overrides and previous handler attached for that property.</div>
<h2 id="Examples" name="Examples">Examples</h2>
<h3 id="Example:_Using_watch_and_unwatch" name="Example:_Using_watch_and_unwatch">Example: Using <code>watch</code> and <code>unwatch</code></h3>
<pre class="brush: js">
var o = { p: 1 };

o.watch("p", function (id, oldval, newval) {
    console.log( "o." + id + " changed from " + oldval + " to " + newval );
    return newval;
});

o.p = 2;
o.p = 3;
delete o.p;
o.p = 4;

o.unwatch('p');
o.p = 5;</pre>
<p>This script displays the following:</p>
<pre>
o.p changed from 1 to 2
o.p changed from 2 to 3
o.p changed from undefined to 4</pre>
<h3 id="Example:_Using_watch_to_validate_an_object.27s_properties" name="Example:_Using_watch_to_validate_an_object.27s_properties">Example: Using <code>watch</code> to validate an object's properties</h3>
<p>You can use <code>watch</code> to test any assignment to an object's properties. This example ensures that every Person always has a valid name and an age between 0 and 200.</p>
<pre class="brush: js">
Person = function(name,age) {
  this.watch("age", Person.prototype._isValidAssignment);
  this.watch("name", Person.prototype._isValidAssignment);
  this.name = name;
  this.age = age;
}

Person.prototype.toString = function() {
  return this.name + ", " + this.age;
};

Person.prototype._isValidAssignment = function(id, oldval, newval) {
  if (id === "name" &amp;&amp; (!newval || newval.length &gt; 30)) {
    throw new RangeError("invalid name for " + this);
  }
  if (id === "age"  &amp;&amp; (newval &lt; 0 || newval &gt; 200)) {
    throw new RangeError("invalid age for " + this);
  }
  return newval;
}

will = new Person("Will", 29);
print(will);   // Will, 29

try {
  will.name = "";
} catch (e) {
  print(e);
}

try {
  will.age = -4;
} catch (e) {
  print(e);
}</pre>
<p>This script displays the following:</p>
<pre>
Will, 29
RangeError: invalid name for Will, 29
RangeError: invalid age for Will, 29
</pre>
<h2 id="See_also" name="See_also">Specifications</h2>
<p>Not part of any specifications. Implemented in JavaScript 1.2.</p>
<h2 id="Browser_compatibility">Browser compatibility</h2>
<ul>
 <li>This <span class="external"><a class="link-https" href="https://gist.github.com/384583" title="https://gist.github.com/384583">Polyfill</a> that offers watch to all ES5 compatible browser</span></li>
 <li>Using a {{jsxref("Global_Objects/Proxy", "Proxy")}} enables you do that even deeper changes to how property assignments work</li>
</ul>
<p>{{ CompatibilityTable() }}</p>
<div id="compat-desktop">
 <table class="compat-table">
  <tbody>
   <tr>
    <th>Feature</th>
    <th>Chrome</th>
    <th>Firefox (Gecko)</th>
    <th>Internet Explorer</th>
    <th>Opera</th>
    <th>Safari</th>
   </tr>
   <tr>
    <td>Basic support</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatVersionUnknown() }}</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatNo() }}</td>
   </tr>
  </tbody>
 </table>
</div>
<div id="compat-mobile">
 <table class="compat-table">
  <tbody>
   <tr>
    <th>Feature</th>
    <th>Android</th>
    <th>Chrome for Android</th>
    <th>Firefox Mobile (Gecko)</th>
    <th>IE Mobile</th>
    <th>Opera Mobile</th>
    <th>Safari Mobile</th>
   </tr>
   <tr>
    <td>Basic support</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatVersionUnknown() }}</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatNo() }}</td>
   </tr>
  </tbody>
 </table>
</div>
<div class="note">
 <strong>Note:</strong> Calling <code>watch()</code> on the {{ domxref("Document") }} object throws a {{jsxref("Global_Objects/TypeError", "TypeError")}} since Firefox&nbsp;23 ({{ bug(903332) }}). This regression has been fixed with Firefox&nbsp;27.</div>
<h2 id="See_also" name="See_also">See also</h2>
<ul>
 <li>{{jsxref("Object.unwatch()")}}</li>
</ul>
Revert to this revision