for in
如果让你遍历对象中的key和value,你第一个想到的一定是使用for in
const o={
name:"chengqige",
age:23
}
for (let key in o){
console.log(key,o[key]);
}
看起来是没有问题的,但是如果我在下面加一行代码,输出的结果就可能让你觉得奇怪了
const o = {
name: "chengqige",
age: 23
}
Object.prototype.getName = function () {
}
Object.prototype.test = 12
for (let key in o) {
console.log(key, o[key]);
}
你会发现for in多打印出了两行东西,它们分别是Object原型上的方法和属性getName
和test
,那么这个是为什么呢?
因为for in会打印原型上的所有可以被枚举的方法
什么是可枚举?
在JS中我们给一个对象添加属性一共有三种办法:
1.通过点语法直接添加属性
const o={}
o.a=1
for(let key in o){
console.log(key)
}
输出结果:a
2.通过动态索引添加
什么是动态索引?我们普遍认为一个对象的key是写死的,value是变量,key不可编程,value可以被赋值
// 变量
const value=12
const o={
"写死的":value
}
但是实际上我们的 key也是可以用变量控制的,请看下面的例子
const value=12
const key ="动态索引"
const o={
[key]:value
}
我们使用[]来扩起来变量,表示这个属性是动态的,是有外部变量控制的
3.通过API添加
es6新增一个API可以直接为对象添加属性
const o = {
"b": 12
}
Object.defineProperty(o, "a", {
get() {
return 1
}
})
for (let key in o) {
console.log(key);
}
console.log("i am here", o.a)
但是它的输出结果是:
问题出现了,为什么for in没有出这个属性a,但是我们使用o.a可以打印出来它
因为for in只能遍历可以被枚举的属性,我们改造一下代码,让我们新添加的a是可以被枚举的就好了
Object.defineProperty(o, "a", {
get() {
return 1
},
// +新增
enumerable: true
})
这一次我们发现for in打印的结果就有a了
什么是原型
原型是与生俱来固有的对象,原型里有很多开箱即用的方法,因此在创建某些对象的同时,这个方法就可以被使用了。
比如数组中的push、pop、shift、unshift
任何数组都可以用它们,难道不是嘛
var arr = []
arr.push(1,2,3,4)
// [1,2,3,4]
那么这些原型上的方法是官方的,所以它们是不可以被枚举的,那么用for…in遍历它是没有的
// 这个点语法创造的天生可以被枚举,动态索引也是
Array.prototype.mine = function(){}
for (let key in Array.prototype){
console.log(key,'只有可以枚举的才会出现哦')
}
如果你在浏览器环境下运行这个代码:
<script>
Array.prototype.mine = function () { }
console.log(Array.prototype);
for (let key in Array.prototype){
console.log(key,'只有可以枚举的才会出现哦')
}
</script>
深色的表示这些属性是可以被枚举的,浅色的表示这些属性是不可被枚举的,谷歌浏览器用颜色深浅来划分
那么我们可以不可以让这些不可枚举的方法设置成可枚举的呢?当然可以!
Array.prototype.mine = function () { }
Object.defineProperty(Array.prototype, "push", {
get(){
return 1
},
enumerable: true
})
console.log(Array.prototype);
for (let key in Array.prototype) {
console.log(key, '只有可以枚举的才会出现哦')
}
let arr=[]
arr.push(1,3)
console.log(arr);
总结
for … in不是一个很好的方法,它会把原型链上所有可枚举的方法打印
Object.prototype.mine = function () { }
Array.prototype.okkk = function () { }
let arr = [1, 2, 3]
for (let key in arr) {
console.log(key)
}
const o = {
name: "chengqige",
age: 23
}
Object.prototype.getName = function () {
}
Object.prototype.test = 12
for (let key in o) {
console.log(key, o[key]);
}
替代方案
Object.keys(o).forEach()
const o = {
name: "chengqige",
age: 23
}
Object.prototype.getName = function () {
}
Object.prototype.test = 12
Object.keys(o).forEach(key=>{
console.log(key, o[key]);
})
for in
+hasOwnProperty
const o = {
name: "chengqige",
age: 23
}
Object.prototype.getName = function () {
}
Object.prototype.test = 12
for (let key in o) {
if(o.hasOwnProperty(key)){
console.log(key, o[key]);
}
}
上面两种的输出结果都是