1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
---
title: Object.prototype.watch()
slug: Web/JavaScript/Reference/Global_Objects/Object/watch
tags:
- Debugging
- Deprecated
- JavaScript
- Method
- Object
- Obsolete
- Prototype
translation_of: Archive/Web/JavaScript/Object.watch
---
<p>{{JSRef}}</p>
<div class="warning">
<p><strong>警告:</strong> 通常来讲,你应该尽量避免使用 <code>watch()</code>和 {{jsxref("Object.prototype.unwatch", "unwatch()")}} 这两个方法。因为只有 Gecko 实现了这两个方法,并且它们主要是为了在调试方便。另外,使用 watchpoint 对性能有严重的负面影响,在全局对象(如 window)上使用时尤其如此。你可以使用 <a href="/zh-cn/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters" title="https://developer.mozilla.org/zh-cn/Core_JavaScript_1.5_Guide/Working_with_Objects#Defining_getters_and_setters">setters and getters</a> 或者 proxy 代替。参见 {{ anch("Compatibility") }} 了解详情。</p>
</div>
<p><code><strong>watch() </strong></code>方法会监视属性是否被赋值并在赋值时运行相关函数。</p>
<h2 id="Summary" name="Summary">语法</h2>
<pre class="syntaxbox"><em>obj</em>.watch(<em>prop</em>, <em>handler</em>)</pre>
<h3 id="Parameters" name="Parameters">参数</h3>
<dl>
<dt><code>prop</code></dt>
<dd>想要监视值是否发生变化的指定对象的某个属性的属性名称</dd>
</dl>
<dl>
<dt><code>handler</code></dt>
<dd>当指定的属性发生变化时执行的回调函数</dd>
</dl>
<h3 id="返回值">返回值</h3>
<p>{{jsxref("undefined")}}.</p>
<h2 id="Description" name="Description">描述</h2>
<p>监视对指定对象的名为 <code>prop</code> 属性的赋值操作,只要 <code>prop</code> 属性被赋值,便调用 <code>handler(prop, oldval, newval)</code> 回调函数,并将函数返回值保存到该属性。 通过返回修改的新值(或者返回旧值),一个监视点可以过滤(或使之为 null )赋值。</p>
<p>如果你删除某个设置监视点的属性,该监视点并不会消失。如果你之后重新创建这个属性,监视点仍然有效。</p>
<p>要移除某个监视点,使用 <code><a href="/zh-cn/JavaScript/Reference/Global_Objects/Object/unwatch" title="zh-cn/JavaScript/Reference/Global_Objects/Object/unwatch">unwatch()</a></code> 方法。默认所有 <code>Object</code> 的后代都将继承 <code>watch</code> 方法。</p>
<p>JavaScript 调试器有与之相似的机制以及其它调试选项。需要更多有关调试器的信息,请查阅 <a href="/zh-cn/Venkman" title="zh-cn/Venkman">Venkman</a>。</p>
<p>对于 Firefox,<code>handler</code> 只会被脚本内的赋值操作激活,并不包括本地代码。举个例子,如果用户点击一个指向当前文档内的某个锚点, <code>window.watch('location', myHandler)</code> 不会回调 <code>myHandler</code> ,但 <code>window.location += '#myAnchor'</code> 将触发回调 <code>myHandler</code>。</p>
<div class="note"><strong>注意:</strong> 对一个对象的指定属性调用 <code>watch()</code> 将覆盖先前关联的 handler。</div>
<h2 id="Examples" name="Examples">例子</h2>
<h3 id="Example_Using_watch_and_unwatch" name="Example:_Using_watch_and_unwatch">使用 <code>watch</code> 和 <code>unwatch</code></h3>
<pre class="brush: js">var o = {p:1};
o.watch("p",
function (id, oldval, newval) {
console.log("o." + id + "由" + oldval + " 变为 " + newval);
return newval;
});
o.p = 2;
o.p = 3;
delete o.p;
o.p = 4;
o.unwatch('p');
o.p = 5;
</pre>
<p>上面的代码显示结果如下:</p>
<pre class="eval">o.p 由 1 变为 2
o.p 由 2 变为 3
o.p 由 undefined 变为 4
</pre>
<h3 id="Example_Using_watch_to_validate_an_object.27s_properties" name="Example:_Using_watch_to_validate_an_object.27s_properties">使用 <code>watch</code> 来验证一个对象的属性</h3>
<p>你可以使用 <code>watch</code> 来检测一个对象的属性赋值是否是合法的.下例演示了如何确保每个人始终具有一个合法的名字和0 到 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" && (!newval || newval.length > 30)) {
throw new RangeError("不合法的名字 " + this);
}
if (id === "age" && (newval < 0 || newval > 200)) {
throw new RangeError("不合法的年龄 " + this);
}
return newval;
}
will = new Person("Will", 29);
print(will); // Will, 29
try {
will.name = "";
} catch (e) {
//print(e);
console.log(e);
}
try {
will.age = -4;
} catch (e) {
console.log(e);
}
</pre>
<p>上面的代码显示结果如下:</p>
<pre class="eval">Will, 29
RangeError: 不合法的名字 Will, 29
RangeError: 不合法的年龄 Will, 29
</pre>
<h2 id="Specifications">Specifications</h2>
<p>不是任何规范的一部分。从 JavaScript 1.2 开始实现。</p>
<h2 id="Browser_compatibility">Browser compatibility</h2>
<div>{{CompatibilityTable}}</div>
<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>
<h2 id="兼容性提示">兼容性提示</h2>
<ul>
<li>此 <a href="https://gist.github.com/384583">Polyfill</a> 为所有 ES5 兼容浏览器提供 <code>watch</code> 支持。</li>
<li>使用 {{jsxref("Proxy")}} 允许你更加深度地调整属性服务机制</li>
<li>从 Firefox 23 开始,在 {{domxref("Document")}} 对象上调用 <code>watch()</code> 将抛出 {{jsxref("TypeError")}} 错误。这个回归问题已经在 Firefox 27 修复。</li>
</ul>
<h2 id="See_Also" name="See_Also">相关链接</h2>
<ul>
<li>{{jsxref("Object.unwatch()")}}</li>
<li>{{jsxref("Object.observe()")}} {{obsolete_inline}}</li>
</ul>
|