一直以来JavaScript的原型链和作用域链非常困扰我,其中夹杂着this问题更是让问题雪上加霜,并不是说原型链或者说作用域链有多难理解,而是经常混乱了概念,下面记录一下思考过程,希望对自己或是他人都有帮助。
var maybe="maybe"
function ObjectMake () {
var maybe = "hello" ;
this .getmaybe = function () {
return maybe;
}
}
var b = new ObjectMake();
var c = b.getmaybe();
作用域(scope)是针对函数而言的,每个函数在执行的时候都会分配作用域链,上面例子是一个典型的工厂模式,其中对于ObjectMake函数而言,其作用域链[[scope]]是scope_0(Windows)+scope_1(ObjectMake),对于getmaybe函数而言,其作用域是scope_0(Windows)+scope_1(ObjectMake)+scope_2(getmaybe),在scope0和scope1都存在maybe变量的时候,scope1优先于scope0,所以变量c的值是hello。
下面这种情况呢:
var maybe="maybe" ;
var getmaybe = function () {
return maybe;
}
function ObjectMake () {
var maybe = "hello" ;
this .getmaybe = getmaybe;
}
var b = new ObjectMake();
var c = b.getmaybe();
根据作用域链分析可以得出:对于getmaybe函数而言,其作用域链[[scope]]是scope_0(Windows)+scope_1(getmaybe),对于对于ObjectMake函数而言,其作用域链[[scope]]是scope_0(Windows)+scope_1(ObjectMake),所以当运行b.getmaybe时getmaybe查找作用域只能在cope_0(Windows)中发现maybe变量,故c的值为maybe。
有人可能会提出一个问题,为什么getmaybe函数作用域链没有包含scope_1(ObjectMake),因为JavaScript是词法作用域,简而言之,就是函数的作用域链只和函数在哪里定义有关系,和函数在哪里运行没有关系,上面getmaybe定义在Windows中,所以其作用域链中只存在两个:Windows和它自己。
明白了这个道理,下面这个例子又让我晕了很久:
var maybe = "maybe" ;
var show = {
maybe:"hello" ,
getmaybe:function () {
return maybe;
}
}
var d = show.getmaybe();
按照之前的说法,getmaybe定义在对象show对象当中,为何d的值不是maybe?让我们还是从之前的分析作用域链开始,函数getmaybe定义在对象show中,其作用域链为:scope_0(Windows)+scope_(getmaybe),scope作用域代表获取执行环境的地址,目前JavaScript的执行环境有:1)全局执行环境、2)Eval函数执行环境、3)普通函数执行环境,可知show对象不是一个执行环境,函数的scope无法将它推入作用域链中,所以d的值为maybe。
下面我们再看一个例子:
var maybe = "maybe" ;
var show = {
maybe:"hello" ,
getmaybe:function () {
return this .maybe;
}
}
var d = show.getmaybe();
上面在getmaybe函数中加上this指针后,终于返回了hello了,this指针在JavaScript中是一个非常重要但是又常常会误导人的概念,在一般的OOP(面向对象的语言中),一般都有this这个概念,比如c++的this,Python的self等等。this代表对象实例的地址,在JavaScript中,对象都是实例,不存在C++中的class概念,而this都是动态绑定的(可以用apply()或是call()等函数来改变),show.getmaybe()将getmaybe函数的this指针绑定了show对象,有些时候this指针会被偷偷的替换掉,这个时候可能我们都不知道,关于this指针,下次有时间再写一篇作为理解之用。
这篇文章主要是关于JavaScript对象和作用域的关系,但实际上通过上面的例子可以知道,它们并没有关系,都是个人见解,有误后续会修改