遇到一個(gè)不明白的問題:
var obj_out = {"a": 1, "obj_in": obj}
var obj = {"a": 2, "fun": function(){console.log(this.a)}}
try{
obj_out.obj_in.fun()
}catch(err){
console.error(err)//TypeError
}
console.log(typeof obj_out.obj_in)//undefined
?????????????????????????????????????????????????
感覺這是變量提升的鍋,進(jìn)行驗(yàn)證
var obj = {"a": 1, "fun": function(){console.log(this.a)}}
var obj_out = {"a": 6, "obj_in": obj}
obj_out.obj_in.fun()//1
分析:我們通過前面的學(xué)習(xí)知道,在JavaScript中,他的代碼在開始運(yùn)行之前會(huì)首先進(jìn)行詞法分析,接著語法分析,然后才是開始運(yùn)行。更加挑明了說的話,在代碼運(yùn)行前,編譯器會(huì)首先找到所有的聲明然后將他們放到相應(yīng)的位置。具體細(xì)節(jié)可以看看前面的提升一文,而這種現(xiàn)象被稱作變量提升現(xiàn)象。對應(yīng)到這里的例子就是:在運(yùn)行之前,obj和obj_out會(huì)被提升為undefined,但是對于a,fun,obj_in這些就不會(huì)被提升了。接著就開始運(yùn)行,運(yùn)行第一行代碼的時(shí)候,引擎對作用域發(fā)起一個(gè)LHS查詢obj,由于提升的原因,很顯然能夠?qū)⑵湔业剑谑菍ζ溥M(jìn)行賦值,屬性a的值為1,屬性obj_in的值為obj,此時(shí)引擎會(huì)發(fā)起一個(gè)RHS查詢obj,由于能夠在當(dāng)前作用域找到,所以此時(shí)利用找到的值——經(jīng)過變量提升后為undefined的obj,注意這里的RHS查詢只是將值拷貝給obj_in屬性,而不是obj_in指向obj,如果是指向的話,那么經(jīng)過后續(xù)的操作之后就不會(huì)是undefined了。那么如何證明這里是深拷貝,而非淺拷貝呢?
下面就證明對于利用字面量構(gòu)建對象時(shí),以及給對象動(dòng)態(tài)添加屬性時(shí),如果對象的一個(gè)屬性指向的值時(shí)引用類型的對象的話,那么此時(shí)將引用類型對象這個(gè)值賦值給某個(gè)屬性的時(shí)候,利用的將是深拷貝。
var fun = function(){console.log("jiajishuiji")}
var obj = {"a": 1, "fun": fun}
fun = function(){console.log("jiagoushuigou")}
obj.fun()//"jiajishuiji"
var fun2 = function(){console.log("before")}
var obj2 = {}
obj2.fun = fun2
fun2 = function(){console.log("after")}
obj2.fun()//"before"
通過上面的例子我們可以知道,如果對象的屬性的值是一個(gè)引用類型的值的話,那么此時(shí)將對象的key和value關(guān)聯(lián)起來的時(shí)候利用的是深拷貝。
其實(shí),仔細(xì)想一想這里根本就不涉及深淺拷貝的問題,因?yàn)?obj_in"的值是undefined,而它是非引用類型的值,對于非引用類型的值來說,其拷貝行為只有一個(gè)表現(xiàn)那就是:深拷貝。
舉一反三:看看下面這個(gè)例子
var obj = {"fun": foo}
function foo(){console.log("hihi")}
obj.fun()
上面的結(jié)果是什么?正確答案是"hihi",這里也是變量提升,不過變量被提升為了其本應(yīng)具有的類型-即函數(shù)類型。
END