假如我們有一個圖書館的項目,項目中有一組圖書和作者,像下面這樣:
var bookAuthors = {
"Farmer Giles of Ham": "J.R.R. Tolkien",
"Out of the Silent Planet": "C.S. Lewis",
"The Place of the Lion": "Charles Williams",
"Poetic Diction": "Owen Barfield"
};
我們分析現在的需求,我們給一個API發送數據,但是書的長度不能超過100,因此我們需要在發送數據之前計算在一個對象中總共有多少本書。那麼我們總怎麼做呢?我們可能會這樣做:function countProperties (obj) {
var count = 0;
for (var property in obj) {
if (Object.prototype.hasOwnProperty.call(obj, property)) {
count++;
}
}
return count;
}
var bookCount = countProperties(bookAuthors);
// Outputs: 4
console.log(bookCount);
這是可以實現的,幸運的是Javascript提供了一個更改的方法來計算對象的長度:
var bookAuthors = {
"Farmer Giles of Ham": "J.R.R. Tolkien",
"Out of the Silent Planet": "C.S. Lewis",
"The Place of the Lion": "Charles Williams",
"Poetic Diction": "Owen Barfield"
};
var arr = Object.keys(bookAuthors);
//Outputs: Array [ "Farmer Giles of Ham", "Out of the Silent Planet", "The Place of the Lion", "Poetic Diction" ]
console.log(arr);
//Outputs: 4
console.log(arr.length);
下面我們來對數組使用keys方法:
var arr = ["zuojj", "benjamin", "www.zuojj.com"];
//Outputs: ["0", "1", "2"]
console.log(Object.keys(arr));
//Outputs: 3
console.log(arr.length);
Object.keys() 方法會返回一個由給定對象的所有可枚舉自身屬性的屬性名組成的數組,數組中屬性名的排列順序和使用for-in循環遍歷該對象時返回的順序一致(兩者的主要區別是 for-in 還會遍歷出一個對象從其原型鏈上繼承到的可枚舉屬性)。方法的兼容性及詳情請戳這裏。Object.keys()方法,只能使用在現代瀏覽器,IE8及以下是不支持的,如果想支持IE低版本,可以使用es5-shim來兼容。其中代碼如下:
// ES5 15.2.3.14
// http://es5.github.com/#x15.2.3.14
// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
dontEnums = [
"toString",
"toLocaleString",
"valueOf",
"hasOwnProperty",
"isPrototypeOf",
"propertyIsEnumerable",
"constructor"
],
dontEnumsLength = dontEnums.length;
defineProperties(Object, {
keys: function keys(object) {
var isFn = isFunction(object),
isArgs = isArguments(object),
isObject = object !== null && typeof object === 'object',
isStr = isObject && isString(object);
if (!isObject && !isFn && !isArgs) {
throw new TypeError("Object.keys called on a non-object");
}
var theKeys = [];
var skipProto = hasProtoEnumBug && isFn;
if (isStr || isArgs) {
for (var i = 0; i < object.length; ++i) {
theKeys.push(String(i));
}
} else {
for (var name in object) {
if (!(skipProto && name === 'prototype') && owns(object, name)) {
theKeys.push(String(name));
}
}
}
if (hasDontEnumBug) {
var ctor = object.constructor,
skipConstructor = ctor && ctor.prototype === object;
for (var j = 0; j < dontEnumsLength; j++) {
var dontEnum = dontEnums[j];
if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) {
theKeys.push(dontEnum);
}
}
}
return theKeys;
}
});
var keysWorksWithArguments = Object.keys && (function () {
// Safari 5.0 bug
return Object.keys(arguments).length === 2;
}(1, 2));
var originalKeys = Object.keys;
defineProperties(Object, {
keys: function keys(object) {
if (isArguments(object)) {
return originalKeys(ArrayPrototype.slice.call(object));
} else {
return originalKeys(object);
}
}
}, !keysWorksWithArguments);