React中的这三个点在做什么?

...在这个React(使用JSX)代码中做了什么,它叫什么?

<Modal {...this.props} title='Modal heading' animation={false}>
579865 次浏览

这是属性扩散符号。它是在ES2018中添加的(数组/迭代的扩展更早,ES2015),但它在React项目中通过转译得到了很长时间的支持(作为“JSX扩展属性”,即使你也可以在其他地方这样做,不仅仅是属性)。

{...this.props}扩散props中的“自己的”可枚举属性作为您正在创建的Modal元素上的离散属性。例如,如果this.props包含a: 1b: 2,那么

<Modal {...this.props} title='Modal heading' animation={false}>

将与

<Modal a={this.props.a} b={this.props.b} title='Modal heading' animation={false}>

但它是动态的,所以props中包含的任何“自己的”属性。

由于childrenprops中是“自己的”属性,因此传播将包含它。因此,如果出现这一点的组件有子元素,它们将被传递给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;}

JavaScript中的三个点是扩散/休息操作符

扩散操作符

扩展语法允许在需要多个参数的地方扩展表达式。

myFunction(...iterableObj);
[...iterableObj, 4, 5, 6]
[...Array(10)]

休息参数

休息参数语法用于具有可变数量参数的函数。

function(a, b, ...theArgs) {// ...}

数组的传播/休息运算符是在ES6中引入的。对象传播/休息属性有一个状态2提案

TypeScript还支持扩展语法,并可以将其转换为带有次要问题的旧版本ECMAScript。

三个点(...)称为扩展运算符,这在概念上类似于ES6数组扩展运算符JSX利用这些支持和开发的标准,以便在JSX中提供更清晰的语法

对象初始化器中的传播属性复制自己的枚举属性从提供的对象到新创建的对象。

let n = { x, y, ...z };n; // { x: 1, y: 2, a: 3, b: 4 }

参考文献:

  1. 传播属性

  2. JSX在深度

...被称为传播属性,正如名称所代表的,它允许扩展表达式。

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的一个特性,也在React中使用。请看下面的示例:

function Sum(x, y, z) {return x + y + z;}console.log(Sum(1, 2, 3)); // 6

如果我们最多有三个参数,这种方式很好。但是,如果我们需要添加,例如,110个参数。我们是否应该定义它们并一个接一个地添加它们?

当然还有一个更简单的方法,叫做传播。而不是传递你写的所有这些参数:

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

对于那些来自Python世界的人来说,JSX传播属性相当于解压缩参数列表(Python**运算符)。

我知道这是一个JSX问题,但使用类比有时有助于更快地解决问题。

它只是在JSX中以不同的方式为您定义道具

它在ES6中使用...数组和对象运算符(对象1尚未完全支持),所以基本上如果你已经定义了你的道具,你可以通过这种方式将它传递给你的元素。

所以在你的情况下,代码应该是这样的:

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} />;

变异道具不好
如果你不知道要设置哪些属性,你可能会想稍后将它们添加到对象中:

var component = <Component />;component.props.foo = x; // badcomponent.props.bar = y; // also bad

这是一个反模式,因为这意味着我们无法帮助您检查直到很久以后。这意味着你的命题类型错误以一个神秘的堆栈跟踪结束。

道具应该被认为是不可变的。修改props对象其他地方可能会导致意想不到的后果所以理想情况下在这一点上是一个冻结的对象。

传播属性
现在你可以使用JSX的一个新特性,称为传播属性:

var props = {};props.foo = x;props.bar = y;var component = <Component {...props} />;

您传入的对象的属性将复制到组件的道具。

您可以多次使用此属性或将其与其他属性组合使用。规范顺序很重要。后面的属性覆盖上一篇:

var props = { foo: 'default' };var component = <Component {...props} foo={'override'} />;console.log(component.props.foo); // 'override'

这奇怪的…符号是怎么回事?
ES6中的数组已经支持…运算符(或扩展运算符)。还有对象休息和传播属性的ECMAScript提案。我们利用这些支持和开发的标准,以便在JSX中提供更清晰的语法。

这些被称为点差。顾名思义,它意味着它将其值放入这些数组或对象中。

例如:

let a = [1, 2, 3];let b = [...a, 4, 5, 6];console.log(b);> [1, 2, 3, 4, 5, 6]

...(传播运算符)在React to中使用:

提供一种巧妙的方式将道具从父组件传递给子组件。例如,给定父组件中的这些道具,

this.props = {username: "danM",email: "dan@mail.com"}

它们可以通过以下方式传递给孩子,

<ChildComponent {...this.props} />

和这个类似

<ChildComponent username={this.props.username} email={this.props.email} />

但更干净。

这三个点代表ES6中的点差算子。它允许我们在JavaScript中做很多事情:

  1. 连接数组

     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']
  2. 破坏数组

       var shooterGames = ['Call of Duty', 'Far Cry', 'Resident Evil'];var [first, ...remaining] = shooterGames;console.log(first); //Call of Dutyconsole.log(remaining); //['Far Cry', 'Resident Evil']
  3. 组合两个对象

     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'}

三个点还有另一个用途,称为休息参数,它可以将所有参数作为一个数组获取到一个函数中。

  1. 数组形式的函数参数

      function fun1(...params) {
    }

它在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)

您可以使用JavaScript中的Object.assign()函数执行相同的结果。

参考:传播语法

在React应用程序中传递props是常见的做法。通过这样做,我们能够对子组件应用状态更改,而不管它是Pure还是Im纯(无状态或有状态)。有时,传入props时,最好的方法是传入奇异属性或整个属性对象。随着ES6对数组的支持,我们被赋予了“…”符号,有了这个,我们现在能够实现将整个对象传递给子对象。

将props传递给子级的典型过程是这样的语法:

var component = <Component foo={x} bar={y} />;

当道具数量很少时,这可以很好地使用,但当道具数量过高时变得无法管理。当您不知道子组件中需要的属性并且典型的JavaScript方法是简单设置这些属性并稍后绑定到对象时,此方法会出现问题。这会导致PropType检查和神秘的堆栈跟踪错误,这些错误没有帮助并导致调试延迟。以下是这种做法的一个示例,以及不要做的事情:

var component = <Component />;component.props.foo = x; // badcomponent.props.bar = y;

同样的结果可以实现,但通过这样做可以获得更适当的成功:

var props = {};props.foo = x;props.bar = y;var component = Component(props); // Where did my JSX go?

但不使用JSX传播或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';

或者像这样合并两个不同的对象(这在所有反应版本中都不可用):

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} />;}

当你构建泛型容器时,传播属性很有用。但是,它们也会让你的代码变得混乱,因为它很容易将许多不相关的道具传递给不关心它们的组件。应该谨慎使用这种语法。

三个点...代表点差运算符其余参数

它允许数组表达式或字符串或任何可以是迭代的东西在需要零个或多个函数调用参数或数组元素的地方进行扩展。

  • 合并两个数组

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]

注意:传播语法在复制数组。因此,它可能不适合复制多维如以下示例所示的数组(与Object.assign()和扩展语法)。

  • 在特定索引处将一个数组的值添加到另一个数组,例如3:

var arr1 = [4, 5]var arr2 = [1, 2, 3, ...arr1, 6]console.log(arr2);    // [1, 2, 3, 4, 5, 6]

  • 使用new调用构造函数时:

var dateFields = [1970, 0, 1];  // 1 Jan 1970var 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}

请注意,对象1的foo属性已被对象2的foo属性覆盖。

  • 作为rest参数语法,它允许我们将不确定数量的参数表示为数组:

function sum(...theArgs) {return theArgs.reduce((previous, current) => {return previous + current;});}
console.log(sum(1, 2, 3));    //6console.log(sum(1, 2, 3, 4));    //10

注意:扩展语法(除了扩展属性的情况)只能应用于可迭代对象:

所以下面会抛出一个错误:

var obj = {'key1': 'value1'};var array = [...obj]; // TypeError: obj is not iterable

参考文献1

参考文献2

ECMAScript 6(ES6)中引入的扩展运算符(三重运算符)。ECMAScript(ES6)是JavaScript的包装器。

传播运算符可枚举道具中的属性。

this.props={名字:'Dan',姓氏:'Abramov',城市:“纽约”国家:“美国”}<模态{…this.props}title='模态标题'动画={false}>

this.props}={第一个名字:'丹',姓氏:'Abramov',城市:“纽约”国家:“美国”}

但主要特征扩展运算符用于引用类型。

例如,

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

向布兰登·莫雷利致敬。他完美地解释了这里,但链接可能会死亡,所以我只是粘贴下面的内容:

扩展语法只是三个点:...它允许可迭代对象在需要0+参数的地方扩展。没有上下文的定义很难。让我们探索一些不同的用例来帮助理解这意味着什么。

示例1-插入数组

看看下面的代码。在此代码中,我们不使用扩展语法:

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的数字数组,而不是嵌套数组。

示例2-数学

JavaScript有一个内置的数学对象,允许我们进行一些有趣的数学计算。在这个例子中,我们将看到Math.max()。如果你不熟悉,Math.max()返回零个或多个数字中的最大值。下面是一些例子:

Math.max();// -InfinityMath.max(1, 2, 3);// 3Math.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);

我们只需要两行代码,而不必创建一个函数并使用应用方法来返回Math.max()的结果!扩展语法扩展了我们的数组元素并将数组中的每个元素单独输入到Math.max()方法中!

示例3-复制数组

在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);

...(JavaScript中的三个点)称为传播语法或传播运算符。这允许扩展阵列表达式或字符串等可迭代对象,或在放置的任何位置扩展对象表达式。这不是React特有的。它是一个JavaScript运算符。

所有这些答案都很有帮助,但我想列出扩展语法(传播运算符)最常用的实际用例。

1.合并数组(连接数组)

有一个组合数组的各种方法,但扩展运算符允许您将其放置在数组中的任何位置。如果您想组合两个数组并将元素放置在数组中的任何点,您可以执行以下操作:

var arr1 = ['two', 'three'];var arr2 = ['one', ...arr1, 'four', 'five'];
// arr2 = ["one", "two", "three", "four", "five"]

2.复制数组

当我们想要数组的副本时,我们曾经使用#0方法。但是,您可以使用扩展运算符执行相同的操作。

var arr = [1,2,3];var arr2 = [...arr];// arr2 = [1,2,3]

3.在不应用的情况下调用函数

在ES5中,要将两个数字的数组传递给doStuff()函数,您通常使用#1方法,如下所示:

function doStuff (x, y, z) {}var args = [0, 1, 2];
// Call the function, passing argsdoStuff.apply(null, args);

但是,通过使用扩展运算符,您可以将数组传递给函数。

doStuff(...args);

4.破坏阵列

你可以一起使用解构和rest运算符来将信息提取到你想要的变量中:

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };console.log(x); // 1console.log(y); // 2console.log(z); // { a: 3, b: 4 }

5.函数参数作为休息参数

ES6还有三个点(...),表示将函数的所有剩余参数收集到数组中的rest参数。

function f(a, b, ...args) {console.log(args);}
f(1, 2, 3, 4, 5); // [3, 4, 5]

6.使用数学函数

任何使用传播作为参数的函数都可以由可以接受任意数量参数的函数使用。

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"]

您可以想出更多使用传播运算符的方法。我在这里列出的是它的流行用例。

对于那些想快速理解这个问题的人来说:

首先,这不仅仅是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合并(如果存在则替换)的对象属性。此外,您可能已经注意到一件事,它只替换属性之前,而不是属性之后。所以在这个例子中,age保持不变。

扩展运算符允许您将可迭代对象(如对象、字符串或数组)扩展为其元素,而Rest运算符则通过将一组元素缩减为一个数组来进行反向操作。

扩展语法允许像数组和对象这样的数据结构解构它们要么从中提取价值,要么为它们添加价值。例如const obj={name:"ram",age:10} const {name}=obj从上面的例子中,我们可以说我们解构了obj并从该对象中提取了名称。同样,const newObj={...obj,address:"Nepal"}在此示例中,我们向该对象添加了一个新属性。这与数组的情况类似。

传播运算符!由于大多数ppl已经优雅地回答了这个问题,我想建议一个使用传播运算符的快速列表:

...扩展运算符对于JavaScript中的许多不同的例程任务很有用,包括以下内容:

  • 复制数组
  • 连接或组合数组
  • 使用数学函数
  • 使用数组作为参数
  • 将项目添加到列表中
  • 在React中添加状态
  • 组合对象
  • 将NodeList转换为数组

查看文章了解更多详细信息。如何使用传播运算符。我建议您习惯它。您可以使用传播运算符有很多很酷的方法。

... 3点表示JS中的扩展运算符。

没有扩展操作员。

let a = ['one','one','two','two'];let unq = [new Set(a)];
console.log(a);console.log(unq);

输出:

(4) ['one', 'one', 'two', 'two'][Set(2)]

与传播运营商。

let a = ['one','one','two','two'];let unq = [...new Set(a)];
console.log(a);console.log(unq);

输出:

(4) ['one', 'one', 'two', 'two'](2) ['one', 'two']

那3个点...不是React术语。那些是JavaScript ES6扩展运算符。这有助于创建一个新数组,而不会干扰原始数组以执行深度复制。这也可用于对象。

const arr1 = [1, 2, 3, 4, 5]const arr2 = arr1 // [1, 2, 3, 4, 5]/*This is an example of a shallow copy.Where the value of arr1 is copied to arr2But now if you apply any method toarr2 will affect the arr1 also.*/
/*This is an example of a deep copy.Here the values of arr1 get copied but theyboth are disconnected. Meaning if youapply any method to arr3 it will notaffect the arr1.*/const arr3 = [...arr1] // [1, 2, 3, 4, 5]