首页 > 其他分享 >(转)JS核心系列:浅谈函数的作用域

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

时间:2022-12-05 13:31:08浏览次数:42  
标签:function obj 浅谈 作用域 JS window var foo

一、作用域(scope)

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

复制代码

1 function scope(){

2 var foo = "global";

3 if(window.getComputedStyle){

4 var a = "I'm if";

5 console.log("if:"+foo); //if:global

6 }

7 while(1){

8 var b = "I'm while";

9 console.log("while:"+foo);//while:global

10 break;

11 }

12 !function (){

13 var c = "I'm function";

14 console.log("function:"+foo);//function:global

15 }();

16 console.log(

17 foo,//global

18 a, // I'm if

19 b, // I'm while

20 c // c is not defined

21 );

22 }

23 scope();


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

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

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

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

复制代码

1 function varscope(){

2 foo = "I'm in function";

3 console.log(foo);//I'm in function

4 }

5 varscope();

6 console.log(window.foo); //I'm in function


复制代码
二、作用域链(scope chain)

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

复制代码

1 foo = "window";

2 function first(){

3 var foo = "first";

4 function second(){

5 var foo = "second";

6 console.log(foo);

7 }

8 function third(){

9 console.log(foo);

10 }

11 second(); //second

12 third(); //first

13 }

14 first();


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

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

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

特殊情况:with语句

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

复制代码

1 foo = "window";

2 function first(){

3 var foo = "first";

4 function second(){

5 var foo = "second";

6 console.log(foo);

7 }

8 function third(obj){

9 console.log(foo); //first

10 with (obj){

11 console.log(foo); //obj

12 }

13 console.log(foo); //first

14 }

15 var obj = {foo:'obj'};

16 third(obj);

17 }

18 first();


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

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

三、this 关键字

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

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

复制代码

1 window.name = "window";

2 function f(){

3 console.log(this.name);

4 }

5 f();//window

6

7 var obj = {name:'obj'};

8 f.call(obj); //obj


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

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

四、实战应用

code1:


复制代码

1 var foo = "window";

2 var obj = {

3 foo : "obj",

4 getFoo : function(){

5 return function(){

6 return this.foo;

7 };

8 }

9 };

10 var f = obj.getFoo();

11 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"

标签:function,obj,浅谈,作用域,JS,window,var,foo
From: https://blog.51cto.com/u_14230175/5911970

相关文章

  • extjs4,spring mvc3上传文件
    本文讲解下extjs4结合springmvc3的注解完成上传文件的例子。1页面文件  <!--ExtJSFiles--><linkrel="stylesheet"type="text/css......
  • 几款JS 框架介绍和比较
     目前来看,JS框架以及一些开发包和库类有如下几个:Dojo、Scriptaculous、Prototype、yui-ext、Jquery、Mochikit、mootools、moo.fx。 Dojo(JS li......
  • 利用jsjiami保护我们的代码成果
    前言之前看到某程序员因为公司的业务需求作为驱动力而开发的一款工具,可以将json转换为sql语句。只看了个标题和demo,没细致看,估计大致实现流程如下。将json串转化为json对象,......
  • 制作nodejs镜像
    DockerfileFROMubuntu:22.04#wgethttps://nodejs.org/dist/v16.17.0/node-v16.17.0-linux-x64.tar.gz#wgethttps://github.com/yarnpkg/yarn/releases/download/v......
  • js中filter过滤用法总结
    定义和用法filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。注意:filter()不会对空数组进行检测。注意:filter()不会改变原始数组......
  • vs 使用第三方库配置jsoncpp
    https://blog.csdn.net/hml111666/article/details/127227992?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendF......
  • 《重构》、《js高级程序设计》一些笔记知识点
    《重构(第2版):改善既有代码的设计》1.函数命名:以它“做什么”来命名,而不是以它“怎么做”来命名。 一个改进函数名字的好方法:先写一句注释描述这个函数的用途,再把这......
  • Threejs:创建文字
    1.DOM+CSS2.将文字绘制到画布中,并将其用作Texture(纹理)如果你希望在three.js的场景中的平面上轻松地绘制文本,请使用此方法。3.在你所喜欢的3D软件里创建模型,并导......
  • js多个(N)个数组的的元素组合排序算法,多维数组的排列组合或多个数组之间的排列组合
    现在有一批手机,其中颜色有['白色','黑色','金色','粉红色'];内存大小有['16G','32G','64G','128G'],版本有['移动','联通','电信'],要求写一个算法,实现[['白色','16G','移动'......
  • Threejs:安装及其环境
    vue3框架安装:npminstallthree导入://方式1:导入整个three.js核心库import*asTHREEfrom'three';constscene=newTHREE.Scene(); //方式2:仅导......