深入学习 JavaScript中的函数调用

发布时间 - 2026-01-11 00:19:14    点击率:

定义

可能很多人在学习 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函数调用  # JavaScript:new 一个函数和直接调用函数的区别分析  # JavaScript函数的4种调用方法实例分析  # JavaScript 函数的定义-调用、注意事项  # 浅谈js函数三种定义方式 & 四种调用方式 & 调用顺序  # javascript函数的四种调用模式  # Javascript 函数的四种调用模式  # 深入理解JavaScript中的尾调用(Tail Call)  # javascript使用call调用微信API  # 基于JavaScript实现继承机制之调用call()与apply()的方法详解  # javaScript call 函数的用法说明  # JavaScript中的apply和call函数详解  # JavaScript直接调用函数与call调用的区别实例分析  # 的是  # 都是  # 我觉得  # 这件事  # 才对  # 所述  # 小编  # 应该是  # 是一个  # 第三段  # 几个  # 这一  # 是在  # 不可能  # 包含了  # 他是  # 多个  # 才是  # 在此  # 就好 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: IOS倒计时设置UIButton标题title的抖动问题  laravel怎么通过契约(Contracts)编程_laravel契约(Contracts)编程方法  Laravel怎么实现一对多关联查询_Laravel Eloquent模型关系定义与预加载【实战】  浅述节点的创建及常见功能的实现  Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】  Android实现代码画虚线边框背景效果  公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?  浅析上传头像示例及其注意事项  Laravel怎么为数据库表字段添加索引以优化查询  如何登录建站主机?访问步骤全解析  如何在云主机上快速搭建多站点网站?  详解阿里云nginx服务器多站点的配置  制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?  Mybatis 中的insertOrUpdate操作  手机怎么制作网站教程步骤,手机怎么做自己的网页链接?  通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】  Laravel如何实现URL美化Slug功能_Laravel使用eloquent-sluggable生成别名【方法】  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  Laravel如何实现登录错误次数限制_Laravel自带LoginThrottles限流配置【方法】  如何实现建站之星域名转发设置?  Laravel如何处理CORS跨域问题_Laravel项目CORS配置与解决方案  如何挑选优质建站一级代理提升网站排名?  ,南京靠谱的征婚网站?  Windows Hello人脸识别突然无法使用  长沙企业网站制作哪家好,长沙水业集团官方网站?  弹幕视频网站制作教程下载,弹幕视频网站是什么意思?  HTML5空格和margin有啥区别_空格与外边距的使用场景【说明】  Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】  公司网站制作需要多少钱,找人做公司网站需要多少钱?  如何自定义建站之星网站的导航菜单样式?  UC浏览器如何设置启动页 UC浏览器启动页设置方法  javascript日期怎么处理_如何格式化输出  猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?  Windows驱动无法加载错误解决方法_驱动签名验证失败处理步骤  Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)  HTML 中动态设置元素 name 属性的正确语法详解  如何破解联通资金短缺导致的基站建设难题?  免费网站制作appp,免费制作app哪个平台好?  Swift开发中switch语句值绑定模式  如何在腾讯云免费申请建站?  如何在宝塔面板创建新站点?  Android使用GridView实现日历的简单功能  Laravel如何操作JSON类型的数据库字段?(Eloquent示例)  EditPlus中的正则表达式 实战(1)  QQ浏览器网页版登录入口 个人中心在线进入  详解Android图表 MPAndroidChart折线图  实例解析Array和String方法  googleplay官方入口在哪里_Google Play官方商店快速入口指南  bing浏览器学术搜索入口_bing学术文献检索地址  iOS验证手机号的正则表达式