Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / third_party / google_input_tools / third_party / closure_library / closure / goog / object / object.js
1 // Copyright 2006 The Closure Library Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS-IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 /**
16  * @fileoverview Utilities for manipulating objects/maps/hashes.
17  */
18
19 goog.provide('goog.object');
20
21
22 /**
23  * Calls a function for each element in an object/map/hash.
24  *
25  * @param {Object.<K,V>} obj The object over which to iterate.
26  * @param {function(this:T,V,?,Object.<K,V>):?} f The function to call
27  *     for every element. This function takes 3 arguments (the element, the
28  *     index and the object) and the return value is ignored.
29  * @param {T=} opt_obj This is used as the 'this' object within f.
30  * @template T,K,V
31  */
32 goog.object.forEach = function(obj, f, opt_obj) {
33   for (var key in obj) {
34     f.call(opt_obj, obj[key], key, obj);
35   }
36 };
37
38
39 /**
40  * Calls a function for each element in an object/map/hash. If that call returns
41  * true, adds the element to a new object.
42  *
43  * @param {Object.<K,V>} obj The object over which to iterate.
44  * @param {function(this:T,V,?,Object.<K,V>):boolean} f The function to call
45  *     for every element. This
46  *     function takes 3 arguments (the element, the index and the object)
47  *     and should return a boolean. If the return value is true the
48  *     element is added to the result object. If it is false the
49  *     element is not included.
50  * @param {T=} opt_obj This is used as the 'this' object within f.
51  * @return {!Object.<K,V>} a new object in which only elements that passed the
52  *     test are present.
53  * @template T,K,V
54  */
55 goog.object.filter = function(obj, f, opt_obj) {
56   var res = {};
57   for (var key in obj) {
58     if (f.call(opt_obj, obj[key], key, obj)) {
59       res[key] = obj[key];
60     }
61   }
62   return res;
63 };
64
65
66 /**
67  * For every element in an object/map/hash calls a function and inserts the
68  * result into a new object.
69  *
70  * @param {Object.<K,V>} obj The object over which to iterate.
71  * @param {function(this:T,V,?,Object.<K,V>):R} f The function to call
72  *     for every element. This function
73  *     takes 3 arguments (the element, the index and the object)
74  *     and should return something. The result will be inserted
75  *     into a new object.
76  * @param {T=} opt_obj This is used as the 'this' object within f.
77  * @return {!Object.<K,R>} a new object with the results from f.
78  * @template T,K,V,R
79  */
80 goog.object.map = function(obj, f, opt_obj) {
81   var res = {};
82   for (var key in obj) {
83     res[key] = f.call(opt_obj, obj[key], key, obj);
84   }
85   return res;
86 };
87
88
89 /**
90  * Calls a function for each element in an object/map/hash. If any
91  * call returns true, returns true (without checking the rest). If
92  * all calls return false, returns false.
93  *
94  * @param {Object.<K,V>} obj The object to check.
95  * @param {function(this:T,V,?,Object.<K,V>):boolean} f The function to
96  *     call for every element. This function
97  *     takes 3 arguments (the element, the index and the object) and should
98  *     return a boolean.
99  * @param {T=} opt_obj This is used as the 'this' object within f.
100  * @return {boolean} true if any element passes the test.
101  * @template T,K,V
102  */
103 goog.object.some = function(obj, f, opt_obj) {
104   for (var key in obj) {
105     if (f.call(opt_obj, obj[key], key, obj)) {
106       return true;
107     }
108   }
109   return false;
110 };
111
112
113 /**
114  * Calls a function for each element in an object/map/hash. If
115  * all calls return true, returns true. If any call returns false, returns
116  * false at this point and does not continue to check the remaining elements.
117  *
118  * @param {Object.<K,V>} obj The object to check.
119  * @param {?function(this:T,V,?,Object.<K,V>):boolean} f The function to
120  *     call for every element. This function
121  *     takes 3 arguments (the element, the index and the object) and should
122  *     return a boolean.
123  * @param {T=} opt_obj This is used as the 'this' object within f.
124  * @return {boolean} false if any element fails the test.
125  * @template T,K,V
126  */
127 goog.object.every = function(obj, f, opt_obj) {
128   for (var key in obj) {
129     if (!f.call(opt_obj, obj[key], key, obj)) {
130       return false;
131     }
132   }
133   return true;
134 };
135
136
137 /**
138  * Returns the number of key-value pairs in the object map.
139  *
140  * @param {Object} obj The object for which to get the number of key-value
141  *     pairs.
142  * @return {number} The number of key-value pairs in the object map.
143  */
144 goog.object.getCount = function(obj) {
145   // JS1.5 has __count__ but it has been deprecated so it raises a warning...
146   // in other words do not use. Also __count__ only includes the fields on the
147   // actual object and not in the prototype chain.
148   var rv = 0;
149   for (var key in obj) {
150     rv++;
151   }
152   return rv;
153 };
154
155
156 /**
157  * Returns one key from the object map, if any exists.
158  * For map literals the returned key will be the first one in most of the
159  * browsers (a know exception is Konqueror).
160  *
161  * @param {Object} obj The object to pick a key from.
162  * @return {string|undefined} The key or undefined if the object is empty.
163  */
164 goog.object.getAnyKey = function(obj) {
165   for (var key in obj) {
166     return key;
167   }
168 };
169
170
171 /**
172  * Returns one value from the object map, if any exists.
173  * For map literals the returned value will be the first one in most of the
174  * browsers (a know exception is Konqueror).
175  *
176  * @param {Object.<K,V>} obj The object to pick a value from.
177  * @return {V|undefined} The value or undefined if the object is empty.
178  * @template K,V
179  */
180 goog.object.getAnyValue = function(obj) {
181   for (var key in obj) {
182     return obj[key];
183   }
184 };
185
186
187 /**
188  * Whether the object/hash/map contains the given object as a value.
189  * An alias for goog.object.containsValue(obj, val).
190  *
191  * @param {Object.<K,V>} obj The object in which to look for val.
192  * @param {V} val The object for which to check.
193  * @return {boolean} true if val is present.
194  * @template K,V
195  */
196 goog.object.contains = function(obj, val) {
197   return goog.object.containsValue(obj, val);
198 };
199
200
201 /**
202  * Returns the values of the object/map/hash.
203  *
204  * @param {Object.<K,V>} obj The object from which to get the values.
205  * @return {!Array.<V>} The values in the object/map/hash.
206  * @template K,V
207  */
208 goog.object.getValues = function(obj) {
209   var res = [];
210   var i = 0;
211   for (var key in obj) {
212     res[i++] = obj[key];
213   }
214   return res;
215 };
216
217
218 /**
219  * Returns the keys of the object/map/hash.
220  *
221  * @param {Object} obj The object from which to get the keys.
222  * @return {!Array.<string>} Array of property keys.
223  */
224 goog.object.getKeys = function(obj) {
225   var res = [];
226   var i = 0;
227   for (var key in obj) {
228     res[i++] = key;
229   }
230   return res;
231 };
232
233
234 /**
235  * Get a value from an object multiple levels deep.  This is useful for
236  * pulling values from deeply nested objects, such as JSON responses.
237  * Example usage: getValueByKeys(jsonObj, 'foo', 'entries', 3)
238  *
239  * @param {!Object} obj An object to get the value from.  Can be array-like.
240  * @param {...(string|number|!Array.<number|string>)} var_args A number of keys
241  *     (as strings, or numbers, for array-like objects).  Can also be
242  *     specified as a single array of keys.
243  * @return {*} The resulting value.  If, at any point, the value for a key
244  *     is undefined, returns undefined.
245  */
246 goog.object.getValueByKeys = function(obj, var_args) {
247   var isArrayLike = goog.isArrayLike(var_args);
248   var keys = isArrayLike ? var_args : arguments;
249
250   // Start with the 2nd parameter for the variable parameters syntax.
251   for (var i = isArrayLike ? 0 : 1; i < keys.length; i++) {
252     obj = obj[keys[i]];
253     if (!goog.isDef(obj)) {
254       break;
255     }
256   }
257
258   return obj;
259 };
260
261
262 /**
263  * Whether the object/map/hash contains the given key.
264  *
265  * @param {Object} obj The object in which to look for key.
266  * @param {*} key The key for which to check.
267  * @return {boolean} true If the map contains the key.
268  */
269 goog.object.containsKey = function(obj, key) {
270   return key in obj;
271 };
272
273
274 /**
275  * Whether the object/map/hash contains the given value. This is O(n).
276  *
277  * @param {Object.<K,V>} obj The object in which to look for val.
278  * @param {V} val The value for which to check.
279  * @return {boolean} true If the map contains the value.
280  * @template K,V
281  */
282 goog.object.containsValue = function(obj, val) {
283   for (var key in obj) {
284     if (obj[key] == val) {
285       return true;
286     }
287   }
288   return false;
289 };
290
291
292 /**
293  * Searches an object for an element that satisfies the given condition and
294  * returns its key.
295  * @param {Object.<K,V>} obj The object to search in.
296  * @param {function(this:T,V,string,Object.<K,V>):boolean} f The
297  *      function to call for every element. Takes 3 arguments (the value,
298  *     the key and the object) and should return a boolean.
299  * @param {T=} opt_this An optional "this" context for the function.
300  * @return {string|undefined} The key of an element for which the function
301  *     returns true or undefined if no such element is found.
302  * @template T,K,V
303  */
304 goog.object.findKey = function(obj, f, opt_this) {
305   for (var key in obj) {
306     if (f.call(opt_this, obj[key], key, obj)) {
307       return key;
308     }
309   }
310   return undefined;
311 };
312
313
314 /**
315  * Searches an object for an element that satisfies the given condition and
316  * returns its value.
317  * @param {Object.<K,V>} obj The object to search in.
318  * @param {function(this:T,V,string,Object.<K,V>):boolean} f The function
319  *     to call for every element. Takes 3 arguments (the value, the key
320  *     and the object) and should return a boolean.
321  * @param {T=} opt_this An optional "this" context for the function.
322  * @return {V} The value of an element for which the function returns true or
323  *     undefined if no such element is found.
324  * @template T,K,V
325  */
326 goog.object.findValue = function(obj, f, opt_this) {
327   var key = goog.object.findKey(obj, f, opt_this);
328   return key && obj[key];
329 };
330
331
332 /**
333  * Whether the object/map/hash is empty.
334  *
335  * @param {Object} obj The object to test.
336  * @return {boolean} true if obj is empty.
337  */
338 goog.object.isEmpty = function(obj) {
339   for (var key in obj) {
340     return false;
341   }
342   return true;
343 };
344
345
346 /**
347  * Removes all key value pairs from the object/map/hash.
348  *
349  * @param {Object} obj The object to clear.
350  */
351 goog.object.clear = function(obj) {
352   for (var i in obj) {
353     delete obj[i];
354   }
355 };
356
357
358 /**
359  * Removes a key-value pair based on the key.
360  *
361  * @param {Object} obj The object from which to remove the key.
362  * @param {*} key The key to remove.
363  * @return {boolean} Whether an element was removed.
364  */
365 goog.object.remove = function(obj, key) {
366   var rv;
367   if ((rv = key in obj)) {
368     delete obj[key];
369   }
370   return rv;
371 };
372
373
374 /**
375  * Adds a key-value pair to the object. Throws an exception if the key is
376  * already in use. Use set if you want to change an existing pair.
377  *
378  * @param {Object.<K,V>} obj The object to which to add the key-value pair.
379  * @param {string} key The key to add.
380  * @param {V} val The value to add.
381  * @template K,V
382  */
383 goog.object.add = function(obj, key, val) {
384   if (key in obj) {
385     throw Error('The object already contains the key "' + key + '"');
386   }
387   goog.object.set(obj, key, val);
388 };
389
390
391 /**
392  * Returns the value for the given key.
393  *
394  * @param {Object.<K,V>} obj The object from which to get the value.
395  * @param {string} key The key for which to get the value.
396  * @param {R=} opt_val The value to return if no item is found for the given
397  *     key (default is undefined).
398  * @return {V|R|undefined} The value for the given key.
399  * @template K,V,R
400  */
401 goog.object.get = function(obj, key, opt_val) {
402   if (key in obj) {
403     return obj[key];
404   }
405   return opt_val;
406 };
407
408
409 /**
410  * Adds a key-value pair to the object/map/hash.
411  *
412  * @param {Object.<K,V>} obj The object to which to add the key-value pair.
413  * @param {string} key The key to add.
414  * @param {V} value The value to add.
415  * @template K,V
416  */
417 goog.object.set = function(obj, key, value) {
418   obj[key] = value;
419 };
420
421
422 /**
423  * Adds a key-value pair to the object/map/hash if it doesn't exist yet.
424  *
425  * @param {Object.<K,V>} obj The object to which to add the key-value pair.
426  * @param {string} key The key to add.
427  * @param {V} value The value to add if the key wasn't present.
428  * @return {V} The value of the entry at the end of the function.
429  * @template K,V
430  */
431 goog.object.setIfUndefined = function(obj, key, value) {
432   return key in obj ? obj[key] : (obj[key] = value);
433 };
434
435
436 /**
437  * Does a flat clone of the object.
438  *
439  * @param {Object.<K,V>} obj Object to clone.
440  * @return {!Object.<K,V>} Clone of the input object.
441  * @template K,V
442  */
443 goog.object.clone = function(obj) {
444   // We cannot use the prototype trick because a lot of methods depend on where
445   // the actual key is set.
446
447   var res = {};
448   for (var key in obj) {
449     res[key] = obj[key];
450   }
451   return res;
452   // We could also use goog.mixin but I wanted this to be independent from that.
453 };
454
455
456 /**
457  * Clones a value. The input may be an Object, Array, or basic type. Objects and
458  * arrays will be cloned recursively.
459  *
460  * WARNINGS:
461  * <code>goog.object.unsafeClone</code> does not detect reference loops. Objects
462  * that refer to themselves will cause infinite recursion.
463  *
464  * <code>goog.object.unsafeClone</code> is unaware of unique identifiers, and
465  * copies UIDs created by <code>getUid</code> into cloned results.
466  *
467  * @param {*} obj The value to clone.
468  * @return {*} A clone of the input value.
469  */
470 goog.object.unsafeClone = function(obj) {
471   var type = goog.typeOf(obj);
472   if (type == 'object' || type == 'array') {
473     if (obj.clone) {
474       return obj.clone();
475     }
476     var clone = type == 'array' ? [] : {};
477     for (var key in obj) {
478       clone[key] = goog.object.unsafeClone(obj[key]);
479     }
480     return clone;
481   }
482
483   return obj;
484 };
485
486
487 /**
488  * Returns a new object in which all the keys and values are interchanged
489  * (keys become values and values become keys). If multiple keys map to the
490  * same value, the chosen transposed value is implementation-dependent.
491  *
492  * @param {Object} obj The object to transpose.
493  * @return {!Object} The transposed object.
494  */
495 goog.object.transpose = function(obj) {
496   var transposed = {};
497   for (var key in obj) {
498     transposed[obj[key]] = key;
499   }
500   return transposed;
501 };
502
503
504 /**
505  * The names of the fields that are defined on Object.prototype.
506  * @type {Array.<string>}
507  * @private
508  */
509 goog.object.PROTOTYPE_FIELDS_ = [
510   'constructor',
511   'hasOwnProperty',
512   'isPrototypeOf',
513   'propertyIsEnumerable',
514   'toLocaleString',
515   'toString',
516   'valueOf'
517 ];
518
519
520 /**
521  * Extends an object with another object.
522  * This operates 'in-place'; it does not create a new Object.
523  *
524  * Example:
525  * var o = {};
526  * goog.object.extend(o, {a: 0, b: 1});
527  * o; // {a: 0, b: 1}
528  * goog.object.extend(o, {b: 2, c: 3});
529  * o; // {a: 0, b: 2, c: 3}
530  *
531  * @param {Object} target The object to modify. Existing properties will be
532  *     overwritten if they are also present in one of the objects in
533  *     {@code var_args}.
534  * @param {...Object} var_args The objects from which values will be copied.
535  */
536 goog.object.extend = function(target, var_args) {
537   var key, source;
538   for (var i = 1; i < arguments.length; i++) {
539     source = arguments[i];
540     for (key in source) {
541       target[key] = source[key];
542     }
543
544     // For IE the for-in-loop does not contain any properties that are not
545     // enumerable on the prototype object (for example isPrototypeOf from
546     // Object.prototype) and it will also not include 'replace' on objects that
547     // extend String and change 'replace' (not that it is common for anyone to
548     // extend anything except Object).
549
550     for (var j = 0; j < goog.object.PROTOTYPE_FIELDS_.length; j++) {
551       key = goog.object.PROTOTYPE_FIELDS_[j];
552       if (Object.prototype.hasOwnProperty.call(source, key)) {
553         target[key] = source[key];
554       }
555     }
556   }
557 };
558
559
560 /**
561  * Creates a new object built from the key-value pairs provided as arguments.
562  * @param {...*} var_args If only one argument is provided and it is an array
563  *     then this is used as the arguments,  otherwise even arguments are used as
564  *     the property names and odd arguments are used as the property values.
565  * @return {!Object} The new object.
566  * @throws {Error} If there are uneven number of arguments or there is only one
567  *     non array argument.
568  */
569 goog.object.create = function(var_args) {
570   var argLength = arguments.length;
571   if (argLength == 1 && goog.isArray(arguments[0])) {
572     return goog.object.create.apply(null, arguments[0]);
573   }
574
575   if (argLength % 2) {
576     throw Error('Uneven number of arguments');
577   }
578
579   var rv = {};
580   for (var i = 0; i < argLength; i += 2) {
581     rv[arguments[i]] = arguments[i + 1];
582   }
583   return rv;
584 };
585
586
587 /**
588  * Creates a new object where the property names come from the arguments but
589  * the value is always set to true
590  * @param {...*} var_args If only one argument is provided and it is an array
591  *     then this is used as the arguments,  otherwise the arguments are used
592  *     as the property names.
593  * @return {!Object} The new object.
594  */
595 goog.object.createSet = function(var_args) {
596   var argLength = arguments.length;
597   if (argLength == 1 && goog.isArray(arguments[0])) {
598     return goog.object.createSet.apply(null, arguments[0]);
599   }
600
601   var rv = {};
602   for (var i = 0; i < argLength; i++) {
603     rv[arguments[i]] = true;
604   }
605   return rv;
606 };
607
608
609 /**
610  * Creates an immutable view of the underlying object, if the browser
611  * supports immutable objects.
612  *
613  * In default mode, writes to this view will fail silently. In strict mode,
614  * they will throw an error.
615  *
616  * @param {!Object.<K,V>} obj An object.
617  * @return {!Object.<K,V>} An immutable view of that object, or the
618  *     original object if this browser does not support immutables.
619  * @template K,V
620  */
621 goog.object.createImmutableView = function(obj) {
622   var result = obj;
623   if (Object.isFrozen && !Object.isFrozen(obj)) {
624     result = Object.create(obj);
625     Object.freeze(result);
626   }
627   return result;
628 };
629
630
631 /**
632  * @param {!Object} obj An object.
633  * @return {boolean} Whether this is an immutable view of the object.
634  */
635 goog.object.isImmutableView = function(obj) {
636   return !!Object.isFrozen && Object.isFrozen(obj);
637 };