其实对于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函数成了这个立即执行匿名函数的内部函数,外部无法调用,除了通过这个立即执行匿名函数内部定义的外部函数。

最新文章

  1. unsafe
  2. C++远征之封装篇(下)
  3. ubuntu 12.04 sever下安装jre
  4. Docker 学习笔记(CentOS 7.1)
  5. 从Paxos到ZooKeeper-二、ZooKeeper和Paxos
  6. 五个有用的jquery小技巧
  7. 怎样把网站js文件合并成一个?几种方法可以实现
  8. (POJ 1797) Heavy Transportation 最大生成树
  9. 数据库分库分表(sharding)系列【转】
  10. JAVA多态学习3
  11. Mac下安装node.js和webpack
  12. Dynamics CRM2016 新功能之从CRM APP通过电子邮件发送页面链接
  13. Nginx之使用nginx搭建简单的文件服务器
  14. Python虚拟环境和包管理工具Pipenv的使用详解--看完这一篇就够了
  15. 【Unix网络编程】chapter3套接字编程简介
  16. Sql server在使用sp_executesql @sql执行文本sql时,报错: Could not find database ID 16, name &#39;16&#39;. The database may be offline. Wait a few minutes and try again.
  17. org.springframework.dao.InvalidDataAccessApiUsageException
  18. how to use jquery with primefaces
  19. C# Lpt 并口热敏小票打印机打印位图
  20. centos系统为php安装memcached扩展

热门文章

  1. 多线程环境下的UI异步操作
  2. C# 泛型编程之泛型类、泛型方法、泛型约束
  3. Android中RelativeLayout各个属性
  4. SpringBoot入门之spring-boot-maven-plugin
  5. spring-boot-actuator健康监控
  6. Android真机调试手动添加程序包的LogCat
  7. Tomcat ( 单机多 Tomcat 并存 )
  8. Android 4.x 获取存储卡路径的方式
  9. Renderer.materials 和sharedMaterials一些用法上的区别
  10. Log4J的配置文件详解