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

Tho*_*sen 762 javascript reactjs

什么是...做这个阵营(使用JSX)代码,什么是它叫什么名字?

<Modal {...this.props} title='Modal heading' animation={false}>
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 911

这是财产传播符号.它是在ES2018中添加的,但是通过转换在React项目中得到了长期支持(即使你可以在其他地方使用"JSX传播属性",而不仅仅是属性).

{...this.props} 展开的"自己"性质props上是离散性Modal要创建元素.举例来说,如果this.propsa: 1b: 2,然后

<Modal {...this.props} title='Modal heading' animation={false}>
Run Code Online (Sandbox Code Playgroud)

会是一样的

<Modal a={this.props.a} b={this.props.b} title='Modal heading' animation={false}>
Run Code Online (Sandbox Code Playgroud)

但它是动态的,所以props包含了"自己的"属性.

由于children是"自有"财产props,传播将包括它.因此,如果出现的组件具有子元素,则它们将被传递给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")
);
Run Code Online (Sandbox Code Playgroud)
.first {
  color: green;
}
.second {
  color: blue;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

扩展符号不仅适用于该用例,而且适用于创建具有现有对象的大部分(或全部)属性的新对象 - 当您更新状态时会出现很多,因为您无法修改状态直:

this.setState(prevState => {
    return {foo: {...prevState.foo, a: "updated"}};
});
Run Code Online (Sandbox Code Playgroud)

这将取代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);
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper {
  max-height: 100% !important;
}
Run Code Online (Sandbox Code Playgroud)

  • 在开始和结束标记之间放置子元素是否会覆盖“children”属性,或者将它们组合起来? (2认同)
  • @anddero-这是一个非常有趣的问题。据我所知,它是[children]的[文档](https://reactjs.org/docs/jsx-in-depth.html#children-in-jsx)并未涵盖的内容。实验告诉我,您通过称为“ children”的属性提供的孩子被您在开始标签和结束标签之间指定的孩子所取代,但是如果这是未定义的行为,我一定不要依赖它。 (2认同)

Meh*_*ash 291

正如你所知道 ...被称为传播的属性,其名称代表,它允许一个表达式来进行扩展.

var parts = ['two', 'three'];
var numbers = ['one', ...parts, 'four', 'five']; // ["one", "two", "three", "four", "five"]
Run Code Online (Sandbox Code Playgroud)

在这种情况下(我会简化它).

//just assume we have an object like this:
var person= {
    name: 'Alex',
    age: 35 
}
Run Code Online (Sandbox Code Playgroud)

这个:

<Modal {...person} title='Modal heading' animation={false} />
Run Code Online (Sandbox Code Playgroud)

等于

<Modal name={person.name} age={person.age} title='Modal heading' animation={false} />
Run Code Online (Sandbox Code Playgroud)

简而言之,我们可以说,这是一个简洁的捷径.

  • 很好的答案,非常清晰和简洁! (4认同)
  • 简单明了。 (2认同)

the*_*pan 93

这三个点代表ES6中的Spread Operator.它允许我们在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']
    
    Run Code Online (Sandbox Code Playgroud)
  2. 解构数组

      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']
    
    Run Code Online (Sandbox Code Playgroud)
  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'}
    
    Run Code Online (Sandbox Code Playgroud)

以上称为rest参数,不限制传递给函数的值的数量.但是,参数必须是相同的类型.

  1. 梳理两个物体

     function fun1(...params) { 
    
     }  
    
    Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的答案,因为每个用例的所有明确的例子.感谢您抽出宝贵时间写下这些内容. (19认同)
  • 不仅是最好的答案,也是最有趣的答案,“Selana Marie 你的初恋:D” (3认同)
  • 3.5. 解构一个对象 (3认同)
  • 为了更清晰,在示例之前提及休息参数 (2认同)
  • 这是一个很棒的答案,作为一名 Python 开发人员,我可以将展开运算符转换为使用 * 或 ** 符号的打包/解包,基本上做同样的事情。 (2认同)

Tom*_*dym 48

JavaScript中的三个点是spread/rest运算符.

传播运营商

价差语法允许表达在多个参数预期的地方进行扩展.

myFunction(...iterableObj);

[...iterableObj, 4, 5, 6]

[...Array(10)]
Run Code Online (Sandbox Code Playgroud)

休息参数

其余参数语法用于与可变参数数目的功能.

function(a, b, ...theArgs) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

在ES6中引入了数组的扩展/休息运算符.对象传播/休息属性有一个State 2 提案.

TypeScript还支持传播语法,并且可以将其转换为较旧版本的ECMAScript,但存在小问题.


Neg*_*gin 29

这是es6的一个特性,也用在React中.看下面的例子:

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

如果我们有最多3个参数,这种方式很好,但如果我们需要添加110个参数,那该怎么办呢.我们应该将它们全部定义并逐个添加吗?!当然,有一种更简单的方法,称为SPREAD.而不是传递你写的所有这些参数:

function (...numbers){} 
Run Code Online (Sandbox Code Playgroud)

我们不知道我们有多少参数,但我们知道有很多参数.基于es6,我们可以重写上面的函数,并使用它们之间的扩展和映射,使它像一块蛋糕一样简单:

let Sum = (...numbers) => {
return numbers.reduce((prev, current) => prev + current );
}
console.log(Sum(1, 2, 3, 4, 5, 6, 7, 8, 9));//45
Run Code Online (Sandbox Code Playgroud)


Kee*_*asa 29

...(JavaScript 中的三个点)称为扩展语法或扩展运算符。这允许扩展诸如数组表达式或字符串之类的可迭代对象,或者扩展放置在任何位置的对象表达式。这不是 React 特有的。它是一个 JavaScript 运算符。

这里的所有这些答案都有帮助,但我想列出传播语法(Spread Operator)的最常用的实际用例。

1.组合数组(Concatenate Arrays)

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

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

// arr2 = ["one", "two", "three", "four", "five"]
Run Code Online (Sandbox Code Playgroud)

2. 复制数组

当我们想要一个数组的副本时,我们曾经使用Array.prototypr.slice()方法。但是,您可以对扩展运算符执行相同操作。

var arr = [1,2,3];
var arr2 = [...arr];
// arr2 = [1,2,3]
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

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

doStuff(...args);
Run Code Online (Sandbox Code Playgroud)

4. 解构数组

您可以将解构和 rest 运算符一起使用,以根据需要将信息提取到变量中:

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 }
Run Code Online (Sandbox Code Playgroud)

5. 函数参数作为 Rest 参数

ES6 还具有三个点 (...),它是一个剩余参数,用于将函数的所有剩余参数收集到一个数组中。

function f(a, b, ...args) {
  console.log(args);
}

f(1,2,3,4,5);
// [ 3, 4, 5 ]
Run Code Online (Sandbox Code Playgroud)

6. 使用数学函数

任何将 spread 用作参数的函数都可以被可以接受任意数量参数的函数使用。

let numbers = [9, 4, 7, 1];
Math.min(...numbers); // 1
Run Code Online (Sandbox Code Playgroud)

7. 组合两个对象

您可以使用展开运算符来组合两个对象。这是一种简单而干净的方法。

var carType = {
  model: 'Toyota',
  yom: '1995'
};

var carFuel = 'Petrol';

var carData = {
  ...carType,
  carFuel
}

console.log(carData);
// {
//  model: 'Toyota',
//  yom: '1995',
//  carFuel = 'Petrol'
// }
Run Code Online (Sandbox Code Playgroud)

8. 将一个字符串分成不同的字符

您可以使用扩展运算符将字符串扩展为单独的字符。

let chars = ['A', ...'BC', 'D'];
console.log(chars); // ["A", "B", "C", "D"]
Run Code Online (Sandbox Code Playgroud)

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


cur*_*Boy 23

感谢布兰登·莫雷利。在这里解释得很好,但链接可能会死,所以我只是粘贴下面的内容:

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

示例 1 - 插入数组

看看下面的代码。在这段代码中,我们不使用传播语法:

var mid = [3, 4];
var arr = [1, 2, mid, 5, 6];

console.log(arr);
Run Code Online (Sandbox Code Playgroud)

上面,我们创建了一个名为mid. 然后我们创建包含我们的mid数组的第二个数组。最后,我们注销结果。您希望arr打印什么?单击上面的运行以查看会发生什么。这是输出:

[1, 2, [3, 4], 5, 6]
Run Code Online (Sandbox Code Playgroud)

这是你期望的结果吗?

通过将mid数组插入arr数组,我们最终得到了数组中的数组。如果这是目标就好了。但是如果您只想要一个值为 1 到 6 的数组呢?为此,我们可以使用传播语法!请记住,展开语法允许扩展数组的元素。

让我们看看下面的代码。一切都一样——除了我们现在使用扩展语法将mid数组插入到arr数组中:

当您点击运行按钮时,结果如下:

[1, 2, 3, 4, 5, 6]
Run Code Online (Sandbox Code Playgroud)

惊人的!

还记得你刚刚在上面读到的传播语法定义吗?这就是它发挥作用的地方。如您所见,当我们创建arr数组并在数组上使用扩展运算符时,mid数组不仅被插入,而且mid会扩展。这种扩展意味着mid数组中的每个元素都被插入到arr数组中。结果不是嵌套数组,而是一个从 1 到 6 的数字数组。

示例 2 - 数学

JavaScript 有一个内置的 math 对象,它允许我们进行一些有趣的数学计算。在此示例中,我们将查看Math.max(). 如果您不熟悉,则Math.max()返回零个或多个数字中最大的一个。这里有一些例子:

Math.max();
// -Infinity
Math.max(1, 2, 3);
// 3
Math.max(100, 3, 4);
// 100
Run Code Online (Sandbox Code Playgroud)

可以看到,如果Math.max()要求多个数的最大值,需要多个参数。不幸的是,您不能简单地使用单个数组作为输入。在展开语法之前,在Math.max()数组上使用的最简单方法是使用.apply().

var mid = [3, 4];
var arr = [1, 2, ...mid, 5, 6];

console.log(arr);
Run Code Online (Sandbox Code Playgroud)

它有效,只是真的很烦人。

现在看看我们如何使用传播语法做同样的事情:

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

示例 3 — 复制数组

在 JavaScript 中,你不能仅仅通过设置一个等于现有数组的新变量来复制数组。考虑以下代码示例:

Math.max();
// -Infinity
Math.max(1, 2, 3);
// 3
Math.max(100, 3, 4);
// 100
Run Code Online (Sandbox Code Playgroud)

当您按运行时,您将获得以下输出:

['a', 'b', 'c']
Run Code Online (Sandbox Code Playgroud)

现在,乍一看,它看起来有效——看起来我们已经将 arr 的值复制到了 arr2 中。但事实并非如此。你看,在 JavaScript 中处理对象(数组是一种对象)时,我们是通过引用而不是值来分配的。这意味着 arr2 已分配给与 arr 相同的引用。换句话说,我们对 arr2 所做的任何事情也会影响原始的 arr 数组(反之亦然)。看看下面:

var arr = [2, 4, 8, 6, 0];

function max(arr) {
  return Math.max.apply(null, arr);
}

console.log(max(arr));
Run Code Online (Sandbox Code Playgroud)

上面,我们已经将一个新元素 d 推入了 arr2。然而,当我们注销 arr 的值时,您会看到 d 值也被添加到该数组中:

['a', 'b', 'c', 'd']
Run Code Online (Sandbox Code Playgroud)

不过没必要害怕!我们可以使用扩展运算符!考虑下面的代码。这几乎和上面一样。相反,我们在一对方括号中使用了扩展运算符:

var arr = [2, 4, 8, 6, 0];
var max = Math.max(...arr);

console.log(max);
Run Code Online (Sandbox Code Playgroud)

点击运行,你会看到预期的输出:

['a', 'b', 'c']
Run Code Online (Sandbox Code Playgroud)

上面,arr 中的数组值扩展为单个元素,然后分配给 arr2。我们现在可以随意更改 arr2 数组,而不会对原始 arr 数组产生任何影响:

var arr = ['a', 'b', 'c'];
var arr2 = arr;

console.log(arr2);
Run Code Online (Sandbox Code Playgroud)

同样,这是因为 arr 的值被扩展以填充我们的 arr2 数组定义的括号。因此,我们将 arr2 设置为等于 arr 的各个值,而不是像我们在第一个示例中所做的那样引用 arr。

奖励示例——字符串到数组

作为最后一个有趣的例子,您可以使用扩展语法将字符串转换为数组。只需在一对方括号内使用扩展语法:


Ali*_*eza 15

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

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

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

function yourA() {
  const props = {name='Alireza', age='35'};
  <Modal {...props} title='Modal heading' animation={false} />
}
Run Code Online (Sandbox Code Playgroud)

所以你定义的道具现在已经分开,必要时可以重复使用.

它等于:

function yourA() {
  <Modal name='Alireza' age='35' title='Modal heading' animation={false} />
}
Run Code Online (Sandbox Code Playgroud)

以下是React团队关于JSX中传播运算符的引用:

JSX Spread属性如果您知道要提前放置在组件上的所有属性,那么使用JSX很容易:

var component = <Component foo={x} bar={y} />;
Run Code Online (Sandbox Code Playgroud)

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

var component = <Component />;
component.props.foo = x; // bad
component.props.bar = y; // also bad
Run Code Online (Sandbox Code Playgroud)

这是一种反模式,因为它意味着我们无法帮助您检查正确的propTypes,直到稍后.这意味着您的propTypes错误最终会出现神秘的堆栈跟踪.

道具应该被认为是不可变的.在其他地方改变道具对象可能会导致意想不到的后果,因此理想情况下,此时它将成为一个冻结的对象.

传播属性
现在您可以使用称为传播属性的JSX新功能:

var props = {};
    props.foo = x;
    props.bar = y;
    var component = <Component {...props} />;
Run Code Online (Sandbox Code Playgroud)

传入的对象的属性将复制到组件的props上.

您可以多次使用它或将其与其他属性组合使用.规范顺序很重要.后来的属性覆盖以前的属性

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

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

  • 你已经回答完了他的问题。 (2认同)

And*_*ras 13

对于那些来自Python世界的人来说,JSX Spread Attributes相当于 Unpacking Argument Lists(Python **-operator).

我知道这是一个JSX问题,但使用类比有时有助于加快速度.


Sup*_*eth 13

对于想要简单快速地理解这一点的人:

首先,这不仅仅是 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" />
Run Code Online (Sandbox Code Playgroud)

那么标签将等于:

<UserTag name="Joe" gender="male" test="test-val" age="66" />
Run Code Online (Sandbox Code Playgroud)

因此,当您在 React 标签中使用 spread 语法时,它将标签的属性作为对象属性,与给定的对象合并(如果存在则替换)user。此外,您可能已经注意到一件事,它只替换属性之前,而不是属性之后。所以在这个例子中,年龄保持不变。

  • @DonCheadle 不,因为我在年龄之前添加了“{...user}”,所以年龄标签不会替换 (4认同)

dan*_*ina 10

...(扩展操作符)用于在反应:

提供一种巧妙的方法将道具从父组件传递到子组件.例如,在父组件中给出这些道具,

this.props = {
  username: "danM",
  email: "dan@mail.com"
}
Run Code Online (Sandbox Code Playgroud)

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

<ChildComponent {...this.props} />
Run Code Online (Sandbox Code Playgroud)

这与此类似

<ChildComponent username={this.props.username} email={this.props.email} />
Run Code Online (Sandbox Code Playgroud)

但方式更清洁.


Cod*_*ode 7

三个点...代表Spread运算符Rest参数

它允许将数组表达式或字符串或任何可以迭代的内容扩展到期望零个或多个参数用于函数调用或数组元素的地方。

  • 合并两个数组

var arr1 = [1,2,3];
var arr2 = [4,5,6];

arr1 = [...arr1, ...arr2];
console.log(arr1);  //[1, 2, 3, 4, 5, 6]
Run Code Online (Sandbox Code Playgroud)

  • 复制数组:

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

console.log(arr); //[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

注意:传播语法在复制数组时有效地深入了一层。因此,可能不适合复制多维数组,如下面的示例所示(与Object.assign()和spread语法相同)。

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

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

  • 用new调用构造函数时:

var dateFields = [1970, 0, 1];  // 1 Jan 1970
var d = new Date(...dateFields);

console.log(d);
Run Code Online (Sandbox Code Playgroud)

  • 传播对象文字:

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}
Run Code Online (Sandbox Code Playgroud)

请注意,fooobj1属性已被obj2 foo属性覆盖

  • 作为剩余参数语法,它使我们可以将不确定数量的参数表示为数组:

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
Run Code Online (Sandbox Code Playgroud)

注意:传播语法(除了传播属性的情况除外)只能应用于可迭代对象: 因此,以下操作将引发错误

var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
Run Code Online (Sandbox Code Playgroud)

参考1

参考2


Ram*_*jan 6

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

对象初始值设定项中的传播属性将自己的可枚举属性从提供的对象复制到新创建的对象上。

let n = { x, y, ...z };
n; // { x: 1, y: 2, a: 3, b: 4 }
Run Code Online (Sandbox Code Playgroud)

参考:

  1. 传播属性

  2. JSX 深入

  • 这是 ECMAScript 中对象上的扩展运算符的建议。问题是关于 JSX 点差运算符。尽管它们的工作方式相同,但它们并不相同。 (3认同)