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. 浅谈mybatis中#{}和${}的区别

    #{}:表示占位符,如果获取简单类型,#{}中可以使用value或其它名称.有效防止sql注入.使用#{}设置参数无需考虑参数的类型. 如果使用#{}比较日期字段,select* from table ...

  2. 【python之路19】文件操作

    一.打开文件 文件句柄 = open('文件路径', '模式') 打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作. 打开文件的模式有: r ...

  3. listview显示固定条数

    看了很多网上其他大神的,感觉还是在listview的adapter中的getCount中下手比较好点 毕竟计算高度等等,那会让辅助的布局会一团糟,例如下面的搜索历史只显示四条,布局中有横向listvi ...

  4. Android中使用ormlite实现持久化--HelloOrmLite

    Android中内置了sqlite,但是常用的开发语言java是面向对象的,而数据库是关系型的,二者之间的转化每次都很麻烦(主要是我对sql语言不熟悉).而Java Web开发中有很多orm框架,但是 ...

  5. Hdu 1269 强连通判定

    题目链接 迷宫城堡 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total S ...

  6. OpenLayers添加地图标记

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...

  7. 二维码识别项目zxing横屏改为竖屏

    第1步: 在AndroidManifest中将CaptureActivity的screenOrientation属性做如下修改: android:screenOrientation="por ...

  8. 洛谷 P3950 部落冲突 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例1 输出样例1 输入样例2 输出样例2 输入样例3 输出样例3 说明 思路 AC代码 总结 题面 题目链接 P3 ...

  9. Leetcode720.Longest Word in Dictionary词典中最长的单词

    给出一个字符串数组words组成的一本英语词典.从中找出最长的一个单词,该单词是由words词典中其他单词逐步添加一个字母组成.若其中有多个可行的答案,则返回答案中字典序最小的单词. 若无答案,则返回 ...

  10. 【转】MySQL的btree索引和hash索引的区别

    Hash 索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-T ...