深入学习 JavaScript中的函数调用
定义
可能很多人在学习JavaScript过程中碰到过函数参数传递方式的迷惑,本着深入的精神,我想再源码中寻找些答案不过在做这件事之前,首先明确几个概念。抛弃掉值传递、引用传递等固有叫法,回归英文:
callbyreference&&callbyvalue&&callbysharing
分别是我们理解的C++中的引用传递,值传递。第三种比较迷惑,官方解释是receivesthecopyofthereferencetoobject。我用通俗的话解释一下:
Object可以理解为key的集合,Object对key指向的数据是引用性质的(这里不深究是指针实现还是C++引用实现),函数接收的是一个变量的copy,变量包含了Object的引用,是一个值传递。
那么很明显,函数传参的时候我们接收到的对象型参其实是实参的复制,所以直接更改型参的指向是不可行的;由于Object本身的key都是引用,所以修改key的指向是可行的。
证明
简单来几段代码即可证明
Code1:函数能修改key指向的数据
letfunc=obj=>{obj.name='Dosk'}; letobj={name:'Alxw'}; console.log(obj);//{name:'Alxw'} func(obj) console.log(obj);//{name:'Dosk'}
Code2:函数不能修改obj
letfunc=obj=>{obj={}}; letobj={name:'Alxw'}; console.log(obj);//{name:'Alxw'} func(obj) console.log(obj);//{name:'Alxw'}
Code3:内部obj和外部===结果相等
letdef={name:'Alxw'}; letfunc=obj=>{console.log(obj===def)}; func(def);//true
所以第三段代码可能有疑问了,既然obj是def的复制,为什么===操作还能够为真?不是说===操作对于Object比较的是在内存中的地址么,如果是复制应该是false才对啊?
所以我们回到GoogleV8的源码来看这件事。
深入GoogleV8
我们来看看源码里严格等于操作代码部分:
boolObject::StrictEquals(Object*that){ if(this->IsNumber()){ if(!that->IsNumber())returnfalse; returnNumberEquals(this,that); }elseif(this->IsString()){ if(!that->IsString())returnfalse; returnString::cast(this)->Equals(String::cast(that)); }elseif(this->IsSimd128Value()){ if(!that->IsSimd128Value())returnfalse; returnSimd128Value::cast(this)->Equals(Simd128Value::cast(that)); } returnthis==that; }
看起来应该是最后一种情况,理论上如果def和obj是不同的对象,那么应该返回false才对,这不是推翻了上文所述么?其实不,忽略了一件事,即GoogleV8内部在实例化一个Object的时候,本身就是动态实例化,而我们知道在编译型语言中如果动态实例化只能够在堆内存上,即只能够指针引用。这个结论是的证明涉及到Local、Handle等class的实现,我觉得太麻烦,有一个简单的证明方式,即搜索源码得到所有调用Object::StrictEquals的地方都是直接传入而没有取地址操作。
不过有人会问,既然是值传递的变量包含Object的引用,理论上也能够修改Object才对,为什么第三段代码不能修改呢?
很简单的道理,因为我们在JavaScript语言逻辑层次上的所谓的操作,只不过是在调用GoogleV8的实例方的法而已,根本不可能操作到这一地步(当然,潜在的BUG不算的-。-)
重新定义
我觉得到这里可以给callbysharing重新解释一下了:
的确,传递的时候是值传递,但是内容包含了Object的指针,而且不能够修改这个指针,他是多个变量共享的。
另一种简单的证明
来来来,看源码
V8_DEPRECATE_SOON("Usemaybeversion", LocalCall(Local recv,intargc, Local argv[])); V8_WARN_UNUSED_RESULTMaybeLocal Call(Local context, Local recv,intargc, Local argv[]);
上面的是即将弃用的接口,碰巧我看到的这个版本代码包含大量的这种即将弃用的代码,看看就好。重点是第二个接口,是函数的唯一的调用的接口。里面的Local
可能是重点
别忘了,我们定义的的变量都是类似Handle
最后的最后
总之理解起来可能很费劲甚至有错误,但是在JavaScript语言层次上能够确定了特性,这才是重要的。
以上所述是小编给大家介绍的JavaScript中的函数调用,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!