在这个 React(使用 JSX)代码中做了什么...
,它叫什么?
<Modal {...this.props} title='Modal heading' animation={false}>
在这个 React(使用 JSX)代码中做了什么...
,它叫什么?
<Modal {...this.props} title='Modal heading' animation={false}>
那是财产传播符号。它是在 ES2018 中添加的(数组/迭代的传播更早,ES2015),但它在 React 项目中通过转译得到了很长时间的支持(作为“ JSX 传播属性”,即使你也可以在其他地方做,不仅仅是属性)。
{...this.props}
在您正在创建的元素上将“自己的”可枚举属性props
作为离散属性展开。Modal
例如,如果this.props
包含a: 1
and b: 2
,则
<Modal {...this.props} title='Modal heading' animation={false}>
将与
<Modal a={this.props.a} b={this.props.b} title='Modal heading' animation={false}>
但它是动态的,所以包括任何“自己的”属性props
。
由于children
是 中的“自己的”属性props
,因此 spread 将包含它。因此,如果它出现的组件有子元素,它们将被传递给Modal
. 将子元素放在开始标签和结束标签之间只是语法糖——很好的一种——用于将children
属性放在开始标签中。例子:
class Example extends React.Component {
render() {
const { className, children } = this.props;
return (
<div className={className}>
{children}
</div>
);
}
}
ReactDOM.render(
[
<Example className="first">
<span>Child in first</span>
</Example>,
<Example className="second" children={<span>Child in second</span>} />
],
document.getElementById("root")
);
.first {
color: green;
}
.second {
color: blue;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
扩展表示法不仅适用于该用例,而且适用于创建具有现有对象的大部分(或全部)属性的新对象 - 当您更新状态时会出现很多情况,因为您无法修改状态直接地:
this.setState(prevState => {
return {foo: {...prevState.foo, a: "updated"}};
});
这将替换为具有除属性之外的this.state.foo
所有相同属性的新对象,该属性变为:foo
a
"updated"
const obj = {
foo: {
a: 1,
b: 2,
c: 3
}
};
console.log("original", obj.foo);
// Creates a NEW object and assigns it to `obj.foo`
obj.foo = {...obj.foo, a: "updated"};
console.log("updated", obj.foo);
.as-console-wrapper {
max-height: 100% !important;
}
...
被称为扩展属性,顾名思义,它允许扩展表达式。
var parts = ['two', 'three'];
var numbers = ['one', ...parts, 'four', 'five']; // ["one", "two", "three", "four", "five"]
在这种情况下(我将简化它)。
// Just assume we have an object like this:
var person= {
name: 'Alex',
age: 35
}
这个:
<Modal {...person} title='Modal heading' animation={false} />
等于
<Modal name={person.name} age={person.age} title='Modal heading' animation={false} />
所以简而言之,这是一个简洁的捷径,我们可以说。
三个点代表ES6中的扩展运算符。它允许我们在 JavaScript 中做很多事情:
连接数组
var shooterGames = ['Call of Duty', 'Far Cry', 'Resident Evil'];
var racingGames = ['Need For Speed', 'Gran Turismo', 'Burnout'];
var games = [...shooterGames, ...racingGames];
console.log(games) // ['Call of Duty', 'Far Cry', 'Resident Evil', 'Need For Speed', 'Gran Turismo', 'Burnout']
解构数组
var shooterGames = ['Call of Duty', 'Far Cry', 'Resident Evil'];
var [first, ...remaining] = shooterGames;
console.log(first); //Call of Duty
console.log(remaining); //['Far Cry', 'Resident Evil']
组合两个对象
var myCrush = {
firstname: 'Selena',
middlename: 'Marie'
};
var lastname = 'my last name';
var myWife = {
...myCrush,
lastname
}
console.log(myWife); // {firstname: 'Selena',
// middlename: 'Marie',
// lastname: 'my last name'}
这三个点还有另一种用途,称为“休息参数”,它可以将函数的所有参数作为一个数组获取。
函数参数作为数组
function fun1(...params) {
}
JavaScript 中的三个点是展开/休息运算符。
扩展运算符
扩展语法允许在需要多个参数的地方扩展表达式。
myFunction(...iterableObj);
[...iterableObj, 4, 5, 6]
[...Array(10)]
休息参数
其余参数语法用于具有可变数量参数的函数。
function(a, b, ...theArgs) {
// ...
}
ES6中引入了数组的扩展/休息运算符。有一个关于对象传播/休息属性的状态 2提案。
TypeScript 还支持扩展语法,并且可以将其转换为具有小问题的旧版 ECMAScript 。
...
(JavaScript 中的三个点)称为扩展语法或扩展运算符。这允许在任何位置扩展诸如数组表达式或字符串之类的可迭代对象,或者在任何位置扩展对象表达式。这不是 React 特有的。它是一个 JavaScript 运算符。
这里所有这些答案都很有帮助,但我想列出传播语法(传播运算符)最常用的实际用例。
1.组合数组(Concatenate Arrays)
有多种组合数组的方法,但扩展运算符允许您将其放置在数组中的任何位置。如果您想组合两个数组并将元素放置在数组中的任何位置,您可以执行以下操作:
var arr1 = ['two', 'three'];
var arr2 = ['one', ...arr1, 'four', 'five'];
// arr2 = ["one", "two", "three", "four", "five"]
2. 复制数组
当我们想要一个数组的副本时,我们曾经有Array.prototypr.slice()方法。但是,您可以对扩展运算符执行相同的操作。
var arr = [1,2,3];
var arr2 = [...arr];
// arr2 = [1,2,3]
3. 不使用Apply调用函数
在 ES5 中,要将包含两个数字的数组传递给doStuff()
函数,您经常使用Function.prototype.apply()方法,如下所示:
function doStuff (x, y, z) { }
var args = [0, 1, 2];
// Call the function, passing args
doStuff.apply(null, args);
但是,通过使用扩展运算符,您可以将数组传递给函数。
doStuff(...args);
4. 解构数组
您可以根据需要将解构和其余运算符一起使用以将信息提取到变量中:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x); // 1
console.log(y); // 2
console.log(z); // { a: 3, b: 4 }
5.函数参数作为休息参数
ES6 还具有三个点 (...),它是一个剩余参数,用于将函数的所有剩余参数收集到一个数组中。
function f(a, b, ...args) {
console.log(args);
}
f(1,2,3,4,5);
// [ 3, 4, 5 ]
6. 使用数学函数
任何使用 spread 作为参数的函数都可以被可以接受任意数量参数的函数使用。
let numbers = [9, 4, 7, 1];
Math.min(...numbers); // 1
7. 结合两个对象
您可以使用扩展运算符来组合两个对象。这是一种简单而干净的方法。
var carType = {
model: 'Toyota',
yom: '1995'
};
var carFuel = 'Petrol';
var carData = {
...carType,
carFuel
}
console.log(carData);
// {
// model: 'Toyota',
// yom: '1995',
// carFuel = 'Petrol'
// }
8. 将字符串分隔成单独的字符
您可以使用展开运算符将字符串展开为单独的字符。
let chars = ['A', ...'BC', 'D'];
console.log(chars); // ["A", "B", "C", "D"]
你可以想出更多使用Spread Operator的方法。我在这里列出的是它的流行用例。
这是 ES6 的一个特性,在 React 中也有使用。看下面的例子:
function Sum(x, y, z) {
return x + y + z;
}
console.log(Sum(1, 2, 3)); // 6
如果我们最多有三个参数,这种方式很好。但是,如果我们需要添加例如 110 个参数怎么办。我们是否应该将它们全部定义并一一添加?
当然还有一种更简单的方法,叫做spread。而不是传递您编写的所有这些参数:
function (...numbers){}
我们不知道我们有多少参数,但我们知道有很多参数。
在ES6的基础上,我们可以将上面的函数重写如下,并利用它们之间的传播和映射,让它变得轻而易举:
let Sum = (...numbers) => {
return numbers.reduce((prev, current) => prev + current);
}
console.log(Sum(1, 2, 3, 4, 5, 6, 7, 8, 9)); // 45
感谢布兰登莫雷利。他在这里解释得很完美,但是链接可能会死,所以我只是粘贴下面的内容:
扩展语法只是三个点:...
它允许迭代在需要 0+ 个参数的地方展开。没有上下文就很难定义。让我们探索一些不同的用例来帮助理解这意味着什么。
看看下面的代码。在这段代码中,我们不使用展开语法:
var mid = [3, 4];
var arr = [1, 2, mid, 5, 6];
console.log(arr);
上面,我们创建了一个名为mid
. 然后我们创建包含我们的数组的第二个mid
数组。最后,我们注销结果。您希望arr
打印什么?点击上面的运行看看会发生什么。这是输出:
[1, 2, [3, 4], 5, 6]
这是你预期的结果吗?
通过将mid
数组插入到arr
数组中,我们最终得到了数组中的数组。如果这是目标,那很好。但是如果你只想要一个值为 1 到 6 的数组呢?为此,我们可以使用扩展语法!请记住,展开语法允许我们数组的元素展开。
让我们看看下面的代码。一切都是一样的——除了我们现在使用扩展语法将mid
数组插入到arr
数组中:
var mid = [3, 4];
var arr = [1, 2, ...mid, 5, 6];
console.log(arr);
当你点击运行按钮时,结果如下:
[1, 2, 3, 4, 5, 6]
惊人的!
还记得你刚才读到的扩展语法定义吗?这就是它发挥作用的地方。如您所见,当我们创建arr
数组并在数组上使用扩展运算符时,mid
数组不会被插入,而是mid
扩展。这种扩展意味着数组中的每个元素都mid
被插入到arr
数组中。结果不是嵌套数组,而是一个范围从 1 到 6 的数字数组。
JavaScript 有一个内置的数学对象,可以让我们进行一些有趣的数学计算。在此示例中,我们将查看Math.max()
. 如果您不熟悉,Math.max()
则返回零个或多个数字中的最大值。这里有一些例子:
Math.max();
// -Infinity
Math.max(1, 2, 3);
// 3
Math.max(100, 3, 4);
// 100
如您所见,如果要找到多个数字的最大值,则Math.max()
需要多个参数。不幸的是,您不能简单地使用单个数组作为输入。在展开语法之前,在Math.max()
数组上使用最简单的方法是使用.apply()
.
var arr = [2, 4, 8, 6, 0];
function max(arr) {
return Math.max.apply(null, arr);
}
console.log(max(arr));
它有效,它只是真的很烦人。
现在看看我们如何使用扩展语法做同样的事情:
var arr = [2, 4, 8, 6, 0];
var max = Math.max(...arr);
console.log(max);
无需创建函数并使用 apply 方法返回结果Math.max()
,我们只需要两行代码!扩展语法扩展我们的数组元素并将数组中的每个元素单独输入到Math.max()
方法中!
在 JavaScript 中,您不能通过将新变量设置为等于现有数组来复制数组。考虑以下代码示例:
var arr = ['a', 'b', 'c'];
var arr2 = arr;
console.log(arr2);
当您按下运行时,您将获得以下输出:
['a', 'b', 'c']
现在,乍一看,它似乎工作了——看起来我们已经将 arr 的值复制到了 arr2 中。但事实并非如此。你看,在 JavaScript 中处理对象(数组是一种对象)时,我们通过引用而不是值来分配。这意味着 arr2 已分配给与 arr 相同的引用。换句话说,我们对 arr2 所做的任何事情也会影响原始的 arr 数组(反之亦然)。看看下面:
var arr = ['a', 'b', 'c'];
var arr2 = arr;
arr2.push('d');
console.log(arr);
上面,我们已经将一个新元素 d 推送到 arr2 中。然而,当我们注销 arr 的值时,您会看到 d 值也被添加到该数组中:
['a', 'b', 'c', 'd']
不过没必要害怕!我们可以使用扩展运算符!考虑下面的代码。和上面的差不多。但是,我们在一对方括号中使用了扩展运算符:
var arr = ['a', 'b', 'c'];
var arr2 = [...arr];
console.log(arr2);
点击运行,您将看到预期的输出:
['a', 'b', 'c']
上面,arr 中的数组值扩展为单独的元素,然后分配给 arr2。我们现在可以随意更改 arr2 数组,而不会对原始 arr 数组产生任何影响:
var arr = ['a', 'b', 'c'];
var arr2 = [...arr];
arr2.push('d');
console.log(arr);
同样,它起作用的原因是 arr 的值被扩展以填充我们的 arr2 数组定义的括号。因此,我们将 arr2 设置为等于 arr 的各个值,而不是像我们在第一个示例中所做的那样对 arr 的引用。
最后一个有趣的例子是,您可以使用扩展语法将字符串转换为数组。只需在一对方括号内使用展开语法:
var str = "hello";
var chars = [...str];
console.log(chars);
它只是为您在JSX中以不同的方式定义道具!
它...
在 ES6 中使用数组和对象运算符(对象一尚未完全支持),所以基本上如果你已经定义了你的道具,你可以通过这种方式将它传递给你的元素。
所以在你的情况下,代码应该是这样的:
function yourA() {
const props = {name='Alireza', age='35'};
<Modal {...props} title='Modal heading' animation={false} />
}
所以你定义的道具现在分开了,可以在必要时重复使用。
它等于:
function yourA() {
<Modal name='Alireza' age='35' title='Modal heading' animation={false} />
}
这些是 React 团队关于 JSX 中传播运算符的引用:
JSX 传播属性 如果您提前知道要放置在组件上的所有属性,那么使用 JSX 很容易:
var component = <Component foo={x} bar={y} />;
修改 Props 是不好的
如果您不知道要设置哪些属性,您可能会想稍后将它们添加到对象中:
var component = <Component />;
component.props.foo = x; // bad
component.props.bar = y; // also bad
这是一种反模式,因为这意味着我们无法帮助您检查正确的 propTypes 直到很久以后。这意味着您的 propTypes 错误以神秘的堆栈跟踪结束。
道具应该被认为是不可变的。在其他地方改变 props 对象可能会导致意想不到的后果,因此理想情况下,此时它将是一个冻结的对象。
传播属性
现在您可以使用 JSX 的一个新特性,称为传播属性:
var props = {};
props.foo = x;
props.bar = y;
var component = <Component {...props} />;
你传入的对象的属性被复制到组件的 props 上。
您可以多次使用它或将其与其他属性结合使用。规范顺序很重要。后面的属性会覆盖前面的属性。
var props = { foo: 'default' };
var component = <Component {...props} foo={'override'} />;
console.log(component.props.foo); // 'override'
奇怪的...符号是怎么回事?
ES6 中的数组已经支持 ... 运算符(或扩展运算符)。还有一个关于 Object Rest 和 Spread 属性的 ECMAScript 提案。我们正在利用这些受支持和正在开发的标准,以便在 JSX 中提供更简洁的语法。
对于想要简单快速地理解这一点的人:
首先,这不仅仅是 React 的语法。这是来自 ES6 的语法,称为扩展语法,它迭代(合并、添加等)数组和对象。在此处阅读更多相关信息。
所以回答这个问题:
假设你有这个标签:
<UserTag name="Supun" age="66" gender="male" />
你这样做:
const user = {
"name"=>"Joe",
"age"=>"50"
"test"=>"test-val"
};
<UserTag name="Supun" gender="male" {...user} age="66" />
然后标签将等于:
<UserTag name="Joe" gender="male" test="test-val" age="66" />
因此,当您在 React 标签中使用扩展语法时,它会将标签的属性作为对象属性,与给定的对象合并(如果存在则替换)user
。此外,您可能已经注意到一件事,它只替换属性之前,而不是属性之后。所以在这个例子中,年龄保持不变。
它允许数组表达式或字符串或任何可以迭代的东西在需要零个或多个函数调用参数或数组元素的地方展开。
var arr1 = [1,2,3];
var arr2 = [4,5,6];
arr1 = [...arr1, ...arr2];
console.log(arr1); //[1, 2, 3, 4, 5, 6]
var arr = [1, 2, 3];
var arr2 = [...arr];
console.log(arr); //[1, 2, 3]
注意:Spread 语法在复制数组时有效地深入一层。因此,它可能不适合复制多维数组,如下例所示(与 Object.assign() 和扩展语法相同)。
var arr1 = [4, 5]
var arr2 = [1, 2, 3, ...arr1, 6]
console.log(arr2); // [1, 2, 3, 4, 5, 6]
var dateFields = [1970, 0, 1]; // 1 Jan 1970
var d = new Date(...dateFields);
console.log(d);
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var clonedObj = { ...obj1 };
console.log(clonedObj); // {foo: "bar", x: 42}
var mergedObj = { ...obj1, ...obj2 };
console.log(mergedObj); // {foo: "baz", x: 42, y: 13}
请注意,foo
obj1 的属性已被 obj2foo
属性覆盖。
function sum(...theArgs) {
return theArgs.reduce((previous, current) => {
return previous + current;
});
}
console.log(sum(1, 2, 3)); //6
console.log(sum(1, 2, 3, 4)); //10
注意:扩展语法(除了扩展属性的情况)只能应用于可迭代对象:
所以下面会报错:
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
对于那些来自 Python 世界的人来说,JSX 传播属性相当于
解包参数列表(Python**
运算符)。
我知道这是一个 JSX 问题,但使用类比有时有助于加快速度。
( ...
spread operator) 在 React 中用于:
提供一种简洁的方式将 props 从父组件传递到子组件。例如,给定父组件中的这些道具,
this.props = {
username: "danM",
email: "dan@mail.com"
}
它们可以通过以下方式传递给孩子,
<ChildComponent {...this.props} />
这与此类似
<ChildComponent username={this.props.username} email={this.props.email} />
但更清洁。
它在 JavaScript 中称为传播语法。
它用于在 JavaScript 中解构数组或对象。
例子:
const objA = { a: 1, b: 2, c: 3 }
const objB = { ...objA, d: 1 }
/* Result of objB will be { a: 1, b: 2, c: 3, d: 1 } */
console.log(objB)
const objC = { ....objA, a: 3 }
/* result of objC will be { a: 3, b: 2, c: 3, d: 1 } */
console.log(objC)
您可以使用Object.assign()
JavaScript 中的函数执行相同的结果。
参考:传播语法
在 React 应用程序中传递 props 是一种常见的做法。在这样做时,我们能够将状态更改应用于子组件,无论它是纯的还是不纯的(无状态的或有状态的)。有时,在传递 props 时,最好的方法是传递单个属性或整个属性对象。由于 ES6 中对数组的支持,我们被赋予了“...”符号,因此我们现在能够实现将整个对象传递给子对象。
使用以下语法记录将道具传递给孩子的典型过程:
var component = <Component foo={x} bar={y} />;
当道具数量很少时使用它很好,但当道具数量变得太多时变得难以管理。当您不知道子组件中所需的属性时,此方法会出现问题,典型的 JavaScript 方法是简单地设置这些属性并稍后绑定到对象。这会导致 propType 检查问题和神秘的堆栈跟踪错误,这些错误无用并导致调试延迟。以下是这种做法的一个例子,以及不应该做的事情:
var component = <Component />;
component.props.foo = x; // bad
component.props.bar = y;
可以实现相同的结果,但通过这样做可以获得更适当的成功:
var props = {};
props.foo = x;
props.bar = y;
var component = Component(props); // Where did my JSX go?
但不使用 JSX spread 或 JSX,因此将其循环回方程,我们现在可以执行以下操作:
var props = {};
props.foo = x;
props.bar = y;
var component = <Component {...props} />;
"...props" 中包含的属性是 foo: x, bar: y。这可以与其他属性结合使用以下语法来覆盖“...props”的属性:
var props = { foo: 'default' };
var component = <Component {...props} foo={'override'} />;
console.log(component.props.foo); // 'override'
此外,我们可以将其他属性对象相互复制或以这种方式组合它们:
var oldObj = { foo: 'hello', bar: 'world' };
var newObj = { ...oldObj, foo: 'hi' };
console.log(newObj.foo); // 'hi';
console.log(newObj.bar); // 'world';
或者像这样合并两个不同的对象(这在所有 React 版本中尚不可用):
var ab = { ...a, ...b }; // merge(a, b)
根据 Facebook 的 react/docs 网站,另一种解释方式是:
如果您已经将“props”作为对象,并且想在 JSX 中传递它,则可以使用“...”作为 SPREAD 运算符来传递整个 props 对象。下面两个例子是等价的:
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
当您构建通用容器时,展开属性会很有用。但是,它们也可以通过轻松将许多不相关的道具传递给不关心它们的组件来使您的代码变得混乱。应谨慎使用此语法。
ECMAScript 6 (ES6) 中引入的扩展运算符(三元运算符)。ECMAScript (ES6) 是 JavaScript 的包装器。
props 中的扩展运算符可枚举属性。
this.props = { firstName: 'Dan', lastName: 'Abramov', city: 'New York', country: 'USA' } <Modal {...this.props} title='Modal heading' animation={false }>
{...this.props} = { firstName:'Dan',lastName:'Abramov',城市:'New York',国家:'USA' }
但主要特征扩展运算符用于引用类型。
例如,
let person= {
name: 'Alex',
age: 35
}
person1 = person;
person1.name = "Raheel";
console.log( person.name); // Output: Raheel
这称为引用类型。一个对象会影响其他对象,因为它们在内存中是可共享的。如果您独立获取一个值,则意味着扩展内存并且都使用扩展运算符。
let person= {
name: 'Alex',
age: 35
}
person2 = {...person};
person2.name = "Shahzad";
console.log(person.name); // Output: Alex
这些被称为spread 属性,在 ES2018 中添加,后来在 JSX 和 ReactJs 中添加。此运算符意味着详细说明或扩展变量中包含的所有属性,此处为({...this.props})
。
例如:
var person={ 姓名:“绿巨人”,年龄:22 };
<Modal {...this.person} title='Modal heading' animation={false} />
将与
<Modal name={person.name} age={person.age} title='Modal heading' animation={false} />
Spread 运算符允许您将对象、字符串或数组之类的可迭代对象扩展为其元素,而 Rest 运算符通过将一组元素缩减为一个数组来执行相反的操作。
扩展语法允许像数组和对象这样的数据结构对它们进行解构,以便从中提取值或向它们添加值。例如
const obj={name:"ram",age:10} const {name}=obj
,从上面的示例中,我们可以说我们解构了 obj 并从该对象中提取了名称。同样,
const newObj={...obj,address:"Nepal"}
在此示例中,我们向该对象添加了一个新属性。这在数组的情况下也是类似的。
这些被称为点差。顾名思义,这意味着它将它的任何值放入那些数组或对象中。
如:
let a = [1, 2, 3];
let b = [...a, 4, 5, 6];
console.log(b);
> [1, 2, 3, 4, 5, 6]