var o = Object.create({inherited: 1}, {
foo: {
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
}
});
o.foo; // "foobar"
我遇到了一些问题。我真的不明白我们如何得到字符串"foobar"
作为结果。我将写下我目前对此代码的错误理解,希望有人可以解释我错在哪里。
o
是具有属性foo
。foo
对应于具有一个属性get
的对象。 (这似乎是错的,但我看不出如何。)get
对应于自动调用匿名函数,该函数返回由一行return closured+'bar';
话虽这么说,我希望o.foo
返回一个对象,o.foo.get
返回一个函数,o.foo.get()
返回"foobar"
。
但这不是正在发生的事情,我不知道为什么。
另外,另外,为什么你会这样写东西?为什么写:
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
而不仅仅是:
get: (function () { // a closure
var closured = 'foo';
return closured+'bar';
})()
额外功能层有什么好处?
答案 0 :(得分:2)
Object.create
的第二个参数应该是属性描述符对象。这是一个描述要添加到原型的属性的对象 - 而不是字面上的对象本身。例如:
var o = Object.create({inherited: 1}, {
foo: { /* ... property descriptor object ... */ },
bar: { /* ... property descriptor object ... */ }
});
在上面的示例中,我们将两个属性添加到新对象的原型中:foo
和bar
。可以使用描述符对象以各种方式配置这些属性中的每一个。
描述符对象接受几个配置属性,即:configurable
,enumerable
,value
,writable
,get
,set
。< / p>
在原始示例中,您有效地为属性foo
配置了一个getter函数。如果您只想设置属性foo
的值,那么您必须在描述符中创建一个value
属性并在那里添加您想要的值(实际上它是一个名为{{的属性的对象) 1}}如果你选择)。例如:
get
有关属性描述符对象的更多详细信息,请参阅:Object.defineProperty()
答案 1 :(得分:1)
foo
对应于具有一个属性的对象,并且该属性是一个函数,如您所说,但Object.create的第二个参数用于定义属性。 o.foo
是新对象o
的一个此类属性。它定义了一个getter,因此它不是“value属性”而是“accessor属性”。尝试从o.foo
读取会导致调用getter。
至于
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
它返回一个函数,而
get: (function () { // a closure
var closured = 'foo';
return closured+'bar';
})()
返回字符串'foobar'
,因此它们不等效,但第一个代码块等同于
get: function () { // a closure
var closured = 'foo';
return closured+'bar';
}
也会返回一个函数。在该示例中,该闭包是无用的,但您可以执行
foo: (function() {
var closured = 'foo';
return {
'get': function () {
return closured+'bar';
},
'set': function (value) {
closured = value;
}
};
})()
这样,getter和setter都可以访问closured
,但没有其他函数可以:
console.log(o.foo); // "foobar"
o.foo = "a";
console.log(o.foo); // "abar"
答案 2 :(得分:1)
关于代码,有几件事你不理解。
var o = Object.create({inherited: 1}, {
foo: {
get: function(){ return 1; }
}
});
console.log(o.foo); // 1
o.foo = 5;
console.log(o.foo); // 1
Object.create
的第二个参数描述了对象的属性。在这种情况下,get
部分实际上是一个getter,因此它描述了在读取对象foo
的{{1}}属性时会发生什么。
o
这种结构称为IIFE。它是一个立即调用的函数。 IIFE的优点是它创建了一个局部范围,因此(function () {
var closure = 'foo';
return function () {
return 'bar';
};
})()
变量在外部范围内不可见。这可以避免冲突。
closure
在第一种情况下,闭包变量在getter函数之外,而在第二种情况下,它在内部。外部意味着每次调用函数(getter)时都不会重置其状态,并且它也可以在其他函数中使用,它们将共享相同的变量。这是一个潜在的用例:
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
// versus:
get: function () { // changed it a bit to be a getter
var closured = 'foo';
return closured+'bar';
}
答案 3 :(得分:0)
您的问题的答案可以在this documentation page找到。如果您阅读有关属性的部分,您可以看到Object.create函数的第二个参数不是简单地合并到原型中,而是实际上是具有getter,setter和各种选项的属性的定义。
考虑到这一点,请查看以下代码:
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
正如你所说的,指定了一个自我调用的匿名函数来获取。此函数返回一个函数,该函数关闭闭包变量并返回闭合的+ bar值。这不等同于以下内容:
get: (function () { // a closure
var closured = 'foo';
return closured+'bar';
})()
原因是在这种情况下为get分配了一个实际值而不是一个函数,打破了Object.create期望的属性规范。
答案 4 :(得分:0)
使用get
为名称为getter
的媒体资源定义foo
方法。因此,每次您对foo
具有读访问权时,它都将执行getter方法。这就是为什么立即执行的函数本身返回一个函数(它是结果的getter)。
执行o.foo
将导致对foo
o
属性的读访问权限,因此将执行getter。
答案 5 :(得分:-1)
闭包是在函数外部访问变量的能力。我想你已经知道了。
现在关于为什么要这样做的问题
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
你知道,当你这样做时,你不仅可以获得“封闭”变量,你可以修改它!(虽然你做了修改)同时'封闭'现在也不会被回收。所以它会存在于内存中,而不是在函数返回时清理。