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

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

答案

那是财产传播符号 。它是在 ES2018 中添加的(用于数组 / 可迭代对象的版本更早于 ES2015),但是随着时间的流逝,它通过转译得到了支持(作为 “ 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;
}

如您所知...被称为 “ 扩展属性” ,其名称代表该名称,它可以扩展表达式。

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 做很多事情:

  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 Duty
      console.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'}

这三个点还有另一种用途,称为Rest 参数 ,它可以将函数的所有参数作为一个数组使用。

  1. 函数参数作为数组

    function fun1(...params) { 
    
     }

JavaScript 中的三个点是传播 / 休息运算符

点差运算符

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

myFunction(...iterableObj);

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

[...Array(10)]

休息参数

rest参数语法用于参数数目可变的函数。

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

ES6 中引入了数组的散布 / 余数运算符。对于对象散布 / 静止属性,有一个状态 2 建议

TypeScript 还支持传播语法,并且可以将其转换为较小问题的 ECMAScript 的较早版本。

这也是 React 中使用的 es6 的功能。看下面的例子:

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

如果我们最多拥有 3 个参数,那么这种方法很好,但是如果我们需要添加例如 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

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

它在 ES6 中使用...数组和对象运算符(尚不完全支持一个对象),因此,基本上,如果您已经定义了 props,则可以将其传递给元素。

因此,在您的情况下,代码应如下所示:

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; // bad
component.props.bar = y; // also bad

这是一种反模式,因为这意味着我们要等到以后才能帮助您检查正确的 propTypes。这意味着您的 propTypes 错误最终会导致隐秘的堆栈跟踪。

道具应该被认为是不变的。将 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 中提供更简洁的语法。

对于那些来自 Python 世界的人来说,JSX Spread 属性等同于Unpacking Argument Lists (Python ** -operator)。

我知道这是一个 JSX 问题,但是使用类比有时可以帮助使其更快。

... (扩展运算符)用于对以下内容做出反应:

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

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

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

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

与此类似

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

但是更干净。

三个点...表示扩展运算符剩余参数

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

  • 合并两个数组

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()和 spread 语法相同)。

  • 将一个数组的值添加到特定索引处的另一个数组,例如 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 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 的财产已经 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

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

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

参考 1

参考 2

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

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

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

参考:

1) https://github.com/sebmarkbage/ecmascript-rest-spread#spread-properties

2) https://facebook.github.io/react/docs/jsx-spread.html