◆ enumerable の列挙するかは for in など一部でのみ関係する
◆ Object.keys で組み込みのメソッドやプロパティが見えないのは enumerable 見えないから
 ◆ 配列の length とか
◆ forEach はプロトタイプチェーンの先でもプロパティあると実行される

いまだに enumerable のスペルに自信のない私ですが 今回は enumerable 使ってみます
ときどきスペルが間違ってるかもしれませんがご容赦ください

for in

まず 普通に for in をしてみます
o2 ---> o1 にプロトタイプチェーンをつないでます
var o1 = {x:10}
var o2 = {a:1, __proto__:o1}
for(var i in o2) console.log(i)
// a x
o1 に enumerable を true と false でプロパティを追加します
Object.defineProperty(o1, "y", {enumerable:false, value:20})
o2.y
// 20

Object.defineProperty(o1, "z", {enumerable:true, value:30})
o2.z
// 30

for(var i in o2) console.log(i)
// a x z
for in では enumerable = false で追加した y が見えていません
enum って列挙型で使われますし それの able 系ですので列挙されるかどうかを表してるんですね

__proto__ や constructor や 各 prototype にあるメソッドは enumerable が false です
enumerable が false だと Chrome だと薄く表示してくれます

enumerable-s-01

forEach

じゃあ つぎは配列メソッド
var a1 = [1,2]
var a2 = new Array(5)
a2[0] = 10
a2.__proto__ = a1

a2.forEach(e=>{console.log(e)})
// 10 2
プロトタイプチェーンの先の 2 も表示されています
enumerable が false のプロパティを作ってみます
Object.defineProperty(a1, "3", {enumerable:false, value:3})
a2.forEach(e=>{console.log(e)})
// 10 2 3
表示されていますね

ドキュメントを見たわけじゃないですが たぶん forEach 系の中身ってこんなのなんだと思います
Array.prototype.forEach = function(cb){
for(var i = 0, l = this.length; i < l; i++) i in this && cb(this[i], i, this)
}
in でオブジェクトとしてキーがあるかだけを見て enumerable かどうかなんて気にしないです
for in だと enumerable = false は無いもの扱いなのにただの in だと enumerable = false でもあるもの扱いされるようです

んー わかりづらいー
とりあえず関係しそうなのをまとめてみました

プロトタイプ
チェーン
enumerable取得方法
in見るfalse も指定したプロパティに対して true, false
for in見るtrue だけ指定したオブジェクトをループで全部のキー
obj
.hasOwnProperty
見ないfalse も指定したプロパティに対して true, false
Object
.getOwnPropertyNames
見ないfalse も指定したオブジェクトのキー全部を配列で
Object.keys見ないtrue だけ指定したオブジェクトのキー全部を配列で
obj
.propertyIsEnumerable
見ないfalse も指定したプロパティに対して true, false
arr.forEach見るfalse も数値のキーのみループで

own property 系は名前の通り プロトタイプチェーンは見ないで自分自身が対象です
enumerable は気にせずあるものはあるって返って来ます

propertyIsEnumerable はそのプロパティが enumerable か教えてくれます
存在しなかったり プロトタイプチェーンの先にある場合は false です

一覧取得系でプロトタイプチェーンも見て enumerable = false も持ってくるのが無いです
キーがわからない状態で取得するなら手動でチェーンたどるしか無いのかなー


それぞれの結果と使い方はこんなになります
var obj = {}
Object.defineProperty(obj, "not_enum", {enumerable:false, value:true})
Object.defineProperty(obj, "enum", {enumerable:true, value:true})
var proto = {}
Object.defineProperty(proto, "proto_not_enum", {enumerable:false, value:true})
Object.defineProperty(proto, "proto_enum", {enumerable:true, value:true})
obj.__proto__ = proto

console.log("enum" in obj) // true
console.log("not_enum" in obj) // true
console.log("proto_enum" in obj) // true
console.log("proto_not_enum" in obj) // true

for(var _ in obj) console.log(_)
// enum
// proto_enum


console.log(obj.hasOwnProperty("enum")) // true
console.log(obj.hasOwnProperty("not_enum")) // true
console.log(obj.hasOwnProperty("proto_enum")) // false
console.log(obj.hasOwnProperty("proto_not_enum")) // false

console.log(Object.getOwnPropertyNames(obj))
// [not_enum, enum]

console.log(Object.keys(obj))
// [enum]