其实对于Javascript链式作用域的描述,包括,JS权威指南,都有些太冗长了--但是很准确:JavaScript中的函数运行在他们被定义的作用域里,而不是他们被执行的作用域里。

这句话有点难懂,但程序的设计,基本都是为了简单,便于理解的。记住JS中经典的一句话是,一切皆对象。

说白了链式作用域,其实就是Javascript的一个特性:子函数中可以访问父函数的所有变量。当然也包括全局变量window(一般的函数定义function a(){},其实都是window对象的子函数)。另外补充一下,函数定义有两种方式,其实略有差别:var a=function(){}和function a(){},稍后再解释他们的区别。

所以,我们看Crockford的<<Javascript语言精粹>>中就提到,要在一个函数中定义变量,要养成良好的习惯,请直接在函数开头定义变量。JS中这点上有别于其它语言的要求----尽量推迟变量定义(使用前定义)。

我们看一下laruence提供的例子:

var name = 'laruence';
   
functionecho(){
    alert(name);

var
name = 'eve';
    alert(name);

alert(age);

}

echo();
   
这个例子其实很有迷惑性(会让人错误的以为,输出结果是:laruence,eve,error;其实结果是:undefined,eve,error),关键就是因为echo()函数中定义的var
name='eve'。但其实换个写法,这个例子就很清楚了:
 
    var name =
'laruence';
    function
echo() {
    var
name;
    alert(name);

name =
'eve';
    alert(name);

alert(age);

}

echo();

其实,上面的函数在JS引擎解析的时候,就会被解析成这样。如果你是初学者,其实这样理解就可以了。但如果你有别的程序的编程经验,例如java。就很容
易被惯用思维给套住了,PS:本人就是给套住的一个。所以,还是按照Crockford的建议把,定义变量,请在函数顶部!!

还记得之前的问题吗? var a=function(){}和function
a(){}的区别。
 
   
它们的区别还变量的定义比较类似。一切皆对象。
 
   
他们两个在函数调用时,基本是等价的,但如果调用函数,在定义函数前就会有问题了。其实区别在于等号和function关键字。
 
   
var和function定义在预编译的时候被提前,var只是占位,具体赋值要等到JS引擎执行到这行。而function定义会在JS引擎预编译阶段就被直接放入到调用对象中。

还是要举例:
 
   
例子一:

alert( echo );//function echo(){return
1;};
    function
echo(){return 1;};
    alert( a
);//undefined
 
    var
a=function(){return 1;};
 
   
所以,函数的定义也可以引申出一句话,请将函数定义放在顶部(先定义后调用)!!

其实还是习惯的问题,JS中一些代码的优良习惯有别于其它语言。建议大家读一下<<Javascript语言精粹>>。在开始学
习一门语言时,最好从欣赏优秀的代码开始。而JS中,大家都喜欢用一系列充满迷惑性的代码来加深自己的理解,这其实是一个误区。

另外说一点,this关键字,laruence的解释很简洁到位:"谁调用,谁就是this"。英文版更详细一点:“In
JavaScript this always refers to the “owner” of the function we're
executing, or rather, to the object that a function is a method of.
”,中文解释:“在JavaScript中,this永远引用我们所执行函数的拥有者,更准确的说,this引用一个函数的方法对象”

看看下面的例子,也是误导人的:
 
    function
a(){
     
g_value="uk";
    }
   
a(); 
   
alert(g_value);
 
   
其实,比较友好的写法应该是这样:

function a(){
   
this.g_value="uk";
    }

a();//a.apply(this);
   
alert(this.g_value);
   
关于this关键字,和别的语言也有区别。首先它并不是实例的引用,而是调用它的上下文。上面例子的a(),等价于a.apply(this);

call和apply的用法是一样的,区别就在参数传递上。一个是一个一个传参数的,一个是将参数作为类数组传递的(注意这个地方是类数组)。

用Javascript 两大特点,也是JS引擎的实现必然导致的:

1) 返回值。在JS引擎中,所有的语法,操作都有返回值,而且通常返回值是它本身或undefined。通常我们可以用"()"操作符,来获取当前句子的返回 值(部分操作符不能用,如var)。例如:a=3;其实这行的返回值就是3,所以在a=b=3时,JS引擎就可以正确的执行下去,首先3赋值给b,然后当 前的返回值3再赋值给a(而不是大家所认为的,先将3赋值给b,然后再将b赋值给a)。又例如函数var fun=function(){},当JS引擎执行到这行时,会先执行右边,返回值是一个函数的字面量,然后将这个函数字面量赋值给fun。

Jquery也是利用了这个特性(函数return this),所以才有链式调用。我们看个例子:"fontFamily".replace( /([A-Z])/g, "-$1" ).toLowerCase(),没错这里也是利用了返回值,所以这行的结果是:font-family。

2) 闭包。子函数调用父函数的变量(非传参),就是闭包。在JS中,子函数能访问父函数的变量,这时被引用的变量不会释放,而且子函数中能一直持有这个变量的引用。

结合以上两大特点,可以生成一个力量强大的怪胎:

(function(){})();

不知道专业的名称,我叫它为:立即执行匿名函数。

首先在第一对括号内,是一个匿名函数,第二个括号会立即调用这个匿名函数的返回值,也就是匿名函数中的内容被立即执行。

这个怪胎的强大在于,它独立了一个作用域(括号中内容执行完后会被立即回收),内部变量外部无法访问,而它又能通过this保留字,来访问外部变量。

举个例子:

var i=100;
   
(function(){
    var
j=1;
       
this.plus_ij = function(){
       
j+=i;
      
 alert(j);
       
}
    }
)
();
plus_ij();

plus_ij();

上面的例子中,立即执行匿名函数,可以访问到外部变量i,甚至可以var定义一个i(也不会影响外部的i值)。而且内部变量j形成了一个闭包,不会释放。

上一篇博文中介绍过function fn(){}和var
fn=function(){},不过,那是在全局作用域中,如果我们将他们放到立即执行匿名函数中,会发生什么呢?

(function(){
var a = function(){}
function b(){}
this.c = function(){ a(); b(); }
})();
c();

上面的例子,你会发现,无论哪种定义方式,在立即执行匿名函数外,都无法访问到a和b函数。也就是a和b函数成了这个立即执行匿名函数的内部函数,外部无法调用,除了通过这个立即执行匿名函数内部定义的外部函数。

Javascript 链式作用域 function fn(){}和var fn=function(){}区别的更多相关文章

  1. js中变量的作用域、变量提升、链式作用域结构

    一:作用域 在ES6之前,javascript没有块级作用域(一对{}即为一个块级作用域),只有全局作用域和函数作用域(局部),因此,对应的有全局变量和局部变量.在函数内部可以访问到全局变量,但在函数 ...

  2. javascript链式运动框架案例

    javascript链式运动框架 任务描述: 当鼠标移入红色矩形时,该矩形宽度逐渐增加至400px,之后高度逐渐增加至400px; 当鼠标移出红色矩形时,该矩形高度逐渐减小至200px,之后宽度逐渐减 ...

  3. JavaScript中函数function fun(){}和 var fun=function(){}的区别

    function fun(){} 和 var fun=function(){}的区别 标题有点长···· 废话少说,其实他们的主要区别就是"函数声明的提前行为". var fun= ...

  4. JavaScript自学笔记(2)---function a(){} 和 var a = function(){}的区别(javascript)

    function a(){} 和 var a = function(){}的区别: 学习做浮窗,看到别人的代码里有: window.onresize = function(){ chroX = doc ...

  5. JavaScript中Function Declaration与Function Expression 或者说 function fn(){}和var fn=function(){} 的区别

    JavaScript是一种解释型语言,函数声明会在JavaScript代码加载后.执行前被解释,而函数表达式只有在执行到这一行代码时才会被解释. 在JS中有两种定义函数的方式, 1是:var aaa= ...

  6. JavaScript 链式结构序列化详解

    一.概述 在JavaScript中,链式模式代码,太多太多,如下: if_else: if(...){ //TODO }else if(...){ //TODO }else{ //TODO } swi ...

  7. Javascript 链式运动框架——逐行分析代码,让你轻松了解运动的原理

    所谓链式运动,就是一环扣一环.我们的很多运动实际上来说指的就是分阶段的,第一个阶段动完,下个阶段开始动. 这个链式运动框架就是用来处理这些问题的. 我们先来看下之前的运动框架,以下是Javascrip ...

  8. JavaScript链式调用

    1.什么是链式调用? 这个很容易理解,例如 $('text').setStyle('color', 'red').show(); 一般的函数调用和链式调用的区别:链式调用完方法后,return thi ...

  9. Javascript 链式操作以及流程控制

    春节过后,感觉过年吃的油腻的食品转化的脂肪都长到 脑子去了. 根本转不动啊 上班第一天 实在是写不动代码了, 顺手打开多天为看的 收件箱,查看查看邮件,看看春节期间 风云变幻的前端圈又有哪些大事发生. ...

随机推荐

  1. cento7.3下玩转sphinx

    cento7.5下玩转sphinx 1 安装依赖文件 yum install postgresql-libs unixODBC 2 下载 wget http://sphinxsearch.com/fi ...

  2. vue打包静态资源路径不正确的解决办法

    vue打包静态资源路径不正确的解决办法 vue项目完成打包上线的时候会碰到静态资源找不到的问题,常见的有两个 1.js,css路径不对 解决办法:打开config/index.js,将其中的asset ...

  3. Django之ModelForm篇

    ModelForm a. class Meta: model, # 对应Model的 fields=None, # 字段 exclude=None, # 排除字段 labels=None, # 提示信 ...

  4. Java服务器工程师任职资格

    Java服务器端开发工程师 1.Java服务器端3年以上开发经验 2.至少一个完整游戏项目经验 3.熟练掌握OOA.OOD.OOP 4.掌握常见网游协议开发方法 5.对TCP/IP有深入了解 6.对消 ...

  5. 使用BlendingTexture实现简单的Terrain

    [使用BlendingTexture实现简单的Terrain] BlendingTexture,就是一张纹理,纹理内存储的数据用于其它去处的Alpha通道value.例如以下四张图需要混合在Terra ...

  6. S初始化生产环境数据

    一.将开发机的库文件导出10.10.1.139开发机服务器,桌面上的BAT文件,将数据库表结构和表数据导出来,导到E:\Repository,设置SADMIN密码永不过期BAT文件内容如下: ::导出 ...

  7. Scala基础:面向对象之对象和继承

    对象 object 相当于 class 的单个实例,通常在里面放一些静态的 field 或者 method:在 Scala 中没有静态方法和静态字段,但是可以使用 object 这个语法结构来达到同样 ...

  8. VUE+WebPack前端游戏设计:实现物体的拖拽动态特效

  9. 高性能Web服务器Nginx的配置与部署研究(16)小议location匹配模式优先级

    1 location 的匹配符 1.1 等于匹配符:= 等于匹配符就是等号,特点可以概括为两点: 精确匹配 不支持正则表达式 1.2 空匹配符 空匹配符的特点是: 匹配以指定模式开始的 URI 不支持 ...

  10. Nginx源码完全注释(3)ngx_list.h / ngx_list.c

    列表头文件ngx_list.h #ifndef _NGX_LIST_H_INCLUDED_ #define _NGX_LIST_H_INCLUDED_ #include <ngx_config. ...