javascript对象、this、作用域和闭包的问题。(相同变量名查找问题)

查看:88
本文介绍了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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆