zoukankan      html  css  js  c++  java
  • JavaScript高级程序设计学习笔记--函数表达式

    关于函数声明,它的一个重要特征就是函数声明提升,意思是在执行代码之间会读取函数声明,意思是在执行代码之前会先读取函数声明。这就意味着可以把函数声明放在调用它的语句

    后面。

    sayHi();
    function sayHi(){
    alert("Hi!");
    }

    理解函数提升的关键,就是理解函数声明与函数表达式之间的区别。

    //不要这样做
    if(condition){
    function sayHi(){
    alert("HI!");
    }
    }else{
    function sayHi(){
    alert("Yo!");
    }
    }

    表面上看,以上代码表示在condition为true时,使用一个sayHi()的定义;否则,就使用另一个定义。实际上,这在ECMSscript中属于无效语法,JavaScript引擎会尝试修正错误,
    将其转换为合理状态。不过,如果是使用函数表达式,那就没什么问题了。

    //可以这样做
    var sayHi;
    if(condition){
    sayHi=function(){
    alert("Hi!");
    }
    }
    else{
    function sayHi(){
    alert("Yo!");
    }
    }

    这个例子不会有什么意外,不同的函数会根据condition被赋值给sayHi.

    递归

    我们知道,argument.callee是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用,例如:

    function factorial(num){
    if(num<=1){
    return 1;
    }else{
    return num*argument.callee(num-1);
    }
    }

    闭包

    闭包是指有权访问另一个函数作用域中的变更的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。

    function createComparisonFunction(propertyName){
    return function(object1,object2){
    var value1=object1[propertyName];
    var value2=object2[propertyName];
    if(value1<value2){
    return -1;
    } else if(value1>value2){
    return 1;
    }else{
    return 0;
    }
    }
    }

    闭包与变更

    作用域链的这种配置机制引出一个值得注意的副作用,即闭包只能取得包含函数中任何变更的最后一个值。如下面这个例子:

    function createFunctions(){
    var result=new Array();
    for(var i=0;i<10;i++){
    result[i]=function(){
    return i;
    }
    }
    return result;
    }

    这个函数会返回一个函数数组。表面上看,似乎每个函数都应该返回自己的索引值,即位置0的函数返回0,位置1的函数返回1,以此类推。但实际上,每个函数都返回10。因为每个
    函数作用域链中都保存着createFunctions()函数的活动对象(只是保存着对匿名函数function(){return i;}的引用),所以它们返回的都是最后一个i.w但是,我们可以通过创建
    另一个匿名函数强制让闭包的行为符合预期,如下所示:

    function createFunctions(){
    var result=new Array();
    for(var i=0;i<10;i++){
    result[i]= function(num){
    return function(){
    return num;
    }
    }(i)
    }
    return result;
    }

    关于this对象

    我们知道,this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等 于那个对象。不过,匿名函数的
    执行环境具有全局性,因此,其this对象通过指向window

    var name="The Window";
    var object={
    name:"My Object",
    getNameFunc:function(){
    return function(){
    return this.name;
    }
    }
    }
    alert(object.getNameFunc()()); //"The Window" ("在非严格模式下")


    前面提到过,每个函数在被调用时都会自动取得两个特殊变更:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中
    的这两个。不过,把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了。如下所示:

    var name="The Window";
    var object={
    name:"My Object",
    getNameFunc:function(){
    var that=this;
    return function(){
    return this.name;
    }
    }
    }


    模仿块级作用域

    如前所述,JavaScript没有块级作用域的概念。这意味磁卡在块语句中定义的变量,实际上是包含在函数中而非语句中创建的,来看下面的例子.

    function outputNumbers(count){
    for(var i=0;i<count;i++){
    alert(i);
    }
    alert(i); //计数
    }


    即使像下面这样错误的重新声明同一个变量,也不会改变它的值。

    function outputNumbers(count){
    for(var i=0;i<count;i++){
    alert(i);
    }
    var i; //重新声明变更
    alert(i); //计数
    }


    JavaScript从来不会告诉你是否多次声明了同一个变量;遇到这种情况,它只会对后续的声明视而不见。匿名函数可以用来模仿块级作用域并避免这个问题。
    用作块级作用域的匿名函数的语法如下所示:

    (function(){
    //这里是块级作用域
    })();

    以上代码定义并立即调用了一个匿名函数。将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一对圆括号会立即调用这个函数。
    无论在什么地方,只要临时需要一些变量,就可以使用私有作用域,例如:

    function outputNumbers(count){
    (function(){
    for(var i=0;i<count;i++){
    alert(i);
    }
    })();
    alert(i); //导致一个错误!
    }
  • 相关阅读:
    JavaScript正则表达式
    web页面全角&半角
    WEB中的GET和POST
    设计模式之观察者模式
    初识numpy的多维数组对象ndarray
    【ACM】求高精度幂
    C++ 变量初始化规则
    浅谈const限定符
    堆和栈的区别(转过无数次的文章)
    【编程小题目8】求解完数
  • 原文地址:https://www.cnblogs.com/Gyoung/p/3803221.html
Copyright © 2011-2022 走看看