您好我在这里传递函数参数Object Destructuring Demo
时会经历对象解构的使用示例function drawES6Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25} = **{}**) {
console.log(size, cords, radius);
// do some chart drawing
}
// In Firefox, default values for destructuring assignments are not yet
implemented (as described below).
// The workaround is to write the parameters in the following way:
// ({size: size = 'big', cords: cords = { x: 0, y: 0 }, radius: radius =
25} = **{}**)
drawES6Chart({
cords: { x: 18, y: 30 },
radius: 30
});
有人能告诉我在函数参数末尾使用空对象赋值的原因是什么,我在上面用粗体标记(嵌入双星)?
答案 0 :(得分:9)
如果你使用它,并调用没有参数的函数,它的工作原理:
function drawES6Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25} = {}) {
console.log(size, cords, radius);
// do some chart drawing
}
drawES6Chart();
如果没有,则抛出错误:
TypeError:无法将undefined转换为object
function drawES6Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25}) {
console.log(size, cords, radius);
// do some chart drawing
}
drawES6Chart();
答案 1 :(得分:5)
使用默认值进行的解构只会在传递没有相应属性的对象时执行。整个参数的= {}
默认值允许不传递(空)对象。
它使drawES6Chart()
等同于drawES6Chart({})
。
答案 2 :(得分:4)
您有一个具有默认值的对象,但该对象也是一个参数,因此它需要一个空对象作为第一个参数的默认值,这是填充的对象值。
function drawES6Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25} = {}) {
}
在伪代码中,它将是:
function drawES6Chart({**first argument**} = {**default value for first argument**}) {
}
答案 3 :(得分:2)
这是函数参数的默认值。不使用= {}
JavaScript解释器在没有对象传递给函数时抛出错误,因为它无法解构undefined
值。
答案 4 :(得分:2)
这里是对该现象的描述(比我原先打算的要长得多) 您是从更严格的角度观察。 为什么更严格? 想调查这个问题,因为我不确定是否有 有关函数默认参数的特殊规则,或者是否存在某些特殊规则 我不了解的关于销毁的基础知识。原来,那是 后者。
我将使用伪语法描述我的发现,该伪语法在某种程度上反映了您的意愿 参见ECMA-262。那是我唯一的参考。
有解构分配和解构绑定 模式。两者的目的都是引入名称并分配 值。
ObjectAssignmentPattern:'{'AssignmentPropertyList'}'= AssignmentExpression AssignmentPropertyList:AssignmentProperty [','AssignmentProperty]
这两个只是说明了“解构分配”的一般形式。
AssignmentProperty:IdentifierReference [Initializer]
这是LHS中名称的“默认值”。
AssignmentProperty:PropertyName':'AssignmentElement AssignmentElement:LeftHandSideExpression [Initializer]
这使得解构可以递归嵌套,但是语义必须是 定义。
如果你看
DestructuringAssignmentEvaluation,
您可以看到谁被分配了什么。 ObjectAssignmentPattern 不太好
有趣的是,它给出了LHS的基本'{' assignments '}'
结构,
更有趣的是12.15.5.3,
PropertyDestructuringAssignmentEvaluation 。这显示了当您
实际分配默认值,以及绑定更深层嵌套的名称时。
AssignmentProperty:IdentifierReference [Initializer]
步骤3在此算法中很重要,其中调用GetV
。在这次通话中
正在尝试获取当前分配给的名称的值
(LHS)来自 value (RHS)。这会抛出错误,这就是以下代码段的原因
抛出:
y = Object.defineProperty({},'foo',{get: () => {throw new Error("get foo");}})
{foo} = y;
下一步(第4步)仅评估初始化程序是否存在,并且 从RHS获得的值未定义。例如:
y = Object.defineProperty({},'foo',{get: () => undefined})
{foo = 3} = y; // foo === 3
请注意,此步骤以及将值实际“放入”所需位置的步骤 去,都可以扔。下一个项目比较棘手,混乱之处在于 肯定会出现:
AssignmentProperty:PropertyName':'AssignmentElement
这里的语义是将罐子打到 KeyedDestructuringAssignmentEvaluation, 传递 PropertyName 和当前值(RHS)。这是它的标题 运行时语义:
AssignmentElement:DestructuringAssignmentTarget [Initializer]
随后的算法步骤有些熟悉,有些意外 和间接。该算法中几乎任何步骤都可以抛出,因此不会 明确指出。步骤1是另一个“递归基础”,说如果 目标不是对象或数组文字(例如,只是标识符),则让 lref 是(请注意,它不必是标识符,而不必是标识符 可以分配给例如
w = {}
{x:w.u = 7} = {x:3} // w == {u:3}
然后,尝试检索“目标值” value.propertyName
,
使用 GetV 。如果未定义此值,则尝试获取
初始化值,该值在第6步中放入 lref 中。步骤5是递归的
调用,剥去尽可能多的层以实现基础
变形的分配。这是我认为可以说明的更多示例
重点。
{x={y:1}} = {} // x == {y:1}
{x:{y=1}} = {} // error, {}.x is undefined, tried to find {}.x.y
x = 'foo'
{x:{y=1}} = {x} // x == 'foo', y == 1.
// x doesn't get assigned in this destructuring assignment,
// RHS becomes {x:x} === {x:'foo'} and since 'foo'.y is
// undefined, y gets the default 1
{x:{y=1}} = {x:{y}} // error, tried to give object value {y} === {y:y} to x
// in RHS, but y is undefined at that point
y = 'foo'
{x:{y=1}} = {x:{y}} // y == 'foo', gave {y} === {y:y} === {y:'foo'} to x in RHS
{x:{y=1}} = {x:{y:2}} // y == 2, maybe what you wanted?
// exercises:
{x=1} = undefined // error
{x=1} = null // error
{x=1} = null || undefined // error
{x=1} = null | undefined // can you guess? x == 1
在看到以下代码后,我实际上开始研究销毁 react-redux的来源:
export function createConnect({
connectHOC = connectAdvanced,
mapStateToPropsFactories = defaultMapStateToPropsFactories,
mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,
mergePropsFactories = defaultMergePropsFactories,
selectorFactory = defaultSelectorFactory
} = {}) {
所以,我开始挖掘的第一个地方是:
这里有一些“堆栈跟踪”试图跟踪相关产品以 让我了解具有约束力的东西。
-> 13.3.3破坏绑定模式
++ BindingIdentifier ,初始化器
+ SingleNameBinding ,
+ PropertyName ':' BindingElement
据我所知,解构绑定和 解构分配是可以使用它们的地方以及词汇的不同方式 处理环境。在形式参数之外解构绑定 列表(等等)需要初始化程序,并且传递了Destructuring Binding 明确地说明一个环境,而根据其定义暗示分配 初始化程序”,从“环境”中获取它们的值。我很高兴听到 为什么会出错,但这是一个快速演示:
var {x}; // syntax error
function noInit({x}) { return x; }
// ok
noInit() // runtime error
noInit({}) // undefined
noInit({x:4}) // 4
function binding({x:y} = {x:y}){ return y; }
function assigning(){({x:y} = {x:y}); return y}
binding() // error, cannot access y before initialization
assigning() // error, y is not defined
y = 0
binding() // still error
assigning() // 0 - now y is defined
我得出以下结论。破坏绑定和分配的目的 是将名称引入当前的词法环境中,可以选择分配 他们的价值观。嵌套解构是为了剖析您的数据形状 想要,而且您不会免费获得自己的名字。你可以有初始化器 作为默认值,但是一旦使用它们,您将无法再进行深入研究。如果 您雕刻出特定形状(实际上是一棵树),然后尝试将其绑定到 可能具有未定义的叶子,但分支节点必须与您所拥有的匹配 描述(名称和形状)。
当我开始时,发现给定不支持解构的目标,看看tsc(打字稿编译器)会将这些内容转换为什么很有帮助和有趣。
以下代码:
function f({A,B:{BB1=7,BB2:{BBB=0}}}) {}
var z = 0;
var {x:{y=8},z} = {x:{},z};
将(tsc --target es5 --noImplicitAny false
)转换为:
function f(_a) {
var A = _a.A,
_b = _a.B,
_c = _b.BB1,
BB1 = _c === void 0 ? 7 : _c,
_d = _b.BB2.BBB,
BBB = _d === void 0 ? 0 : _d;
}
var z = 0;
var _a = { x: {}, z: z },
_b = _a.x.y,
y = _b === void 0 ? 8 : _b,
z = _a.z;