JavaScript中的对象观点异常差别,要把它看成别的言语的关联数组(如PHP)或许Map(如Java)来明白的话,照样有很大的不一样——因为原型链和属性描述符(主如果[[Enumerable]]
)的存在。
一个对象字面量{}
有Object
作为原型,它有继续自原型链的不可罗列的toString
要领。下面将以对象字面量为例。
下标操作符、点操作符能够接见到本身属性或继续自原型链的任何属性,除非涌现了属性掩盖
var a ={}; a.toString
返回toString要领var a ={toString:"a"}; a.toString
返回字符串”a”for in
轮回将罗列的本身属性和继续自原型链的一切[[Enumerable]]
的属性"key" in obj
的推断中,推断本身属性或继续自原型链的属性的存在性"toString" in {}
返回trueobj.hasOwnProperty()
的推断中,只推断本身属性的存在性({}).hasOwnProperty("toString")
返回false({toString:"a"}).hasOwnProperty("toString")
返回trueObject.keys()
可返回本身[[Enumerable]]
的属性构成的数组,不包括原型链上继续的属性Object.keys({a:1})
返回["a"]
,不包括原型链上的toString等内容Object.getOwnPropertyNames()
能够返回本身任何属性构成的数组,不包括原型链上继续的属性
类目 | 语句 | 本身属性 | 原型链上继续的属性 | ||
可罗列属性 | 不可罗列属性 | 可罗列属性 | 不可罗列属性 | ||
接见 | obj.prop | √ | √ | √ | √ |
obj[“prop”] | √ | √ | √ | √ | |
轮回 | for key in obj | √ | √ | ||
推断 | key in obj | TRUE | TRUE | TRUE | TRUE |
obj.hasOwnProperty(key) | TRUE | TRUE | FALSE | FALSE | |
枚举 | Object.keys(obj) | √ | |||
Object.getOwnPropertyNames(obj) | √ | √ |
能够经由过程以下体式格局防止遍历过程当中的原型链滋扰:
在get/set要领中为每个键加上前缀
Object.create(null)
来建立一个没有原型的对象
这些都能够在StringMap的解决方案里找到:
(虽然很不喜好粘代码,然则google code都快关了)
// Copyright (C) 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Implements StringMap - a map api for strings.
*
* @author Mark S. Miller
* @author Jasvir Nagra
* @requires ses
* @overrides StringMap
*/
var StringMap;
(function() {
'use strict';
var create = Object.create;
var freeze = Object.freeze;
function constFunc(func) {
func.prototype = null;
return freeze(func);
}
function assertString(x) {
if ('string' !== typeof(x)) {
throw new TypeError('Not a string: ' + x);
}
return x;
}
var createNull;
if (typeof ses === 'undefined' ||
!ses.ok() ||
ses.es5ProblemReports.FREEZING_BREAKS_PROTOTYPES.beforeFailure) {
// Object.create(null) may be broken; fall back to ES3-style implementation
// (safe because we suffix keys anyway).
createNull = function() { return {}; };
} else {
createNull = function() { return Object.create(null); };
}
StringMap = function StringMap() {
var objAsMap = createNull();
return freeze({
get: constFunc(function(key) {
return objAsMap[assertString(key) + '$'];
}),
set: constFunc(function(key, value) {
objAsMap[assertString(key) + '$'] = value;
}),
has: constFunc(function(key) {
return (assertString(key) + '$') in objAsMap;
}),
'delete': constFunc(function(key) {
return delete objAsMap[assertString(key) + '$'];
})
});
};
})();