深入学习 JavaScript中的函数调用


Posted in Javascript onMarch 23, 2017

定义

可能很多人在学习 JavaScript 过程中碰到过函数参数传递方式的迷惑,本着深入的精神,我想再源码中寻找些答案不过在做这件事之前,首先明确几个概念。抛弃掉值传递、引用传递等固有叫法,回归英文:

call by reference && call by value && call by sharing

分别是我们理解的 C++ 中的引用传递,值传递。第三种比较迷惑,官方解释是 receives the copy of the reference to object 。我用通俗的话解释一下:

Object 可以理解为 key 的集合,Object 对 key 指向的数据是引用性质的(这里不深究是指针实现还是C++引用实现),函数接收的是一个变量的 copy,变量包含了 Object 的引用 ,是一个值传递。

那么很明显,函数传参的时候我们接收到的对象型参其实是实参的复制,所以直接更改型参的指向是不可行的;由于 Object 本身的 key 都是引用,所以修改 key 的指向是可行的。

证明

简单来几段代码即可证明

Code 1: 函数能修改 key 指向的数据

let func = obj => { obj.name = 'Dosk' };
let obj = {name : 'Alxw'};
console.log(obj); //{ name: 'Alxw' }
func(obj)
console.log(obj); //{ name: 'Dosk' }

Code 2: 函数不能修改 obj

let func = obj => { obj = {} };
let obj = {name : 'Alxw'};
console.log(obj); //{ name: 'Alxw' }
func(obj)
console.log(obj); //{ name: 'Alxw' }

Code 3: 内部 obj 和外部 === 结果相等

let def = {name : 'Alxw'};
let func = obj => { console.log(obj === def) };
func(def); //true

所以第三段代码可能有疑问了,既然 obj 是 def 的复制,为什么 === 操作还能够为真?不是说 === 操作对于 Object 比较的是在内存中的地址么,如果是复制应该是 false 才对啊?

所以我们回到 Google V8 的源码来看这件事。

深入 Google V8

我们来看看源码里严格等于操作代码部分:

bool Object::StrictEquals(Object* that) {
 if (this->IsNumber()) {
  if (!that->IsNumber()) return false;
  return NumberEquals(this, that);
 } else if (this->IsString()) {
  if (!that->IsString()) return false;
  return String::cast(this)->Equals(String::cast(that));
 } else if (this->IsSimd128Value()) {
  if (!that->IsSimd128Value()) return false;
  return Simd128Value::cast(this)->Equals(Simd128Value::cast(that));
 }
 return this == that;
}

看起来应该是最后一种情况,理论上如果 def 和 obj 是不同的对象,那么应该返回 false 才对,这不是推翻了上文所述么?其实不,忽略了一件事,即 Google V8 内部在实例化一个 Object 的时候,本身就是动态实例化,而我们知道在编译型语言中如果动态实例化只能够在堆内存上,即只能够指针引用。这个结论是的证明涉及到 Local 、Handle 等 class 的实现,我觉得太麻烦,有一个简单的证明方式,即搜索源码得到所有调用 Object::StrictEquals 的地方都是直接传入而没有取地址操作。

不过有人会问,既然是值传递的变量包含 Object 的引用,理论上也能够修改 Object 才对,为什么第三段代码不能修改呢?

很简单的道理,因为我们在 JavaScript 语言逻辑层次上的所谓的操作,只不过是在调用 Google V8 的实例方的法而已,根本不可能操作到这一地步(当然,潜在的 BUG 不算的 -。-)

重新定义

我觉得到这里可以给 call by sharing 重新解释一下了:

的确,传递的时候是值传递,但是内容包含了 Object 的指针,而且不能够修改这个指针,他是多个变量共享的。

另一种简单的证明

来来来,看源码

V8_DEPRECATE_SOON("Use maybe version",
         Local<Value> Call(Local<Value> recv, int argc,
                  Local<Value> argv[]));
V8_WARN_UNUSED_RESULT MaybeLocal<Value> Call(Local<Context> context,
                       Local<Value> recv, int argc,
                       Local<Value> argv[]);

上面的是即将弃用的接口,碰巧我看到的这个版本代码包含大量的这种即将弃用的代码,看看就好。重点是第二个接口,是函数的唯一的调用的接口。里面的 Local<Value> 最终会调用 C++ 的位复制,所以可以简单的证明就是值传递。

可能是重点

别忘了,我们定义的的变量都是类似 Handle<Object> 这种形式的,所以它们之间对象才是共享的,我们所说的 JavaScript 里面变量并不直接指的是 Object 的实例!!!

最后的最后

总之理解起来可能很费劲甚至有错误,但是在 JavaScript 语言层次上能够确定了特性,这才是重要的。

以上所述是小编给大家介绍的JavaScript中的函数调用,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Jquery练习之表单验证实现代码
Dec 14 Javascript
javascript强大的日期函数代码分享
Sep 04 Javascript
通过javascript把图片转化为字符画
Oct 24 Javascript
浅析js设置控件的readonly与enabled属性问题
Dec 25 Javascript
解决自定义$(id)的方法与jquery选择器$冲突的问题
Jun 14 Javascript
javascript使用正则控制input输入框允许输入的值方法大全
Jun 19 Javascript
谈谈Jquery中的children find 的区别有哪些
Oct 19 Javascript
jQuery中的一些常见方法小结(推荐)
Jun 13 Javascript
Bootstrap源码解读导航条(7)
Dec 23 Javascript
webpack配置文件和常用配置项介绍
Apr 28 Javascript
微信小程序全选多选效果实现代码解析
Jan 21 Javascript
eslint+prettier统一代码风格的实现方法
Jul 22 Javascript
js中toString()和String()区别详解
Mar 23 #Javascript
jQuery插件Echarts实现的渐变色柱状图
Mar 23 #jQuery
javascript实现圣旨卷轴展开效果(代码分享)
Mar 23 #Javascript
如何给ss bash 写一个 WEB 端查看流量的页面
Mar 23 #Javascript
angularJS深拷贝详解
Mar 23 #Javascript
canvas实现环形进度条效果
Mar 23 #Javascript
Javascript实现登录记住用户名和密码功能
Mar 22 #Javascript
You might like
php 转换字符串编码 iconv与mb_convert_encoding的区别说明
2011/11/10 PHP
php中使用Ajax时出现Error(c00ce56e)的详细解决方案
2014/11/03 PHP
PHP版微信第三方实现一键登录及获取用户信息的方法
2016/10/14 PHP
PHP批量删除jQuery操作
2017/07/23 PHP
PHP实现的多维数组排序算法分析
2018/02/10 PHP
对laravel的csrf 防御机制详解,及form中csrf_token()的存在介绍
2019/10/24 PHP
document.body.scrollTop 值总为0的解决方法 比较常见的标准问题
2009/11/30 Javascript
jQuery老黄历完整实现方法
2015/01/16 Javascript
JavaScript中 ES6 generator数据类型详解
2016/08/11 Javascript
纯JS代码实现隔行变色鼠标移入高亮
2016/11/23 Javascript
详解js的延迟对象、跨域、模板引擎、弹出层、AJAX【附实例下载】
2016/12/19 Javascript
NodeJS设计模式总结【单例模式,适配器模式,装饰模式,观察者模式】
2017/09/06 NodeJs
小程序ios音频播放没声音问题的解决
2018/07/11 Javascript
jQuery中使用validate插件校验表单功能
2019/05/24 jQuery
mpvue实现左侧导航与右侧内容的联动
2019/10/21 Javascript
node.js Promise对象的使用方法实例分析
2019/12/26 Javascript
vue-cli脚手架的.babelrc文件用法说明
2020/09/11 Javascript
Python3使用turtle绘制超立方体图形示例
2018/06/19 Python
python3+pyqt5+itchat微信定时发送消息的方法
2019/02/20 Python
python的常见矩阵运算(小结)
2019/08/07 Python
Pytorch实现基于CharRNN的文本分类与生成示例
2020/01/08 Python
HTML5 FormData 方法介绍以及实现文件上传示例
2017/09/12 HTML / CSS
兰蔻英国官网:Lancome英国
2019/04/30 全球购物
意大利奢侈品零售商:ilDuomo Novara
2019/09/11 全球购物
瑞士网球商店:Tennis-Point
2020/03/12 全球购物
Perfume’s Club美国官网:西班牙第一家在线美容店
2020/06/10 全球购物
static全局变量与普通的全局变量有什么区别
2014/05/27 面试题
系统管理员的职责包括那些?管理的对象是什么?
2016/09/20 面试题
电气工程自动化求职信
2014/03/14 职场文书
六一儿童节主持词
2014/03/21 职场文书
毕业晚会主持词
2014/03/24 职场文书
大学生演讲稿
2014/04/25 职场文书
奥运会口号
2014/06/13 职场文书
老公出轨后的保证书
2015/05/08 职场文书
php实例化对象的实例方法
2021/11/17 PHP
Python find()、rfind()方法及作用
2022/12/24 Python