摘要:图示如下而对于引用类型的复制可不是这样这个复制只是将的引用赋值给,二者是属于同一个引用,访问的都是堆内存中的同一个对象,任何一个该引用的变量发生变化,会对其余使用该引用的变量也发生变化。
这两天自己在写代码的时候,出现一个BUG,代码如下:
class Car { constructor(carId) { this.position = [114, 130] this.path = [] this.speed = Math.floor(Math.random() * 5) this.timer = null } run(){ this.position[0] += this.speed * (Math.random() * 2 == 1 ? 1 : -1) this.position[1] += this.speed * (Math.random() * 2 == 1 ? 1 : -1) this.path.push(this.position) if(this.path.length > 10){ this.path.shift() } } start(){ this.timer = setInterval(function(){ this.run() }, 1000) } stop(){ clearInterval(this.timer) } } var car = new Car("10086") car.start()
代码预期的结果是,记录car的最近10个坐标点。
但是实际结果大失所望,得出的是10个一模一样的坐标点,原因在于调用run方法时,其中坐标的改变是基于其属性position这个数组对象的改变,而数组对象的变量名其实是对数组对象地址的引用,因此导致了最后一个坐标的改变引起了所有坐标的改变。
通过这个BUG对自己的基础知识又进行了一次梳理,归纳以及总结,参考资料为JavaScript高级程序设计:
1:基础类型 : Undefined、null、Boolean、Number和String
2:引用类型 : object
其中引用类型的赋值操作需要注意,因为引用类型的值是按引用访问的,且具有动态属性,会根据取得其引用的变量的操作而改变该引用的内存对象发生改变。取复制变量的例子用图示的方法来解释:
如下代码:
var num1 = 5 var num2 = num1
基本类型的赋值就相当于创建一个num1的副本,同时将num2的值等于该副本,两个变量之间的操作互不影响。
图示如下:
而对于引用类型的复制可不是这样
var num1 = obj1 var num2 = num1
这个复制只是将num1的引用赋值给num2,二者是属于同一个引用,访问的都是堆内存中的同一个对象,任何一个该引用的变量发生变化,会对其余使用该引用的变量也发生变化。
在JS中函数参数的传参方式都是按值传参的
可以近似看成函数内部声明一个局部变量名为参数名字的变量,同时为其赋值为参数的值,参数为引用类型则较为复杂些,主要是按值传递比较难理解。
传递的参数为引用类型的话,即函数内部该参数发生了改变会引起堆内存对象的属性发生改变,那么为什么不叫按引用访问,资料中有如下代码进行解释:
function setName(obj) { obj.name = "Nicholas"; obj = new Object(); obj.name = "Greg"; } var person = new Object(); setName(person); alert(person.name); //"Nicholas"
书中的解释比较简洁,个人理解为如果是按引用传参则会发生堆内存的对象会发生改变,由原本的实例person将被新的new Object的实例,同时将其属性name置为"Greg",即最终obj指向的是new Object的实例,而事实上没有,可以理解为函数的引用类型的参数为引用类型的引用,且这里对引用的处理方式是类似基本类型的值一般,不会发生变化。
图示如下:
归纳总结基础知识梳理完毕,回到我的BUG,犯的错误就是引用类型的访问方式的错误,path所push的position数组准确来说指向的都是同一个对象,因此position的每次变化,数组中所有的元素都会发生相同的变化,导致path数组的元素均为一致.
为此对数组的方法进行一次归纳,将数组中可以返回新数组副本(即对原数组无影响)的方法,以方便避免像我这种使用导致的BUG
返回新数组副本方法:concat, slice, splice, filter, map
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/90560.html
摘要:但在开始之前应该心中有数值的不可变性并不是说我们不能在程序编写时不改变某个值。这些都是对值的不可变这个概念的误解。程序的其他部分不会影响的赋值。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTML 最坚实的梁柱;分享,是 CSS 里最闪...
摘要:项目中异常分析引发崩溃日志的流程分析解决办法常见的出现场景状态异常非法线程操作。引发崩溃日志的流程分析解释如下所示,释放与此位图关联的本机对象,并清除对像素数据的引用。 目录介绍 1.1 java.lang.UnsatisfiedLinkError找不到so库异常 1.2 java.lang.IllegalStateException非法状态异常 1.3 android.conten...
摘要:幸运的是,使用符号创建的构造器,如果在不使用来调用,则始终会报错,即使在非严格模式下也不会产生问题。 来源:ApacheCN『JavaScript 编程精解 中文第三版』翻译项目原文:Bugs and Errors 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 部分参考了《JavaScript 编程精解(第 2 版)》 调试的难度是开始编写代码的两倍。 因此,如...
摘要:但是当传递的参数为对象或者数组的时候,是通过引用传入的,所以对于一个引用类型的来说,在子组件中改变这个参数本身将会影响到父组件的数据状态。 问题 父级组件与子组件的通信一般都是通过props来实现的,因为数据流向的单一才能保证数据变化的可追踪性,在vue中props遵循的是单向数据流,原则上子组件修改props是不被允许的。但是当props传递的参数为对象或者数组的时候,是通过引用传入...
摘要:出现错误引发崩溃日志的流程分析这个错误是应用的方法总数限制造成的。 目录介绍 1.1 java.lang.ClassNotFoundException类找不到异常 1.2 java.util.concurrent.TimeoutException连接超时崩溃 1.3 java.lang.NumberFormatException格式转化错误 1.4 java.lang.Illegal...
阅读 3539·2021-11-22 15:22
阅读 3330·2019-08-30 15:54
阅读 2727·2019-08-30 15:53
阅读 790·2019-08-29 11:22
阅读 3533·2019-08-29 11:14
阅读 2074·2019-08-26 13:46
阅读 2212·2019-08-26 13:24
阅读 2279·2019-08-26 12:22