前不久,一朋友求助,让我给解释一波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. 图->连通性->关节点和重连通分量

    文字描述 相关定义:假若在删去顶点v以及和v相关联的各边之后,将图的一个连通分量分割成两个或两个以上的连通分量,则称顶点v为该图的一个关节点.一个没有关节点的连通图称为重连通图. 在重连通图上,任意一 ...

  2. TZOJ:3660: 家庭关系

    描述 给定若干家庭成员之间的关系,判断2个人是否属于同一家庭,即2个人之间均可以通过这些关系直接或者间接联系. 输入 输入数据有多组,每组数据的第一行为一个正整数n(1<=n<=100), ...

  3. CookieUitl

    import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;import javax.servlet.h ...

  4. OOP面向对象编程(下)

    我们怎么去模拟重载,在javasceipr中我们可以通过参数的类型区别或者数量的区别,来去让同样一个函数名字,可以根据不同的参数列表的情况来去调用相应的函数. javascript中函数类型是不确定的 ...

  5. fiddler学习总结--通过Fiddler模拟弱网进行测试

    弱网测试的目的: 弱网测试可以发现一些因为网络问题导致的交互问题,从而更好的完善应用的性能. 关注点:1.卡死,崩溃,无响应,闪退.2.业务交互数据传输正确性. 通过Fiddler可以模拟弱网进行测试 ...

  6. 逆向 AWS API 设计

    由于AWS并没有像Google一样公开出一份API Design Guide,所以只能根据 API 的模样去逆向工程最初的设计考量.既然上一篇介绍了很多 REST 的缺陷,那么这里也会介绍一下 AWS ...

  7. 2015 北京网络赛 C Protecting Homeless Cats hihoCoder 1229 树状数组

    题意:求在平面上 任意两点连线,原点到这个点的距离小于d的点对有多少个,n=200000; 解: 以原点为圆心做一个半径为d的圆,我们知道圆内的点和园内以外的点的连线都是小于d的还有,圆内和园内的点联 ...

  8. vue移动端金融UI组件库滴滴MandMobile面向金融场景设计附功能思维导图

    vue移动端金融UI组件库滴滴MandMobile面向金融场景设计附功能思维导图 Mand Mobile是面向金融场景设计的移动端组件库,基于Vue.js实现.目前已实际应用于滴滴四大金融业务板块的1 ...

  9. django开发(二)

    1.django数据库操作---model的使用以及django自带的数据api django中已经做了ORM,表就是一个类class,表中的一个项就是一个对象object,很好用 1.1django ...

  10. /* * 有五个学生,每个学生有3门课的成绩,从键盘输入以上数据 *(包括学生号,姓名,三门课成绩),计算出平均成绩, *将原有的数据和计算出的平均分数存放在磁盘文件"stud"中。 */

    1.Student类:类中有五个变量,分别是学号,姓名,三门成绩 package test3; public class Student { private int num; private Stri ...