最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

JS核心系列:浅谈函数的作用域

来源:动视网 责编:小采 时间:2020-11-27 20:26:00
文档

JS核心系列:浅谈函数的作用域

JS核心系列:浅谈函数的作用域:一、作用域(scope)所谓作用域就是:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。function scope(){ var foo = "global"; if(window.getComputedStyle){ var a = "I'm if
推荐度:
导读JS核心系列:浅谈函数的作用域:一、作用域(scope)所谓作用域就是:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。function scope(){ var foo = "global"; if(window.getComputedStyle){ var a = "I'm if


一、作用域(scope)

所谓作用域就是:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

function scope(){
 var foo = "global";
 if(window.getComputedStyle){
 var a = "I'm if";
 console.log("if:"+foo); //if:global
 }
 while(1){
 var b = "I'm while";
 console.log("while:"+foo);//while:global
 break;
 }
 !function (){
 var c = "I'm function";
 console.log("function:"+foo);//function:global
 }();
 console.log(
 foo,//global
 a, // I'm if
 b, // I'm while
 c // c is not defined
 );
}
scope();

(1)scope函数中定义的foo变量,除过自身可以访问以外,还可以在if语句、while语句和内嵌的匿名函数中访问。 因此,foo的作用域就是scope函数体。

(2)在javascript中,if、while、for 等代码块不能形成独立的作用域。因此,javascript中没有块级作用域,只有函数作用域。

但是,在JS中有一种特殊情况:

如果一个变量没有使用var声明,window便拥有了该属性,因此这个变量的作用域不属于某一个函数体,而是window对象。

function varscope(){
 foo = "I'm in function";
 console.log(foo);//I'm in function
}
varscope();
console.log(window.foo); //I'm in function

二、作用域链(scope chain)

所谓作用域链就是:一个函数体中嵌套了多层函数体,并在不同的函数体中定义了同一变量, 当其中一个函数访问这个变量时,便会形成一条作用域链(scope chain)。

foo = "window";
function first(){
 var foo = "first";
 function second(){
 var foo = "second";
 console.log(foo);
 }
 function third(){
 console.log(foo);
 }
 second(); //second
 third(); //first
}
first();

ond时,JS引擎会将second的作用域放置链表的头部,其次是first的作用域,最后是window对象,于是会形成如下作用域链:

second->first->window, 此时,JS引擎沿着该作用域链查找变量foo, 查到的是"second"

当执行third时,third形成的作用域链:third->first->window, 因此查到的是:"frist"

特殊情况:with语句

JS中的with语句主要用来临时扩展作用域链,将语句中的对象添加到作用域的头部。with语句结束后,作用域链恢复正常。

foo = "window";
function first(){
 var foo = "first";
 function second(){
 var foo = "second";
 console.log(foo);
 }
 function third(obj){
 console.log(foo); //first
 with (obj){
 console.log(foo); //obj
 }
 console.log(foo); //first
 }
 var obj = {foo:'obj'};
 third(obj);
}
first();

在执行third()时,传递了一个obj对象,obj中有属性foo, 在执行with语句时,JS引擎将obj放置在了原链表的头部,于是形成的作用域链如下:

obj->third->first->window, 此时查找到的foo就是obj中的foo,因此输出的是:"obj", 而在with之前和之后,都是沿着原来的链表进行查找,从而说明,在with语句结束后,作用域链已恢复正常。

三、this 关键字

在一个函数中,this总是指向当前函数的所有者对象,this总是在运行时才能确定其具体的指向, 也才能知道它的调用对象。

这句话总结了关于this的一切,切记,切记,切记!(ps:重要的事情说三遍!)

window.name = "window";
function f(){
 console.log(this.name);
}
f();//window

var obj = {name:'obj'};
f.call(obj); //obj

在执行f()时,此时f()的调用者是window对象,因此输出"window"

f.call(obj) 是把f()放在obj对象上执行,相当于obj.f(),此时f中的this就是obj,所以输出的是"obj"

四、实战应用

code1:

var foo = "window";
var obj = {
 foo : "obj",
 getFoo : function(){
 return function(){
 return this.foo;
 };
 }
};
var f = obj.getFoo();
f(); //window

code2:

var foo = "window";
var obj = {
 foo : "obj",
 getFoo : function(){
 var that = this;
 return function(){
 return that.foo;
 };
 }
};
var f = obj.getFoo();
f(); //obj

code1和code2是对this和scope最好的总结,如果对于运行结果有疑惑,欢迎讨论!

代码解析:

code1:
执行var f = obj.getFoo()返回的是一个匿名函数,相当于:
var f = function(){
 return this.foo;
}
f() 相当于window.f(), 因此f中的this指向的是window对象,this.foo相当于window.foo, 所以f()返回"window" 

code2:
执行var f = obj.getFoo() 同样返回匿名函数,即:
var f = function(){
 return that.foo;
}
唯一不同的是f中的this变成了that, 要知道that是哪个对象之前,先确定f的作用域链:f->getFoo->window 并在该链条上查找that,此时可以发现that指代的是getFoo中的this, getFoo中的this指向其运行时的调用者,从var f = obj.getFoo() 可知此时this指向的是obj对象,因此that.foo 就相当于obj.foo,所以f()返回"obj"

文档

JS核心系列:浅谈函数的作用域

JS核心系列:浅谈函数的作用域:一、作用域(scope)所谓作用域就是:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。function scope(){ var foo = "global"; if(window.getComputedStyle){ var a = "I'm if
推荐度:
标签: js 系列 函数
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top