遇到一个不明白的问题:
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
?????????????????????????????????????????????????
感觉这是变量提升的锅,进行验证
var obj = {"a": 1, "fun": function(){console.log(this.a)}}
var obj_out = {"a": 6, "obj_in": obj}
obj_out.obj_in.fun()//1
分析:我们通过前面的学习知道,在JavaScript中,他的代码在开始运行之前会首先进行词法分析,接着语法分析,然后才是开始运行。更加挑明了说的话,在代码运行前,编译器会首先找到所有的声明然后将他们放到相应的位置。具体细节可以看看前面的提升一文,而这种现象被称作变量提升现象。对应到这里的例子就是:在运行之前,obj和obj_out会被提升为undefined,但是对于a,fun,obj_in这些就不会被提升了。接着就开始运行,运行第一行代码的时候,引擎对作用域发起一个LHS查询obj,由于提升的原因,很显然能够将其找到,于是对其进行赋值,属性a的值为1,属性obj_in的值为obj,此时引擎会发起一个RHS查询obj,由于能够在当前作用域找到,所以此时利用找到的值——经过变量提升后为undefined的obj,注意这里的RHS查询只是将值拷贝给obj_in属性,而不是obj_in指向obj,如果是指向的话,那么经过后续的操作之后就不会是undefined了。那么如何证明这里是深拷贝,而非浅拷贝呢?
下面就证明对于利用字面量构建对象时,以及给对象动态添加属性时,如果对象的一个属性指向的值时引用类型的对象的话,那么此时将引用类型对象这个值赋值给某个属性的时候,利用的将是深拷贝。
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"
通过上面的例子我们可以知道,如果对象的属性的值是一个引用类型的值的话,那么此时将对象的key和value关联起来的时候利用的是深拷贝。
其实,仔细想一想这里根本就不涉及深浅拷贝的问题,因为"obj_in"的值是undefined,而它是非引用类型的值,对于非引用类型的值来说,其拷贝行为只有一个表现那就是:深拷贝。
举一反三:看看下面这个例子
var obj = {"fun": foo}
function foo(){console.log("hihi")}
obj.fun()
上面的结果是什么?正确答案是"hihi",这里也是变量提升,不过变量被提升为了其本应具有的类型-即函数类型。
END