JS的作用域链是在函数创建时创建的。而this对象是在函数运行期间绑定的。

下面看几个例子,说明JS的作用域链和this是两套分离的链。

1)

var name = 'window下的name<br/>';
var resultCon;
function fn1() {
  resultCon.innerHTML += name;
}

function MyObj() {
  var name = 'MyObj下的name<br/>';
  this.doFunction = function() {
    resultCon.innerHTML += name;
  };
}

window.onload = function() {
  resultCon = document.getElementsByTagName('p')[0];
  var name = "onload下的name<br/>";
  var fn2 = function() {
    resultCon.innerHTML += name;
  };
  fn1();//window下的name    fn1()在创建时它的作用域链就是自己的活动对象-->全局环境,因此在这里搜寻name时,先查找自身没有,然后查找全局发现name='window下的name';
  fn2();//onload下的name   fn2()创建时,作用域链为自己的活动对象-->window.onload函数-->全局环境,在window.onload下找到了name
  var obj = new MyObj();
  obj.doFunction();//MyObj下的name  doFunction()作用域链自己的活动对象-->MyObj的活动对象-->全局环境
};

2)现在把上面的name都改成this.name

var name = 'window下的name<br/>';
var resultCon;
function fn1() {
  resultCon.innerHTML += this.name;
}

function MyObj() {
  var name = 'MyObj下的name<br/>';
  this.doFunction = function() {
    resultCon.innerHTML += this.name;
  };
}

window.onload = function() {
  resultCon = document.getElementsByTagName('p')[0];
  var name = "onload下的name<br/>";
  var fn2 = function() {
    resultCon.innerHTML += this.name;
  };
  fn1();//window下的name   fn1()是在全局环境下调用的,因此this指向window
  fn2();//window下的name   fn2()也是在全局环境下调用的
  var obj = new MyObj();
  obj.doFunction();//undefined    doFunction()中this指向obj,因为MyObj()中name是个局部变量,因此obj.name=undefined,如果把var name=''MyObj下的name<br/>';改为this.name='MyObj下的name<br/>';,那么obj.doFunction()就是'MyObj下的name';
};

可以看到this和作用域是两套分离的链,遵循个自的变量查询逻辑。

this的作用域链,this后的属性或者方法在使用时是先从本实例中查找,如果找到就先返回,如果没找到就接着向上从原型链中查找,如果有多重继承关系,那就一级一级的找上去。

var resultCon;

function MyObj() {
  this.name = 'MyObj下的name<br/>';
  this.doFunction = function() {
    resultCon.innerHTML += this.name;
  };
}
MyObj.prototype.name = 'prototype下的name<br/>';

window.onload = function() {
  resultCon = document.getElementsByTagName('p')[0];
  var obj = new MyObj();
  obj.doFunction();//this指向obj,先看实例中有没有name,找到了MyObj()中的name,因此返回MyObj下的name;
};

如果把MyObj下的name注销掉,那么this就会顺着原型链往上找,返回prototype下的name;

在这里obj的原型链为obj-->MyObj.prototype-->Object.prototype-->null

再来看看call和apply

var name = 'window下的name<br/>';
var resultCon;
function fn1() {
  resultCon.innerHTML += this.name;
}

function MyObj() {
  var name = 'MyObj下的name<br/>';
  this.doFunction = function() {
    resultCon.innerHTML += this.name;
  };
}

window.onload = function() {
  resultCon = document.getElementsByTagName('p')[0];
  var name = "onload下的name<br/>";
  var fn2 = function() {
    resultCon.innerHTML += this.name;
  };
  var myThis = {
    name: "自定义的this的name属性<br/>"
  };
  fn1.call(myThis);//自定义的this的name属性
  fn2.call(myThis);//自定义的this的name属性
  var obj = new MyObj();
  obj.doFunction.call(myThis);//自定义的this的name属性
};

call和apply改变了被调用函数的this的指向

最后看下with,with的使用是为了改变被调用函数中变量的查询域。我们把上例中的call和name前的this去掉再加上with来演示with的作用。

var name = 'window下的name<br/>';
var resultCon;
function fn1(myScope) {
  with (myScope) {
    resultCon.innerHTML += name;
  }
}

function MyObj(myScope) {
  var name = 'MyObj下的name<br/>';
  this.doFunction = function(myScope) {
    with (myScope) {
      resultCon.innerHTML += name;
    }
  };
}

window.onload = function() {
  resultCon = document.getElementsByTagName('p')[0];
  var name = "onload下的name<br/>";
  var fn2 = function(myScope) {
    with (myScope) {
      resultCon.innerHTML += name;
    }
  };
  var myScope = {
    name : "自定义变量查询域</br>"
  };

  fn1(myScope);//自定义变量查询域
  fn2(myScope);//自定义变量查询域
  var obj = new MyObj();
  obj.doFunction(myScope);//自定义变量查询域

};

如果把with这个例子中的name改为this.name的话,同样的输出 window下的name,window下的name,undefined;因为with 只能改变作用域链,this的指向还是保持不变。

看到with的使用并不方便,需要在被调用函数中添加with,有人可能想能不能向下面那样调用来整体改变变量作用域而不去改变被调用函数呢?

with (myScope) {
fn1();
fn2();
var obj = new MyObj();
obj.doFunction();
}

很遗憾,不可以!所以在一些成熟的框架中随处可见call和apply的使用,却很少用到with,在用JSHint检测js语法的时候with处都标了小红点,在一些js编码指导中也建议尽量少用with,因为with改变了变量的默认查询链,所以会给后期的维护人员一些困惑,还有性能方面的一些考虑,请慎用with。

所有的示例都是摘自http://www.cnblogs.com/longze/p/3542582.html   http://www.cnblogs.com/longze/p/3543242.html

JS的作用域链与this指向的更多相关文章

  1. JS 之作用域链和闭包

    1.JS无块级作用域 <script> function Main(){ if (1==1){ var name = "alex"; } console.log(nam ...

  2. js中作用域链的问题

    为什么没有var声明的变量是全局的? 是因为,在js中,如果某个变量没有var声明,会自动到上一层作用域中去找这个变量的声明语句,如果找到,就使用,如果没有找到,继续向上查找,一直查找到全局作用域为止 ...

  3. 浅谈JS的作用域链(一)

    JS的执行环境 执行环境(Execution context,EC)或执行上下文,是JS中一个极为重要的概念. 在JavaScript中有三种代码运行环境: Global Code JavaScrip ...

  4. js之作用域链到闭包

    一.作用域 全局作用域和函数作用域(局部作用域). 一个变量的作用域就是源代码中定义这个变量的区域. 二.作用域链和闭包 全局变量只有一个(window,globel),全局环境下每一个函数都会形成一 ...

  5. JS的作用域链与原型链

    来一波,好记性不如烂笔头. 这两条链子可是很重要的. 作用域链 当执行一段JS代码(全局代码或函数)时,JS引擎会创建为其创建一个作用域又称为执行上下文(Execution Context),在页面加 ...

  6. 浅谈JS的作用域链(三)

    前面两篇文章介绍了JavaScript执行上下文中两个重要属性:VO/AO和scope chain.本文就来看看执行上下文中的this. 首先看看下面两个对this的概括: this是执行上下文(Ex ...

  7. 浅谈JS的作用域链(二)

    上一篇文章中介绍了Execution Context中的三个重要部分:VO/AO,scope chain和this,并详细的介绍了VO/AO在JavaScript代码执行中的表现. 本文就看看Exec ...

  8. 深入理解JS函数作用域链与闭包问题

    function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } ); a.fun(); a.f ...

  9. js高级-作用域链

    作用域链存放的就是 VO  AO 参数 变量 等

随机推荐

  1. python之特点

    .python区分大小写:2.注释规范:python使用井号#作为单行注释,且注释的位置,一般放在要注释代码的前一行或这代码的右侧:多行注释则可以用连续三个单引号开始一行,并连续三个单引号在要注释的代 ...

  2. golang之select

    2.switch语句 (1) (2) 3.select语句 4.for语句 (1)常规式 (2)条件式 (3) (4) goto break continue fallthrought ------- ...

  3. CSS(前)篇

    1.1CSS重点总结 1.1.1 选择器 1.1.2 盒子模型 1.1.3 浮动 1.1.4定位 1.2CSS介绍 概念: 层叠样式表或者级联样式表(Cascading Style Sheets) 层 ...

  4. ubuntu安装verilog

    1.安装verilog sudo apt-get install verilog 2.安装gtkwave sudo apt-get install gtkwave 3.安装dinotrace(和gtk ...

  5. AutoDesk产品,Maya 2018 安装,Microsoft Visual C++ 2012 安装失败,结果 = -2147024546,安装Microsoft Visual C++ 2012 Redistributable 错误0x80070005 等等

    今日老弟装Maya 2018出现问题,我帮忙解决了一下问题,过程颇为曲折,记录一下,看能否帮到有类似困惑的朋友. 我和老弟的电脑牌子一样,就现在自己电脑上装了,竟然开始和他的错误是一样的!都是Micr ...

  6. js 常用事件总结

    无论web端还是手机端,用户的交互总伴随着事件监听 下面是我总结的一些常用到的事件 1.监听标签内容变化 非input元素 $(dom).bind('DOMNodeInserted',function ...

  7. Direct2D 第3篇 绘制文字

    原文:Direct2D 第3篇 绘制文字 #include <windows.h> #include <d2d1.h> #include <d2d1helper.h> ...

  8. SDUT-3376_数据结构实验之查找四:二分查找

    数据结构实验之查找四:二分查找 Time Limit: 30 ms Memory Limit: 65536 KiB Problem Description 在一个给定的无重复元素的递增序列里,查找与给 ...

  9. 安装babel-preset-stage-0为了不打包所有的组件

    今天 看到一段话 是否是我们可以通过这个自定义多种组件,但是只选择我们需要的组件进行打包

  10. Provider Policy与Consumer Policy在bnd中的区别

    首先需要了解的是bnd的相关知识: 1. API(也就是接口), 2. API Provider(接口的实现) 3. API Consumer( 接口的使用者) OSGi中的一个版本有4个部分:    ...