美文网首页
数组与对象的赋值问题

数组与对象的赋值问题

作者: 2359634711 | 来源:发表于2019-07-10 14:03 被阅读0次

0x01导言

React的学习中,官方文档 性能优化章节中提到了一个例子产生了一些疑惑,遂刨根问底查看了相关资料来帮助理解。

0x02原文

class ListOfWords extends React.PureComponent {
  render() {
    return <div>{this.props.words.join(',')}</div>;
  }
}

class WordAdder extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      words: ['marklar']
    };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    // 这部分代码很糟,而且还有 bug
    const words = this.state.words;
    words.push('marklar');
    this.setState({words: words});
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick} />
        <ListOfWords words={this.state.words} />
      </div>
    );
  }
}

这是一段bug代码,并不能达到修改state并进行render显示的效果。
下面对代码进行稍微修改,对handleClick函数进行修改:

handleClick() {
  this.setState(state => ({
    words: state.words.concat(['marklar'])
  }));
}

便可以进行对正常的state修改,从而调起render函数进行页面渲染。

0x03 原理分析

官方解释如下:

问题在于 PureComponent 仅仅会对新老 this.props.words 的值进行简单的对比。由于代码中 WordAdderhandleClick 方法改变了同一个 words 数组,使得新老 this.props.words 比较的其实还是同一个数组。即便实际上数组中的单词已经变了,但是比较结果是相同的。可以看到,即便多了新的单词需要被渲染, ListOfWords 却并没有被更新。

简单来说就是虽然进行了setState,但是同时改变了旧的state使得在setState时,新老state相同,导致不进行render的调用,页面也没有渲染。

JavaScript中的数组和对象

JavaScript教程-高级-内存管理中有这样一个例子:

var o = { 
  a: {
    b:2
  }
}; 
// 两个对象被创建,一个作为另一个的属性被引用,另一个被分配给变量o
// 很显然,没有一个可以被垃圾收集


var o2 = o; // o2变量是第二个对“这个对象”的引用
/** 笔者注:试想此时o2与o的关系 (o2是o的引用 并非创建新的内存并赋值) */
o = 1;      // 现在,“这个对象”的原始引用o被o2替换了

var oa = o2.a; // 引用“这个对象”的a属性
// 现在,“这个对象”有两个引用了,一个是o2,一个是oa
/** 笔者注:试想此时oa与o2.a的关系 (oa是o2.a的引用 并非创建新的内存并赋值) */
o2 = "yo"; // 最初的对象现在已经是零引用了
           // 他可以被垃圾回收了
           // 然而它的属性a的对象还在被oa引用,所以还不能回收

oa = null; // a属性的那个对象现在也是零引用了
           // 它可以被垃圾回收了

在这个例子中,需要注意的是引用和赋值的区别,在JavaScript中var newArr=oldArr表示的并不是创建新的数组并进行赋值,而是创建newArroldArr的一个新的引用,这种特性被称为浅拷贝
试想下面的例子:

var arr = [1,2,3];
var arr2 = arr;
arr2.push(4);
//此时arr是多少?

由于此时arr2arr的一个引用,改变arr2就会相应的改变arr,所以此时arr[1,2,3,4]

0x04解决方案

浅拷贝vs深拷贝

站在巨人的肩膀-参考文章:关于JavaScript的浅拷贝和深拷贝

修改方案

1、 如官方文档例子中使用concat

handleClick() {
  this.setState(state => ({
    words: state.words.concat(['marklar'])
  }));
}

2、 使用JSON转JSON字符串的方式

  handleClick() {
    // 使用转JSON字符串的方式
    let words = JSON.stringify(this.state.words);
    words = JSON.parse(words)
    words.push('asdw')
    this.setState({ words });
  }

3、使用Object.creat函数

  handleClick() {
    // 使用Object.creat的方式
    let words = Object.create(this.state.words);
    words.push('asdw')
    this.setState({ words });
  }

...更多方式

相关文章

  • 数组与对象的赋值问题

    0x01导言 在React的学习中,官方文档 性能优化章节中提到了一个例子产生了一些疑惑,遂刨根问底查看了相关资料...

  • JS数组与对象赋值问题

    最近有群友遇到一个问题 就是给数组赋值遇到的一些问题 正好自己也不了解 就去网上查了一些资料 在这里做一下总结 问...

  • 解构赋值

    解构赋值 数组的解构赋值 嵌套,默认值,展开符 对象的解构赋值 对象解构赋值的本质与简写 对象解构的模式与变量 对...

  • ECMAScript6 -- 解构赋值

    解构赋值 数组的解构赋值 对象的解构赋值 特殊: 数组的解构赋值 如果右边不是数组,默认转换为类数组 对象的解构赋...

  • 第三节:变量的解构赋值

    1、数组的解构赋值 2、对象的解构赋值 注意:对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取...

  • 字符串、解构赋值

    字符串 解构赋值 数组的结构赋值 对象的解构赋值 伪数组变真数组方法

  • ES6解构赋值

    解构赋值 按照一定的模式,从数组或对象中把数据拿出来,对变量进行赋值 一、数组解构赋值 等号左边与右边必须都是数组...

  • ES6常用新特性3--解构赋值

    对象的解构赋值 数组的解构赋值

  • [解构赋值-02] 对象的解构赋值

    对象的结构赋值与数组的结构赋值相似,等号左右两边都为对象结构 const {a,b} = {a:1,b:2}, ...

  • 解构赋值和扩展运算符

    解构赋值 数组的解构赋值 如果解构不成功,变量的值就等于undefined。默认值 对象 对象的解构与数组有一个重...

网友评论

      本文标题:数组与对象的赋值问题

      本文链接:https://www.haomeiwen.com/subject/zshckctx.html