深入學(xué)習(xí) JavaScript中的函數(shù)調(diào)用
定義
可能很多人在學(xué)習(xí) JavaScript 過(guò)程中碰到過(guò)函數(shù)參數(shù)傳遞方式的迷惑,本著深入的精神,我想再源碼中尋找些答案不過(guò)在做這件事之前,首先明確幾個(gè)概念。拋棄掉值傳遞、引用傳遞等固有叫法,回歸英文:
call by reference && call by value && call by sharing
分別是我們理解的 C++ 中的引用傳遞,值傳遞。第三種比較迷惑,官方解釋是 receives the copy of the reference to object 。我用通俗的話解釋一下:
Object 可以理解為 key 的集合,Object 對(duì) key 指向的數(shù)據(jù)是引用性質(zhì)的(這里不深究是指針實(shí)現(xiàn)還是C++引用實(shí)現(xiàn)),函數(shù)接收的是一個(gè)變量的 copy,變量包含了 Object 的引用 ,是一個(gè)值傳遞。
那么很明顯,函數(shù)傳參的時(shí)候我們接收到的對(duì)象型參其實(shí)是實(shí)參的復(fù)制,所以直接更改型參的指向是不可行的;由于 Object 本身的 key 都是引用,所以修改 key 的指向是可行的。
證明
簡(jiǎn)單來(lái)幾段代碼即可證明
Code 1: 函數(shù)能修改 key 指向的數(shù)據(jù)
let func = obj => { obj.name = 'Dosk' };
let obj = {name : 'Alxw'};
console.log(obj); //{ name: 'Alxw' }
func(obj)
console.log(obj); //{ name: 'Dosk' }
Code 2: 函數(shù)不能修改 obj
let func = obj => { obj = {} };
let obj = {name : 'Alxw'};
console.log(obj); //{ name: 'Alxw' }
func(obj)
console.log(obj); //{ name: 'Alxw' }
Code 3: 內(nèi)部 obj 和外部 === 結(jié)果相等
let def = {name : 'Alxw'};
let func = obj => { console.log(obj === def) };
func(def); //true
所以第三段代碼可能有疑問(wèn)了,既然 obj 是 def 的復(fù)制,為什么 === 操作還能夠?yàn)檎??不是說(shuō) === 操作對(duì)于 Object 比較的是在內(nèi)存中的地址么,如果是復(fù)制應(yīng)該是 false 才對(duì)啊?
所以我們回到 Google V8 的源碼來(lái)看這件事。
深入 Google V8
我們來(lái)看看源碼里嚴(yán)格等于操作代碼部分:
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;
}
看起來(lái)應(yīng)該是最后一種情況,理論上如果 def 和 obj 是不同的對(duì)象,那么應(yīng)該返回 false 才對(duì),這不是推翻了上文所述么?其實(shí)不,忽略了一件事,即 Google V8 內(nèi)部在實(shí)例化一個(gè) Object 的時(shí)候,本身就是動(dòng)態(tài)實(shí)例化,而我們知道在編譯型語(yǔ)言中如果動(dòng)態(tài)實(shí)例化只能夠在堆內(nèi)存上,即只能夠指針引用。這個(gè)結(jié)論是的證明涉及到 Local 、Handle 等 class 的實(shí)現(xiàn),我覺(jué)得太麻煩,有一個(gè)簡(jiǎn)單的證明方式,即搜索源碼得到所有調(diào)用 Object::StrictEquals 的地方都是直接傳入而沒(méi)有取地址操作。
不過(guò)有人會(huì)問(wèn),既然是值傳遞的變量包含 Object 的引用,理論上也能夠修改 Object 才對(duì),為什么第三段代碼不能修改呢?
很簡(jiǎn)單的道理,因?yàn)槲覀冊(cè)?JavaScript 語(yǔ)言邏輯層次上的所謂的操作,只不過(guò)是在調(diào)用 Google V8 的實(shí)例方的法而已,根本不可能操作到這一地步(當(dāng)然,潛在的 BUG 不算的 -。-)
重新定義
我覺(jué)得到這里可以給 call by sharing 重新解釋一下了:
的確,傳遞的時(shí)候是值傳遞,但是內(nèi)容包含了 Object 的指針,而且不能夠修改這個(gè)指針,他是多個(gè)變量共享的。
另一種簡(jiǎn)單的證明
來(lái)來(lái)來(lái),看源碼
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[]);
上面的是即將棄用的接口,碰巧我看到的這個(gè)版本代碼包含大量的這種即將棄用的代碼,看看就好。重點(diǎn)是第二個(gè)接口,是函數(shù)的唯一的調(diào)用的接口。里面的 Local<Value> 最終會(huì)調(diào)用 C++ 的位復(fù)制,所以可以簡(jiǎn)單的證明就是值傳遞。
可能是重點(diǎn)
別忘了,我們定義的的變量都是類似 Handle<Object> 這種形式的,所以它們之間對(duì)象才是共享的,我們所說(shuō)的 JavaScript 里面變量并不直接指的是 Object 的實(shí)例!!!
最后的最后
總之理解起來(lái)可能很費(fèi)勁甚至有錯(cuò)誤,但是在 JavaScript 語(yǔ)言層次上能夠確定了特性,這才是重要的。
以上所述是小編給大家介紹的JavaScript中的函數(shù)調(diào)用,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- JavaScript:new 一個(gè)函數(shù)和直接調(diào)用函數(shù)的區(qū)別分析
- JavaScript函數(shù)的4種調(diào)用方法實(shí)例分析
- JavaScript 函數(shù)的定義-調(diào)用、注意事項(xiàng)
- 淺談js函數(shù)三種定義方式 & 四種調(diào)用方式 & 調(diào)用順序
- javascript函數(shù)的四種調(diào)用模式
- Javascript 函數(shù)的四種調(diào)用模式
- 深入理解JavaScript中的尾調(diào)用(Tail Call)
- javascript使用call調(diào)用微信API
- 基于JavaScript實(shí)現(xiàn)繼承機(jī)制之調(diào)用call()與apply()的方法詳解
- javaScript call 函數(shù)的用法說(shuō)明
- JavaScript中的apply和call函數(shù)詳解
- JavaScript直接調(diào)用函數(shù)與call調(diào)用的區(qū)別實(shí)例分析
相關(guān)文章
Javascript腳本實(shí)現(xiàn)靜態(tài)網(wǎng)頁(yè)加密實(shí)例代碼
這篇文章介紹了Javascript腳本實(shí)現(xiàn)靜態(tài)網(wǎng)頁(yè)加密實(shí)例代碼,有需要的朋友可以參考一下2013-11-11
ES6使用export和import實(shí)現(xiàn)模塊化的方法
這篇文章主要介紹了ES6使用export和import實(shí)現(xiàn)模塊化的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
弱類型語(yǔ)言javascript中 a,b 的運(yùn)算實(shí)例小結(jié)
這篇文章主要介紹了弱類型語(yǔ)言javascript中 a,b 的運(yùn)算,結(jié)合實(shí)例形式總結(jié)分析了js閉包函數(shù)中布爾值與字符串的a,b運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2019-08-08
js實(shí)現(xiàn)動(dòng)態(tài)改變字體大小代碼
本文為大家介紹下使用js如何實(shí)現(xiàn)動(dòng)態(tài)改變字體大小,感興趣的額朋友不要錯(cuò)過(guò)2014-01-01
javascript設(shè)計(jì)模式 – 原型模式原理與應(yīng)用實(shí)例分析
這篇文章主要介紹了javascript設(shè)計(jì)模式 – 原型模式,結(jié)合實(shí)例形式分析了javascript原型模式相關(guān)概念、原理、應(yīng)用場(chǎng)景及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04
webpack自動(dòng)引入打包資源HtmlWebpackPlugin的實(shí)現(xiàn)
本文主要介紹了webpack自動(dòng)引入打包資源HtmlWebpackPlugin的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
myFocus slide3D v1.1.0 使用方法與下載
myFocus slide3D v1.1.0 使用方法與下載,需要的朋友可以參考下。2011-01-01

