摘要:写在最前本次尝试通过流程图的形式并结合两个例子来重新理解一下中的参数传递。欢迎关注我的博客,不定期更新中参数到底如何传递借用红宝书的一句话中所有函数的参数都是按值传递的这个值如果是简单类型,那么就是其本身。同时执行第一个结果即为。
写在最前
本次尝试通过流程图的形式并结合两个例子来重新理解一下JavaScript中的参数传递。
欢迎关注我的博客,不定期更新中——
参数到底如何传递?借用红宝书的一句话:
ECMAScript中所有函数的参数都是按值传递的
这个值如果是简单类型,那么就是其本身。如果是引用类型也就是对象传递的就是指向这个对象的地址。故我们可以认为参数传递全部都是值传递,那么具体怎么理解呢?看下例子:
第一个例子var obj = { n: 1 }; function foo(data) { data = 2; console.log(data); //2 } foo(obj); console.log(obj.n) // 1
先不说为什么原因,我们就通过画图的方式来走一遍流程,我相信应该就能理解其中的参数传递了。切记传递引用类型传递的是指针!
首先执行var obj = {n: 1}; ,可以看作在栈的001地址中存入了一个指向{n:1}的指针*p
接下来为声明function foo 此时会创建函数执行上下文,产生一个变量对象,其中声明了形参data,由于函数没有执行,当前值为undefined。我们记data地址为022。关于更多变量对象的知识可以参考冴羽老师的这篇JavaScript深入之变量对象,本文不深入研究关于AO相关,你只需要知道在声明这个函数的时候里面的形参已经被创建出来了。
执行foo(obj) 其中会进行参数传递,其中将obj中存储的*p拷贝给处在022地址的data,那么此时它们就指向了同一个对象,如果某一个变量更改了n的值,另一个变量中n的值也会更改,因为其中保存的是指针。
进入函数内部,顺序执行data = 2;此时002地址存储了基本类型值,则直接存储在栈中,从而与堆中的{n:1}失去了联系。从而打印console.log(data) // 2 ,最后发现初始开辟的{n:1}对象没有过更改,故而 console.log(obj.n) // 1仍然打印1。
第二个例子var obj = {n:1}; (function(obj){ console.log(obj.n); //1 obj.n=3; var obj = {n:2}; console.log(obj.n) //2 })(obj); console.log(obj.n) //3
整体来看这个例子中出现了同名覆盖的问题。不太了解代码如何执行的流程,可能会因为同名的关系而有些混乱,不过没关系。只要按照上一个例子的流程图中的执行过程,一定可以得出正确的结果。
声明变量obj,地址为011其中存入指向{n:1}的指针*p
声明函数,虽然同为obj变量名,但是形参obj为AO中的属性,不会与全局造成覆盖,其拥有新的地址记作022,在未执行前其值为undefined。
函数立即执行,此时将全局obj赋值给形参obj,我们忽略这个重复命名的问题,其实就是将011中的 指针*p拷贝了一份给了022。同时执行第一个console.log(obj.n)结果即为1。
执行obj.n=3,此时为函数的形参即022中的obj来改变了对象内n的值。
最关键的一步:var obj = {n:2}; 由于对象命名的关系可能很多童鞋就会有点懵,但依然按照同样的方式来分析即可,由于使用了var那么就是新声明一个对象,从而会在栈中压入新的地址记作033,其中存入了新的指针指向了新的对象{n:2}。从而之后打印的console.log(obj.n)结果则应是新开辟的对象中的n的值。
最后打印 console.log(obj.n) //3很显然,全局的对象有过一次更改其值为3。
小结至此我们走完了上述两段代码涉及变量的所有“心路历程”,由于作者不是科班出身,这个图中对于堆栈以及变量重名的描述可能不是非常的准确,有差错的地方还望不吝赐教~重点是能理解我希望表达的意思就好。总的来说关键点就在于传参的过程中存在一次值的拷贝,同时如果赋值对象是引用类型传入的是指针,明白这两点之后再加上之前流程图的分析相信再遇到类似的问题都可以有较为一致的思路了。
最后惯例po作者的博客,不定时更新中——
有问题欢迎在issues下交流。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/90603.html
摘要:继承和前面两篇文章中的知识非常相关,如果对函数创建原理和原型链不熟悉,请猛戳高级程序设计笔记创建对象高级程序设计笔记原型图解继承,通俗的说,就是将自身不存在的属性或方法,通过某种方式为自己所用文章分别介绍原型链继承继承借用构造函数继承组合继 继承和前面两篇文章中的知识非常相关,如果对函数创建原理和原型链不熟悉,请猛戳:《javascript高级程序设计》笔记:创建对象《javascri...
摘要:因此,所有在方法中定义的变量都是放在栈内存中的当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用因为对象的创建成本通常较大,这个运行时数据区就是堆内存。 上一篇:《javascript高级程序设计》笔记:继承近几篇博客都会围绕着图中的知识点展开 showImg(https://segmentfault.com/img/bVY0C4?w=1330&h=618);...
摘要:一栈数据结构与不同,中并没有严格意义上区分栈内存与堆内存。引用数据类型的值是保存在堆内存中的对象。不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。为了更好的搞懂变量对象与堆内存,我们可以结合以下例子与图解进行理解。 showImg(https://segmentfault.com/img/remote/1460000009784102?w=1240&h=683); ...
摘要:并且如果使用那么必须要指明值使用简单的数据类型不好使使用接口代理模式的注解也可以 属于MyBatis的核心之一,这里面的坑比较多,大家多多看看吧 一 模糊查询的三种方式介绍 我会使用resultMap处理结果集数据 1.死数据的模糊查询 映射文件 SELECT * FROM...
摘要:缓存缓存主要是通过请求和响应报文头中的对应信息,来控制缓存的策略。就会返回一个的状态码,表示可以继续使用客户端本地缓存的数据,并刷新超时时间。与之相对的,则表示当前响应是针对单个用户的,并非通用数据,因此不建议任何中间缓存对其进行缓存。 showImg(https://segmentfault.com/img/remote/1460000015383634?w=1080&h=720);...
阅读 1871·2021-11-24 11:16
阅读 3237·2021-09-10 10:51
阅读 3136·2021-08-03 14:03
阅读 1232·2019-08-29 17:03
阅读 3217·2019-08-29 12:36
阅读 2173·2019-08-26 14:06
阅读 473·2019-08-23 16:32
阅读 2607·2019-08-23 13:42