JavaScript 对象属性的存在性

先看一个例子

var person = {
  name:undefined
}
console.log(person.name); // undefined
console.log(person.age); // undefined

上面的例子中 person对象有一个name属性,没有age属性。但是,使用
person.name 和 person.age访问属性值时,两者的结果都是undefined。

因此我们没法通过值为undefined来判断一个对象是否有某个属性。

那么如何判断一个对象是否存在一个属性。

1. in 操作符

如果指定的属性存在对象或其原型链中,那么in操作符返回true 。

注意: in操作符判断属性的存在性,不论属性是否可枚举

举个例子:

let man = {
  speak: 'I can'
}

// 已man对象为原型创建person对象
let person = Object.create(man);
//定义person对象的name属性,该属性是person对象的自有属性
person.name='noshower';

//定义person对象的自有属性,但是'age'不可枚举,
Object.defineProperty(person, 'age', {
  enumerable: false,
  configurable: true,
  writable: true,
  value: 23
});

console.log('speak' in person);  // true
console.log('name' in person);   // true
console.log('age' in person);   // true
console.log('job' in person);   // false

因为job不存在person中,也不存在person对象的原型链上,所以结果为false。

再看个例子:

var array = new Array('a','b','c','d','e');
delete array[3];
console.log(3 in array); // false
console.log(array.length); // 5

从这个例子中看出,当删除数组的某个下标后,数组下标确实不存在了。但是没有改变数组的长度。只是该位置被空出来了而已。

2. hasOwnProperty

如果对象自身属性中存在指定的属性,那么hasOwnProperty()方法将会返回true,否则返回false。

注意:

  • hasOwnProperty 不会检查对象原型链上的属性。

  • hasOwnProperty 不论属性是否可以枚举

  • hasOwnProperty方法存在于Object.prototype上,因此只要对象的原型链上存在Object.prototype, 就可以直接访问hasOwnProperty方法。有点对象(通过Object.create(null)创建的对象)没有连接到Object.prototype,那么就无法访问到hasOwnProperty方法。

  • JavaScript 没有保护hasOwnProperty属性名,因此,任何对象都可以使用hasOwnProperty这个名字作为属性名。

  • 上述两点,所以可必要使用Object.prototype.hasOwnProperty.call(obj,prop)这种形式判断某个属性的存在, 这样就无需担心obj上是否存在hasOwnProperty方法或者hasOwnProperty被覆盖的问题。

举个例子:

let man = {
  speak: 'I can'
}

let person = Object.create(man);

person.name='noshower';

Object.defineProperty(person, 'age', {
  enumerable: false,
  configurable: true,
  writable: true,
  value: 23
});

console.log(person.hasOwnProperty('speak')); // false
console.log(person.hasOwnProperty('name')); // true
console.log(person.hasOwnProperty('age')); // true
console.log(person.hasOwnProperty('job')); // false

因为speak属性存在于原型链上,所以返回false。
因为name属性是自有属性,所以返回true。
因为age属性是自有属性,虽然该属性不可枚举,但结果还是true。
因为job属性不存在,所以没有false。

3. for...in 循环

for...in 循环用来遍历对象的可枚举属性,包括原型链上的

注意:

  • for..in 循环以任意顺序迭代一个对象的属性,不同浏览器遍历属性的顺序可能不同。 因此,最好不要在迭代中对对象进行添加、修改或删除属性。

  • 不要使用for..in遍历数组

  • for...in不会返回不可枚举的属性

举个例子:

let man = {
  speak: 'I can'
}

let person = Object.create(man);

person.name='noshower';

Object.defineProperty(person, 'age', {
  enumerable: false,
  configurable: true,
  writable: true,
  value: 23
});

for(let prop in person){
  console.log(prop);   // name , speak (并不一定是这样的输出顺序)
}

其中age属性没有遍历得到,因为它是不可枚举的。

4. propertyIsEnumerable

如果一个属性是对象的自有属性(直接定义在对象上的)且该属性可枚举,那么 propertyIsEnumerable方法返回true,否则返回false。

举个例子:

let man = {
  speak: 'I can'
}

let person = Object.create(man);

person.name='noshower';

Object.defineProperty(person, 'age', {
  enumerable: false,
  configurable: true,
  writable: true,
  value: 23
});

console.log(person.propertyIsEnumerable('speak')); //false
console.log(person.propertyIsEnumerable('name')); // true
console.log(person.propertyIsEnumerable('age')); // false

5. Object.keys()

Object.keys() 方法会返回一个由给定对象的所有自身可枚举属性组成的数组。

注意:

  • Object.keys() 返回的属性是可枚举

  • Object.keys()返回的属性是对象的自有属性

  • 结果数组中属性名的排列顺序和使用 for ...in循环遍历该对象时返回的顺序一致

举个例子:

let man = {
  speak: 'I can'
}

let person = Object.create(man);

person.name='noshower';

Object.defineProperty(person, 'age', {
  enumerable: false,
  configurable: true,
  writable: true,
  value: 23
});

console.log(Object.keys(person)); // [ 'name' ]

6. Object.getOwnPropertyNames()

Object.getOwnPropertyNames()方法会返回一个数组,包含所有自有属性,无论它们是否可枚举。

注意:

  • 返回的是自有属性
  • 不论是否可枚举
  • 不包括Symbol值作为名称的属性
  • 数组中可枚举属性的顺序与通过for...in循环(或Object.keys)迭代该对象属性时一致。数组中不可枚举属性的属性未定义。

举个例子:

let man = {
  speak: 'I can'
}

let person = Object.create(man);

person.name='noshower';

Object.defineProperty(person, 'age', {
  enumerable: false,
  configurable: true,
  writable: true,
  value: 23
});

console.log(Object.getOwnPropertyNames(person)); //[ 'name', 'age' ]

7.自定义函数:getOwnInnumerablePropertyNames

getOwnInnumerablePropertyNames 只获取对象自身的所有不可枚举属性

function getOwnInnumerablePropertyNames (obj){
    //返回对象的所有自有属性,包括不可枚举的
    let props = Object.getOwnPropertyNames(obj);
    //返回对象的所有可枚举属性
    let propsEnum = Object.keys(obj); 
    // 过滤出所有不可枚举的
    return props.filter(function(key){
      return propsEnum.indexOf(key) === -1;
    })
}

参考文献

  • 《你不知道的JavaScript 上卷》

  • MDN

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容

  •   面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意...
    霜天晓阅读 2,089评论 0 6
  • 函数和对象 1、函数 1.1 函数概述 函数对于任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且...
    道无虚阅读 4,511评论 0 5
  • 面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的慨念,而通过类可以创建任意多个...
    threetowns阅读 871评论 0 4
  • 第3章 基本概念 3.1 语法 3.2 关键字和保留字 3.3 变量 3.4 数据类型 5种简单数据类型:Unde...
    RickCole阅读 5,092评论 0 21
  • 文‖苍穹一君 越是接近真相的时候 心里好慌 这是不是说 曾经的深情 都只是个荒诞的笑话 被披上红头巾的人 心里会发...
    苍穹一君阅读 242评论 9 10