为什么对象在JavaScript中不可编辑?
为什么默认情况下对象不可编辑 我一直看到与迭代对象相关的问题,常见的解决方案是迭代对象的属性并以这种方式访问对象中的值。这似乎很常见,让我想知道为什么对象本身不可移植。 默认情况下,像ES6这样的语句很适合用于对象。由于这些功能仅适用于不包括为什么对象在JavaScript中不可编辑?,javascript,arrays,iterator,ecmascript-6,ecmascript-5,Javascript,Arrays,Iterator,Ecmascript 6,Ecmascript 5,为什么默认情况下对象不可编辑 我一直看到与迭代对象相关的问题,常见的解决方案是迭代对象的属性并以这种方式访问对象中的值。这似乎很常见,让我想知道为什么对象本身不可移植。 默认情况下,像ES6这样的语句很适合用于对象。由于这些功能仅适用于不包括{}对象的特殊“iterable对象”,因此我们必须对我们想要使用它的对象进行调整 for…of语句创建了一个循环,循环遍历iterable对象 (包括数组、映射、集合、参数对象等) 例如,使用ES6: 以上内容按照我在Firefox中运行代码时希望的顺序正
{}
对象的特殊“iterable对象”,因此我们必须对我们想要使用它的对象进行调整
for…of语句创建了一个循环,循环遍历iterable对象
(包括数组、映射、集合、参数对象等)
例如,使用ES6:
以上内容按照我在Firefox中运行代码时希望的顺序正确记录数据(Firefox支持):
默认情况下,{}
对象是不可编辑的,但为什么?可移植对象的缺点是否会超过其潜在好处?与此相关的问题有哪些?
此外,由于{}
对象不同于“类似数组”的集合和“iterable对象”,例如和,因此它们不能转换为数组
例如:
var argumentsArray=Array.prototype.slice.call(参数)代码>
或与数组方法一起使用:
Array.prototype.forEach.call(节点列表,函数(元素){})
除了我上面提到的问题之外,我还想看到一个关于如何将{}
对象转换为iterables的工作示例,特别是那些提到[Symbol.iterator]
的人,这应该允许这些新的{}
“iterable对象”使用类似的语句来表示of
。另外,我想知道使对象可移植是否允许将它们转换为数组
我尝试了下面的代码,但是我得到了一个TypeError:无法将未定义的转换为object
var example = {a: {e: 'one', f: 'two'}, b: {g: 'three'}, c: {h: 'four', i: 'five'}};
// I want to be able to use "for...of" for the "example" object.
// I also want to be able to convert the "example" object into an Array.
example[Symbol.iterator] = function* (obj) {
for (let key of Object.keys(obj)) {
yield [key, obj[key]];
}
};
for (let [key, value] of example) { console.log(value); } // error
console.log([...example]); // error
我想问题应该是“为什么没有内置的对象迭代
向对象本身添加可写性可能会产生意想不到的后果,不,没有办法保证顺序,但编写迭代器非常简单
function* iterate_object(o) {
var keys = Object.keys(o);
for (var i=0; i<keys.length; i++) {
yield [keys[i], o[keys[i]]];
}
}
我将尝试一下。请注意,我与ECMA没有关联,也无法了解他们的决策过程,因此我无法确定他们为什么做了或没有做任何事情。不过,我将陈述我的假设,并尽我所能
1.为什么首先要为
构造的…添加一个
JavaScript已经在
结构中包含了一个
for…,它可以用来迭代对象的属性。但是,它非常有用,因为它枚举了对象上的所有属性,并且往往只在简单的情况下工作
它在更复杂的情况下会崩溃(包括在数组中,在数组中,它的使用往往是通过正确使用数组所需的保护措施来实现的)。您可以通过使用hasOwnProperty
(除其他外)来解决这一问题,但这有点笨拙和不雅观
因此,我的假设是,正在添加for…of
构造,以解决与for…in
构造相关的缺陷,并在迭代时提供更大的实用性和灵活性。人们倾向于将for…in
视为一个forEach
循环,通常可应用于任何收集并在任何可能的上下文中生成合理的结果,但事实并非如此。循环的for…修复了这一问题
我还假设现有ES5代码在ES6下运行并产生与在ES5下相同的结果是很重要的,因此不能对结构中的for…的行为进行破坏性更改
2.for…of
如何工作?
对于这部分很有用。具体来说,如果对象定义了符号.iterator
属性,则将其视为iterable
属性定义应该是一个函数,它返回集合中的项,one、by、one,并设置一个标志,指示是否有更多的项要获取。提供了预定义的实现,并且相对清楚的是,使用for…of
只会委托迭代器函数
这种方法很有用,因为它使提供自己的迭代器变得非常简单。我可能会说,这种方法可能会带来实际问题,因为它依赖于定义一个以前不存在的属性,但我可以告诉你,情况并非如此,因为除非你仔细考虑,否则新属性基本上会被忽略你可以去寻找它(也就是说,它不会作为一个键出现在循环中,等等)。所以情况并非如此
撇开实际的非问题不谈,从概念上讲,用一个新的预定义属性开始所有对象,或者含蓄地说“每个对象都是一个集合”,可能会被认为是有争议的
3.为什么对象在默认情况下不可iterable
使用for…of
我猜这是以下因素的组合:
默认情况下,将所有对象设置为可伸缩的
,可能被认为是不可接受的,因为它添加了以前没有的属性,或者因为对象(不一定)是集合。正如Felix所指出的,“对函数或正则表达式对象进行迭代意味着什么?”
简单对象已经可以在
中使用
对…进行迭代,并且不清楚内置迭代器实现与现有的
对中的行为有什么不同/更好的地方。因此,即使#1是错误的,并且添加属性是可以接受的,也可能不会
function* iterate_object(o) {
var keys = Object.keys(o);
for (var i=0; i<keys.length; i++) {
yield [keys[i], o[keys[i]]];
}
}
for (var [key, val] of iterate_object({a: 1, b: 2})) {
console.log(key, val);
}
a 1
b 2
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for (var value of myIterable) {
console.log(value);
}
for (let levelOneKey in object) {
console.log(levelOneKey); // "example"
console.log(object[levelOneKey]); // {"random":"nest","another":"thing"}
var levelTwoObj = object[levelOneKey];
for (let levelTwoKey in levelTwoObj ) {
console.log(levelTwoKey); // "random"
console.log(levelTwoObj[levelTwoKey]); // "nest"
}
}
obj = {
a: '1',
b: { something: 'else' },
c: 4,
d: { nested: { nestedAgain: true }}
};
obj[Symbol.iterator] = function() {
var keys = [];
var ref = this;
for (var key in this) {
//note: can do hasOwnProperty() here, etc.
keys.push(key);
}
return {
next: function() {
if (this._keys && this._obj && this._index < this._keys.length) {
var key = this._keys[this._index];
this._index++;
return { key: key, value: this._obj[key], done: false };
} else {
return { done: true };
}
},
_index: 0,
_keys: keys,
_obj: ref
};
};
var array = [...myIterable];
var files = {
'/root': {type: 'directory'},
'/root/example.txt': {type: 'file'}
};
for (let [key, {type}] of Object.entries(files)) {
console.log(type);
}
Object.prototype[Symbol.iterator] = function * () {
for (const [key, value] of Object.entries(this)) {
yield {key, value}; // or [key, value]
}
};
for (const {key, value:{type}} of files) {
console.log(key, type);
}
for (const {key, value:item1} of example) {
console.log(key);
console.log(item1);
for (const {key, value:item2} of item1) {
console.log(key);
console.log(item2);
}
}
Object.defineProperty(Object.prototype, Symbol.iterator, {
enumerable: false,
value: function * (){
for(let key in this){
if(this.hasOwnProperty(key)){
yield [key, this[key]];
}
}
}
});
var iterableProperties={
enumerable: false,
value: function * () {
for(let key in this) if(this.hasOwnProperty(key)) yield this[key];
}
};
var fruit={
'a': 'apple',
'b': 'banana',
'c': 'cherry'
};
Object.defineProperty(fruit,Symbol.iterator,iterableProperties);
for(let v of fruit) console.log(v);
var instruments={
'a': 'accordion',
'b': 'banjo',
'c': 'cor anglais'
};
Object.defineProperty(instruments,Symbol.iterator,iterableProperties);
for(let v of instruments) console.log(v);