前不久,一朋友求助,让我给解释一波Object.keys(), Object.getOwnPropertyNames(), for in的区别,面试中好几次呗问了。所以,抽了点时间看了看,大概把我看的过程中做的demo记录一下。

看了网上一些关于介绍Object.keys(), Object.getOwnPropertyNames(), for in, Object.getOwnPropertySymbol()的区别,都介绍得不是很详细,不容易理解,今天抽空来说说这三者的区别。

废话不多说,直接上代码。

defineProperty() => 给对象添加单个属性及属性值的,并规定该属性是否可枚举,默认是不可枚举的;所以正常情况下,我们给对象添加单个属性时,只需要用.操作即可。亦,obj.e = 2。这种方式添加的属性默认是可枚举的。

我们通过设置 enumerable 的值来设置属性是否可枚举。

来,下面demo运行起来。

var obj = { a: "1", b: "2"};
Object.prototype.protoName = "proto foobar";
var foo = Symbol("foo");
// 给obj 添加了一个键名为 c, foo 变量值
Object.defineProperty(obj, "c", {
value: "3",
enumerable: false // 定义是否可枚举,默认 false
})
Object.defineProperty(obj, "d", {
value: "4",
enumerable: true // 定义是否可枚举
})
Object.defineProperty(obj, foo, {
value: "foobar",
enumerable:false
});

打印的结果为:

{a: "1", b: "2", d: "4", c: "3", Symbol(foo): "foobar"}

OK,接下来我们,我们输出日志看看...

for (var i in obj) {
console.log(" for in : ", i); // 输出 a b d protoName
if (obj.hasOwnProperty(i)) {
console.log("obj.hasOwnProperty(i): ", i); // a b d
}
}
console.log("Object.keys(obj): ", Object.keys(obj)); // ["a", "b", "d"]
console.log("Object.getOwnPropertyNames(obj): ", Object.getOwnPropertyNames(obj)); // ["a", "b", "c", "d"]
console.log("Object.getOwnPropertySymbols(obj): ", Object.getOwnPropertySymbols(obj)); // [Symbol(foo)]
// JSON.stringify(obj) 只能将自身的属性转化成字符串
console.log("JSON.stringify(obj): ", JSON.stringify(obj)); // {"a": "1", "b": "2", "d": "4"}

就上面demo,简单总结一下:

  1. keys() => 输出为一个数组,取到的是 obj 的所有的自身可枚举属性。其功能和for in + hasOwnProperty()功能是一致的
  2. getOwnPropertyNames() => 输出为一个数组,取到的是 obj 的所有自身属性。(可枚举、不可枚举,但不包括symbol类型的属性)
  3. getOwnPropertySymbol() => 输出为一个数组,取到的是 obj 的所有自身的Symbol属性
  4. for in => 遍历 obj 的所有属性,包括自身属性和原型上的所有可枚举的属性
  5. JSON.stringify() => 只能将自身的可枚举的属性转化成字符串

OK, 运行完上面demo后发现,问题是不是轻轻松松地解决了喂,然而,并没有。仔细对比一下上面的日志,然后,来,接着往下走。

for in obj => 能遍历obj的所有属性,包括原型上的属性。(包括原型上的可枚举的属性和方法),有点蒙比了?

如果确实蒙比了,我们接着往下敲代码

Object.defineProperty(obj, "func1", {
value: function() {console.log("func1")}
})
Object.defineProperty(obj, "func2", {
value: function() {
console.log("func2")
},
enumerable: true
}) // 来,我们在在原型上添加一个方法
Object.prototype.func3 = function() {
console.log("func3")
} for (var i in obj) {
console.log(" for in : ", i); // 输出 a b d protoName func2 func3
if (obj.hasOwnProperty(i)) {
console.log("obj.hasOwnProperty(i): ", i); // a b d func2
}
}
console.log("Object.keys(obj): ", Object.keys(obj)); // ["a", "b", "d", "func2"]
console.log("Object.getOwnPropertyNames(obj): ", Object.getOwnPropertyNames(obj)); // ["a", "b", "c", "d", "func1", "func2"]
console.log("Object.getOwnPropertySymbols(obj): ", Object.getOwnPropertySymbols(obj)); // [Symbol(foo)]
console.log("JSON.stringify(obj): ", JSON.stringify(obj)); // {"a":"1","b":"2","d":"4"}
console.log("obj: ", obj); // {a: "1", b : "2", d : "4", func2 : ƒ (), c : "3", func1 : ƒ (), Symbol(foo) : "foobar"}

对比上面输出日志,我不难发现:

  1. defineProperty() 和 prototype 添加的属性默认是不可枚举的。
  2. defineProperty() 添加的属性时属于自身属性。

哈哈哈,能读到这儿,我想未来的我,可能没有晕吧。

管他呢,简单提个醒吧,方便以后自己更快速地懂这些东西;

  1. for in 没有 func1, 是因为defineProperty()定义的是自身属性,且默认不可枚举。protoName 是在原型 prototype 上,所以会有。
  2. hasOwnProperty() 是只取自身属性,所以 原型上的 protoName, func3 都没有。
  3. keys() 所有的自身可枚举属性, 所以 protoName 和 func3 首先排除了。c 和 func2 是不可枚举。
  4. getOwnPropertyNames() 所有自身属性。所以原型上的protoName 和 func3 都被排除了。
  5. JSON.stringify() 只要自身的,且可枚举的属性。认真看看,转字符串和直接输出的 obj 有多大区别。

所以,网上关于深度克隆一个对象的方式 ---- JSON.parse(JSON.stringify(obj)),严格来说,是不正确的。

然而此时,我就有问题要讲啦。

实际项目中我们应该怎么选,如何规避上述的问题呢?

还待高人指点迷津,

抑或,以后自己去发现。


今天被同事骗了,说 撒拉黑你好 的意思。来了一个男同事,我就对他说了:

-- 撒拉黑

-- 滚犊子

啊,留我一人在风中凌乱...

   .>|=|<.

论Object.keys(), Object.getOwnPropertyNames(), for in, Object.getOwnPropertySymbol()区别的更多相关文章

  1. for in,Object.keys()与for of的用法与区别

    Array.prototype.sayLength=function(){ console.log(this.length); } let arr = ['a','b','c','d']; arr.n ...

  2. for in,Object.keys和Object.getOwnPropertyNames的区别

    var parent = Object.create(Object.prototype, { a: { value: 1, writable: true, enumerable: true, conf ...

  3. Object.keys() https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

    Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用for...in 循环遍历该对象时返回的顺序一致 (两者的主要区别是 一个 for-in ...

  4. Object.keys的‘诡异’特性,你值得收藏!

    先从'诡异'的问题入手 例1: 纯Number类型的属性 const obj = { 1: 1, 6: 6, 3: 3, 2: 2 } console.log('keys', Object.keys( ...

  5. Object.keys(),Object.values(),Object.entries()

    (1)Object.keys() //       返回数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名. eg:var obj = {a:1,b:'gy'} Ob ...

  6. 关于Object.keys()和Object.values()的使用

    关于Object.keys()和Object.values()的使用 1. 关于Object.keys() 1) 处理对象,返回可枚举的所有可枚举属性的字符串数组 let person ={ name ...

  7. JavaScript中in操作符(for..in)、Object.keys()和Object.getOwnPropertyNames()的区别

    ECMAScript将对象的属性分为两种:数据属性和访问器属性.每一种属性内部都有一些特性,这里我们只关注对象属性的[[Enumerable]]特征,它表示是否通过 for-in 循环返回属性,也可以 ...

  8. Object.keys、Object.getOwnPropertyNames区别

    用途 Object.keys 定义:返回一个对象可枚举属性的字符串数组: Object.getOwnPropertyNames 定义:返回一个对象可枚举.不可枚举属性的名称: 属性的可枚举性.不可枚举 ...

  9. [转] JavaScript中in操作符(for..in)、Object.keys()和Object.getOwnPropertyNames()的区别

    ECMAScript将对象的属性分为两种:数据属性和访问器属性.每一种属性内部都有一些特性,这里我们只关注对象属性的[[Enumerable]]特征,它表示是否通过 for-in 循环返回属性,也可以 ...

  10. 小tips:JS之for in、Object.keys()和Object.getOwnPropertyNames()的区别

    for..in循环 使用for..in循环时,返回的是所有能够通过对象访问的.可枚举的属性,既包括存在于实例中的属性,也包括存在于原型中的实例.这里需要注意的是使用for-in返回的属性因各个浏览器厂 ...

随机推荐

  1. SQLSERVER CTE表 row_number()字段 BUG

    当CTE中 引用的子视图的字段用了  row_number() over等那么有可能造成row_number() 的对应关系出错的问题 所以CTE  row_number() over 排序字段 必须 ...

  2. JavaScript 世界万物诞生记

    一. 无中生有 起初,什么都没有.造物主说:没有东西本身也是一种东西啊,于是就有了null: 现在我们要造点儿东西出来.但是没有原料怎么办?有一个声音说:不是有null嘛?另一个声音说:可是null代 ...

  3. Docker命令详解(run篇)

    命令格式:docker run [OPTIONS] IMAGE [COMMAND] [ARG...] Usage: Run a command in a new container 中文意思为:通过r ...

  4. 图像分类(一)GoogLenet Inception_V1:Going deeper with convolutions

    论文地址 在该论文中作者提出了一种被称为Inception Network的深度卷积神经网络,它由若干个Inception modules堆叠而成.Inception的主要特点是它能提高网络中计算资源 ...

  5. javaweb(3)之JSP&EL&JSTL

    JSP(Java Server Page) 介绍 什么是 JSP ? 从用户角度看,JSP 就是一个网页. 从开发者角度看,它其实就是一个继承了 Servlet 的 java 类,所以可以直接说 JS ...

  6. Linux操作系统加固

    1. 账号和口令 1.1 禁用或删除无用账号 减少系统无用账号,降低安全风险. 操作步骤 使用命令 userdel <用户名> 删除不必要的账号. 使用命令 passwd -l <用 ...

  7. ARIMA模型总结

    时间序列建模基本步骤 获取被观测系统时间序列数据: 对数据绘图,观测是否为平稳时间序列:对于非平稳时间序列要先进行d阶差分运算,化为平稳时间序列: 经过第二步处理,已经得到平稳时间序列.要对平稳时间序 ...

  8. 大数据小视角3:CarbonData,来自华为的中国力量

    连续两篇文章都聊了不同的存储格式,这篇我们继续深入来看看在存储格式的演变之上有什么新的"黑科技".华为公司在2016年开源了类parquet的列存格式:CarbonData,并且贡 ...

  9. ASP.NET MVC案例教程(二)

    ASP.NET MVC案例教程(二) 让第一个页面跑起来 现在,我们来实现公告系统中的第一个页面——首页.它非常简单,只包括所有公告分类的列表,并且每个列表项是一个超链接.其中分类数据是用我们的Moc ...

  10. acm 2015北京网络赛 F Couple Trees 主席树+树链剖分

    提交 题意:给了两棵树,他们的跟都是1,然后询问,u,v 表 示在第一棵树上在u点往根节点走 , 第二棵树在v点往根节点走,然后求他们能到达的最早的那个共同的点 解: 我们将第一棵树进行书链剖,然后第 ...