javascript对象、this、作用域和闭包的问题。(相同变量名查找问题)
问题描述
以下几段代码,输出的结果不一样。希望有大神可以解答一下原理,谢谢!
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return function(){
return myvar;
};
}
};
console.log(object.getVar()());//输出TheWindow
function MyCont(){
var myvar = "MyObject";
this.getVar = function(){
return function(){
return myvar;
};
}
}
var obj = new MyCont();
console.log(obj.getVar()());//输出MyObject
然后我修改了一下,加上了this,输出结果又不同了。
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return function(){
return this.myvar;//此处加入了this,依旧输出TheWindow
};
}
};
console.log(object.getVar()());
function MyCont(){
var myvar = "MyObject";
this.getVar = function(){
return function(){
return this.myvar;//此处加入了this,输出变成了TheWindow,而不是原先的MyObject
};
}
}
var obj = new MyCont();
console.log(obj.getVar()());
然后我再改一下
var myvar = "TheWindow";
var object = {
myvar1 : "MyObject",
getVar : function(){
return function(){
return myvar1;//虽然object内含有myvar1属性,但是这样写会报错,但是如果写this.myvar1的话就不报错,输出undefined
};
}
};
console.log(object.getVar()());
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return myvar;//此处去掉了function,还是输出TheWindow
}
};
console.log(object.getVar());
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return this.myvar;//对比上面,加入了this,则输出的是对象属性MyObject
}
};
console.log(object.getVar());
最后还是要感谢一下,好心人帮忙解答问题,万分感谢!
参考文献
这里主要考察的还是对this和作用域的理解,题主可以仔细阅读以下这两篇文章:
基本概念
对this的理解
this值的激活是由于函数调用时上下文的不同而导致的。
另外需要理解引用类型和非引用类型的判定:
如果该表达式是引用类型,那么可根据引用时所处的上下文来确定this的值
如果该表达式不是引用类型,那么this的值为null,而this为null时会默认将this转换为global;那么我们来
明确一下什么是引用类型,什么是非引用类型:
如果标识符,则是引用类型
如果是属性访问器,则是引用类型
其他情况为非引用类型
下面看看引用类型得例子:
var testVar = 10;
function testFunc() {}
var testObj = {
func: function() {
.....
}
};
testObj.func();
testObj['func']();
它们的运行中间结果为:
// 它们的表达式均为标识符,所以属于引用类型,且base均为global,所以它们的this被激活为global
var testVarReference = {
base: global,
propertyName: 'testVar'
};
var testFuncReference = {
base: global,
propertyName: 'testFunc'
};
// 它表达式均为属性访问器,所以属于引用类型,且base均为testObj,所以它们的this被激活为testObj
var testObjFuncReference = {
base: testObj,
propertyName: 'func'
};
另外有两个特殊情况:
在with语句中调用函数,with语句内部所有的this隐式绑定为with对象
this在作为构造器调用的函数中的this隐式绑定为该函数构造器构造的对象
对Scope Chain的理解
作用域链是用于搜索上下文代码中出现的标识符的一组对象序列。搜索规则类似于原型链,如果标识符不在当前的作用域中,那就继续在它的父作用域中继续搜索,知道找到为止。
开始分析
我们对以上基本上有一定了解之后,可以开始分析代码了。
代码片段1
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return function(){
return myvar;
};
}
};
console.log(object.getVar()());//输出TheWindow
function MyCont(){
var myvar = "MyObject";
this.getVar = function(){
return function(){
return myvar;
};
}
}
var obj = new MyCont();
console.log(obj.getVar()());//输出MyObject
第一部分:
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return function(){
return myvar;
};
}
};
console.log(object.getVar()());//输出TheWindow
分析过程:
这里考虑的是在函数getVar中查找标识符myVar的过程;而不是考虑考察this变量的值
在getVar函数作用域中没有搜索到myVar标识符,继续查找父作用域
父作用域中有定义myVar="TheWindow",搜索结束
输出TheWindow
第二部分
function MyCont(){
var myvar = "MyObject";
this.getVar = function(){
return function(){
return myvar;
};
}
}
var obj = new MyCont();
console.log(obj.getVar()());//输出MyObject
分析过程:
同样在作用域链中搜索myVar标识符
在构造函数MyCount中有对myVar的定义,搜索结束
输出MyObject
代码片段2
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return function(){
return this.myvar;//此处加入了this,依旧输出TheWindow
};
}
};
console.log(object.getVar()());
function MyCont(){
var myvar = "MyObject";
this.getVar = function(){
return function(){
return this.myvar;//此处加入了this,输出变成了TheWindow,而不是原先的MyObject
};
}
}
var obj = new MyCont();
console.log(obj.getVar()());
第一部分
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return function(){
return this.myvar;//此处加入了this,依旧输出TheWindow
};
}
};
console.log(object.getVar()());
分析过程:
考察this值得判定
表达式object.getVar()():对于第一次函数调用,其中getVar是属性访问器,所以它的this值是object
由于object.getVar调用之后返回一个匿名函数,所以在第二次函数调用时,也就是第二个括号执行时,由于括号左边的表达式既不是标识符,也不是属性访问器,所以它是一个非引用类型,此时this值为null
this值为null,默认转换为global
输出TheWindow
第二部分
function MyCont(){
var myvar = "MyObject";
this.getVar = function(){
return function(){
return this.myvar;//此处加入了this,输出变成了TheWindow,而不是原先的MyObject
};
}
}
var obj = new MyCont();
console.log(obj.getVar()());
分析过程:
首先要确定,这里搜索变量用到的this值,而不是作用域链中搜索
最后的括号左边表达式是非引用类型,this值为global
输出TheWindow
代码片段3
var myvar = "TheWindow";
var object = {
myvar1 : "MyObject",
getVar : function(){
return function(){
return myvar1;//虽然object内含有myvar1属性,但是这样写会报错,但是如果写this.myvar1的话就不报错,输出undefined
};
}
};
console.log(object.getVar()());
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return myvar;//此处去掉了function,还是输出TheWindow
}
};
console.log(object.getVar());
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return this.myvar;//对比上面,加入了this,则输出的是对象属性MyObject
}
};
console.log(object.getVar());
第一部分
var myvar = "TheWindow";
var object = {
myvar1 : "MyObject",
getVar : function(){
return function(){
return myvar1;//虽然object内含有myvar1属性,但是这样写会报错,但是如果写this.myvar1的话就不报错,输出undefined
};
}
};
console.log(object.getVar()());
分析过程:
myVar1左边没有this,此处myVar1通过作用域链搜索
搜索失败,找不到该标识符
而改成this.myVar1时,根据以上的分析,此处的this隐式转换为global,而global this变量也没有myVar1的声明:在chrome中会输出undefined,而在node下运行会报错!
第二部分
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return myvar;//此处去掉了function,还是输出TheWindow
}
};
console.log(object.getVar());
分析过程:
myvar左边没有this,使用作用域链搜索
输出TheWindow
第三部分
var myvar = "TheWindow";
var object = {
myvar : "MyObject",
getVar : function(){
return this.myvar;//对比上面,加入了this,则输出的是对象属性MyObject
}
};
console.log(object.getVar());
分析过程:
myvar左边有this,需要判定this值
object.getVar为属性访问器,此处this为object
输出MyObject
这篇关于javascript对象、this、作用域和闭包的问题。(相同变量名查找问题)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!