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

What are these three dots in React doing?

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

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

那是 property spread notation. It was added in ES2018 (spread for arrays/iterables was earlier, ES2015), but it's been supported in React projects for a long time via transpilation (as "JSX spread attributes”,尽管您也可以在别处这样做,而不仅仅是属性)。

{...this.props} 展开 props 中的 "own" 可枚举属性作为 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 中的任何 "own" 属性都包含在内。

由于 childrenprops 中的 "own" 属性,传播将包括它。因此,如果它出现的组件有子元素,它们将被传递给 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 中的三个点是 展开/休息运算符

展开运算符

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

myFunction(...iterableObj);

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

[...Array(10)]

其余参数

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

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

ES6. There's a State 2 proposal 中引入了数组的展开/剩余运算符,用于对象展开/剩余属性。

TypeScript 还支持传播语法,并且可以将其转换为具有次要 issues.

的旧版本 ECMAScript

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

Spread properties in object initializers copies own enumerable properties from a provided object onto the newly created object.

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

参考文献:

  1. Spread Properties

  2. JSX In Depth

... 称为 展开属性,顾名思义,它允许展开表达式。

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

简而言之,这是一个整洁 short-cut,我们可以说

这是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 Spread Attributes 相当于 Unpacking Argument Lists(Python **-运算符)。

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

只是在JSX中以不同的方式为您定义了props

它在 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 Spread Attributes If you know all the properties that you want to place on a component ahead of time, it is easy to use JSX:

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

Mutating Props is Bad
If you don't know which properties you want to set, you might be tempted to add them onto the object later:

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

This is an anti-pattern because it means that we can't help you check the right propTypes until way later. This means that your propTypes errors end up with a cryptic stack trace.

The props should be considered immutable. Mutating the props object somewhere else could cause unexpected consequences so ideally it would be a frozen object at this point.

Spread Attributes
Now you can use a new feature of JSX called spread attributes:

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

The properties of the object that you pass in are copied onto the component's props.

You can use this multiple times or combine it with other attributes. The specification order is important. Later attributes override previous ones.

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

What's with the weird ... notation?
The ... operator (or spread operator) is already supported for arrays in ES6. There is also an ECMAScript proposal for Object Rest and Spread Properties. We're taking advantage of these supported and developing standards in order to provide a cleaner syntax in JSX.

这些被称为点差。顾名思义,就是把它的值放到那些数组或对象中。

如:

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

...(扩展运算符)在 React 中用于:

提供一种将 props 从 parent 传递到 child 组件的巧妙方法。例如,在 parent 组件中给出这些道具,

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

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

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

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

  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() 函数获得相同的结果。

参考:传播syntax

在 React 应用程序中传递 props 是常见的做法。在这样做时,我们能够将状态更改应用于 child 组件,而不管它是 Pure 还是 Impure(无状态或有状态)。有时,在传递 props 时,最好的方法是传递单个属性或整个 object 属性。通过 ES6 中对数组的支持,我们获得了“...”符号,现在我们能够实现将整个 object 传递给 child。

将 props 传递给 child 的典型过程用以下语法记录:

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

当道具数量很少时使用它很好,但当道具数量太多时变得难以管理。当您不知道 child 组件中所需的属性时,此方法会出现问题,而典型的 JavaScript 方法是简单地设置这些属性并稍后绑定到 object。这会导致 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'

此外,我们可以将其他 属性 object 相互复制或以这种方式组合它们:

var oldObj = { foo: 'hello', bar: 'world' };
var newObj = { ...oldObj, foo: 'hi' };
console.log(newObj.foo); // 'hi';
console.log(newObj.bar); // 'world';

或者像这样合并两个不同的object(这在所有的react版本中还不可用):

var ab = { ...a, ...b }; // merge(a, b)

根据 Facebook 的 react/docs 网站,另一种解释方式是:

如果你已经有 "props" 作为 object,并且你想在 JSX 中传递它,你可以使用“...”作为 SPREAD 运算符来传递整个属性 object。下面两个例子是等价的:

function App1() {
  return <Greeting firstName="Ben" lastName="Hector" />;
}



function App2() {
  const props = {firstName: 'Ben', lastName: 'Hector'};
  return <Greeting {...props} />;
}

Spread 属性在构建通用容器时很有用。但是,它们也可以让您轻松地将大量不相关的属性传递给不关心它们的组件,从而使您的代码变得混乱。应谨慎使用此语法。

三点...代表spread operators or rest parameters.

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

  • 合并两个数组

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]

Note: Spread syntax effectively goes one level deep while copying an array. Therefore, it may be unsuitable for copying multidimensional arrays as the following example shows (it's the same with Object.assign() and spread syntax).

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

注意obj1的foo属性已经被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

Reference1

Reference2

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

的包装器

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

this.props = { 名字:'Dan', 姓氏:'Abramov', 城市:'New York', 国家:'USA' } <模态{...this.props} title='Modal heading' animation={false}>

{...this.props} = { firstName: 'Dan', lastName: 'Abramov', city: 'New York', country: '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

感谢 Brandon Morelli。 他解释得很完美 here,但是链接可能会失效所以我只粘贴下面的内容:

传播语法只是三个点:... 它允许迭代器在需要 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() return 是零个或多个数字中最大的一个。这里有几个例子:

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 方法用于 return 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 中的三个点)称为展开语法或展开运算符。这允许扩展诸如 array 表达式或 stringobject 表达式的可迭代对象随处展开。这不是 React 特有的。它是一个 JavaScript 运算符。

这里的所有这些答案都很有帮助,但我想列出 Spread Syntax(展开运算符)最常用的实际用例。

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

有一个 variety of ways to combine arrays,但展开运算符允许您将其放置在数组中的任何位置。如果你想合并两个数组并将元素放在数组中的任意点,你可以这样做:

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

// arr2 = ["one", "two", "three", "four", "five"]

2。复制数组

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

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

3。不应用调用函数

在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使用方法。我在这里列出的是它的流行用例。

对于想要理解这个简单快速的人:

首先,这不仅仅是 React 的语法。这是来自 ES6 的语法,称为 spread syntax which iterate (merge, add, etc.) the array and object. Read more about it here.

所以回答问题:

假设您有这个标签:

<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。此外,您可能已经注意到一件事,它只替换属性之前,而不是属性之后。所以在这个例子中,年龄保持不变。

Spread 运算符可让您将可迭代对象(如对象、字符串或数组)扩展到其元素中,而 Rest 运算符通过将一组元素缩减为一个数组来执行相反的操作。

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

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

…展开运算符可用于 JavaScript 中的许多不同的常规任务,包括以下内容:

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

查看文章了解更多详情。 How to use the Spread Operator. 我建议习惯它。您可以通过多种很酷的方式使用展开运算符。

... 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']