定义
可能很多人在学习 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 的实现,我觉得太麻烦,有一个简单的证明方式,即搜索源码得到所有调用
新闻热点
疑难解答
图片精选