微信小程序-js数组的拷贝赋值复制,你真的懂?

记录日常的一个小bug,吃一堑长一智,今天要讲的就是 操作数组赋值指针指向问题。 

事情原尾是这样的,调用查询测评接口返回一个resultList接口,测评页展示遍历走resultList;但由于条件筛选框的诞生,要根据学生name 作为条件传参,就得单独一栏只下拉展示学生名称,于是乎调用学生列表接口获取studentList,既然studentList值只返回学生name,但实际情况,是不是得给studentList 第0位给新加一个元素进去,有一个能选 ‘全部’,即不按name作为条件筛选 ,这样才显示合理,对吧;如下图。

微信小程序-js数组的拷贝赋值复制,你真的懂?_第1张图片

先给你们看段代码,假如走如下逻辑,修改studentList2的值会不会同时改变studentList1的值???

 //获取学生列表
  getStudentList: function() {
    var that = this;
    var list = new Array();
    var teacherId = wx.getStorageSync('userId');
    wx.request({
      url: that.data.host + '/student/listByTeacherId?teacherId=' + teacherId,
      method: 'get',
      success: function(e) {
        list = e.data.result.list;
        var studentListAdd= list ;
        var stuObj = {
          nickName: '全部',
          userId: ''
        }
        studentListAdd.unshift(stuObj); // 筛选姓名列表 开头添加一个元素
        that.setData({
          studentList1: list,
          studentList2: studentListAdd,
        })
      }
    })
  },

 下面我再举个很简洁的栗子,注意看!

  var a = [1, 2, 3]; //数组
  var b = a;
  b.unshift('aaa'); //开头添加一个元素
  console.log("b=", b)
  console.log("a=", a) 

 结果很让人出乎意料,随着我给b数组新增一个元素,结果也改变了a数组的值,同时都在数组的第0位加上了‘ aaa’元素;

于是很纳闷,结果问题就出在值引用,因为JavaScript存储对象都是存地址的(在js里数组不是简单数据类型,而是对象),所以浅复制会导致 a 和 b 指向同一块内存地址;变量是值传递,而数组是引用传递;

微信小程序-js数组的拷贝赋值复制,你真的懂?_第2张图片

思路还是数组拷贝,但不能再是浅拷贝,那该如何深拷贝呢?请看下文

所以正确的做法应该是:

  1. 使用js的concat()
  2. 使用js的slice()

1、使用concat() 函数;

          原理:返回数组的一个副本(相当于另外开辟内存空间),所以并不会改变数组本身的的值;

    var a = [1, 2, 3]; //数组
    var b = [].concat(a)
    b.unshift('aaa'); //开头添加一个元素
    console.log("b=", b)
    console.log("a=", a) 

再看打印结果,你发现了什么,竟然成功了,是不是感到很意外,想知道为什么要利用一个空数组去 拼接a 数组呢?

 

 原因就是: 

concat()返回的不是调用函数的Array,而是一个新的Array,开辟了一个新内存地址,同时也把a数组的元素复制给了b数组,所以第一次var b = a; 其实只把引用地址交给了b.所以两个数组 共享同一个 [ 1,2,3 ]数组对象,而当修改了数组b的时候,那么他们共享的内容就发生了变化,导致数组a输出的时候也发生了变化,变成了【‘a’,1,2,3】;

这样就完成了数组的拷贝,而不再是引用;即便无论怎么改变拷贝后的数组b,也不会影响原来的数组a!

给大家画个图辅助性理解下:

微信小程序-js数组的拷贝赋值复制,你真的懂?_第3张图片


 2、使用js的slice() 函数 

原理:返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。

    var a = [1, 2, 3]; //数组
    var b = [];
    b=a.slice(0)//如果 end 未被规定,那么 slice() 方法会选取从 start 到数组结尾的所有元素
    b.unshift('aaa'); //开头添加一个元素
    console.log("b=", b)
    console.log("a=", a) 

结合实例理解,小伙伴们,你们都学废了吗?学废了的,记得给宝宝点个赞就当交学费啦!没学废了,建议反复观看,直到学废为止,反正这你们必须给我掌握[傲娇脸]┗( ´・∧・`)┛

 最后,我就出道题考考大家,验收下大家是否有真正学会;

请听题:

var a = [1,2,3];
var b = a;
a.pop();   //pop()方法 :删除数组对象的最后一个元素  这里是直接改变的数组对象[1,2,3]
console.log("b=",b);        //结果b=?

请问,输入数组b 为多少?

请大家留言栏见!我倒要看看,有多少小伙伴能回答上来,第一时间回答正确的小伙伴,我打算给予适当奖励哦!


concat() 用法 :

定义和用法:

concat() 方法用于连接两个或多个数组。

该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。

语法:

arrayObject.concat(arrayX,arrayX,......,arrayX)
参数 描述
arrayX 必需。该参数可以是具体的值,也可以是数组对象。可以是任意多个。

返回值:

返回一个新的数组。该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组。

详情请戳:https://www.w3school.com.cn/jsref/jsref_concat_array.asp

slice()用法

定义和用法:

slice() 方法可从已有的数组中返回选定的元素。

语法

arrayObject.slice(start,end)
参数 描述
start 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。

返回值

返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。

说明

请注意,该方法并不会修改数组,而是返回一个子数组。如果想删除数组中的一段元素,应该使用方法 Array.splice()。

提示和注释

注释:您可使用负值从数组的尾部选取元素。

注释:如果 end 未被规定,那么 slice() 方法会选取从 start 到数组结尾的所有元素。

详情请戳:https://www.w3school.com.cn/js/jsref_slice_array.asp

 

往期回顾:

【1】如何实时统计输入框用户输入字数?

【2】怎么防止用户表单二次提交,你知道吗?

【3】页面如何调用组件内置方法?


❤如果文章对您有所帮助,就在文章的右上角或者文章的末尾点个赞吧!(づ ̄ 3 ̄)づ

❤如果喜欢大白兔分享的文章,就给大白兔点个关注吧!(๑′ᴗ‵๑)づ╭❤~

❤对文章有任何问题欢迎小伙伴们下方留言或者入群探讨【群号:708072830】

❤鉴于个人经验有限,所有观点及技术研点,如有异议,请直接回复讨论(请勿发表攻击言论)。

你可能感兴趣的:(微信小程序)