JS的作用域链与this指向
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指向的更多相关文章
- JS 之作用域链和闭包
1.JS无块级作用域 <script> function Main(){ if (1==1){ var name = "alex"; } console.log(nam ...
- js中作用域链的问题
为什么没有var声明的变量是全局的? 是因为,在js中,如果某个变量没有var声明,会自动到上一层作用域中去找这个变量的声明语句,如果找到,就使用,如果没有找到,继续向上查找,一直查找到全局作用域为止 ...
- 浅谈JS的作用域链(一)
JS的执行环境 执行环境(Execution context,EC)或执行上下文,是JS中一个极为重要的概念. 在JavaScript中有三种代码运行环境: Global Code JavaScrip ...
- js之作用域链到闭包
一.作用域 全局作用域和函数作用域(局部作用域). 一个变量的作用域就是源代码中定义这个变量的区域. 二.作用域链和闭包 全局变量只有一个(window,globel),全局环境下每一个函数都会形成一 ...
- JS的作用域链与原型链
来一波,好记性不如烂笔头. 这两条链子可是很重要的. 作用域链 当执行一段JS代码(全局代码或函数)时,JS引擎会创建为其创建一个作用域又称为执行上下文(Execution Context),在页面加 ...
- 浅谈JS的作用域链(三)
前面两篇文章介绍了JavaScript执行上下文中两个重要属性:VO/AO和scope chain.本文就来看看执行上下文中的this. 首先看看下面两个对this的概括: this是执行上下文(Ex ...
- 浅谈JS的作用域链(二)
上一篇文章中介绍了Execution Context中的三个重要部分:VO/AO,scope chain和this,并详细的介绍了VO/AO在JavaScript代码执行中的表现. 本文就看看Exec ...
- 深入理解JS函数作用域链与闭包问题
function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } ); a.fun(); a.f ...
- js高级-作用域链
作用域链存放的就是 VO AO 参数 变量 等
随机推荐
- pycharm中引入相对路径错误
真是气死老子了,明明代码就在眼前,居然pycharm说找不到,import报错,最后才发现,需要设置代码的根目录,因此,python代码就在app目录下面,故将app设置成代码根目录就行了
- HR招聘_(九)_招聘方法论(面试环节·薪资谈判和心理把控)
.薪资谈判 薪资谈判在整个过程中非常重要,如果这一环出现问题前期的所有付出都功亏一篑,无法达成招聘目标. 谈判过程中需要遵循以下原则: 明确 通过面试后需要再次确认候选人的目前薪资和期望,虽然第一次电 ...
- 用Python的pandas框架操作Excel文件中的数据教程
用Python的pandas框架操作Excel文件中的数据教程 本文的目的,是向您展示如何使用pandas 来执行一些常见的Excel任务.有些例子比较琐碎,但我觉得展示这些简单的东西与那些你可以在其 ...
- 优化SQL之最佳索引
SQL优化工具Tosska SQL Tuning Expert for Oracle,帮助SQL开发人员解决SQL性能问题. 本工具主要创始人Richard To, 资深ITPUB元老,从1996年开 ...
- ie6中兼容性问题总结
针对firefox ie6 ie7 ie8的css样式中的line-height属性,以前我们大部分都是用!important来hack,对于ie6和firefox测试可以正常显示,但是ie7以上对! ...
- 如何用SPSS分析学业情绪量表数据
如何用SPSS分析学业情绪量表数据 1.数据检验.由于问卷.量表的题目是主观判断和选择,因而难免有些人不认真填,所以,筛选出有效.高质量的数据非常关键.通常需要作如下检查:(1)是否有人回答互相矛盾, ...
- Deserializing/Serializing SOAP Messages in C#
/// <summary> /// Converts a SOAP string to an object /// </summary> /// <typep ...
- 【JZOJ4920】【NOIP2017提高组模拟12.10】降雷皇
题目描述 降雷皇哈蒙很喜欢雷电,他想找到神奇的电光. 哈蒙有n条导线排成一排,每条导线有一个电阻值,神奇的电光只能从一根导线传到电阻比它大的上面,而且必须从左边向右传导,当然导线不必是连续的. 哈蒙想 ...
- objectarx之两条曲线最短距离
double CCommonFuntion::GetLineDistance(AcDbObjectId& Line1, AcDbObjectId& Line2){ AcGeLineSe ...
- 洛谷2050 BZOJ2897美食节题解
放个链接 BZ链接 其实这题就是修车的加强版,做法差不多,还是对于每个厨师进行拆点 可是这样强行建图跑网络流会T飞 我们发现,如果一个厨师没有做倒数第x到菜,他一定不会做倒数第x+1到菜 我们的每次增 ...