一、函数声明和函数表达式

定义函数有两种方式:函数声明和函数表达式。它们之间一个重要的区别是函数提升。

1.函数声明会进行函数提升,所以函数调用在函数声明之前也不会报错:

test();
function test(){
alert(1);
}

2.函数表达式不会进行函数提升,函数调用在函数声明之前的话会报错:

test(); // test is not a function
var test=function(){
alert(1);
}

二、递归函数

递归函数是通过在函数内部调用自身实现的。

①直接使用函数名进行递归调用

function f(num){
  if(num==1){
  return 1;
  }else{
  return num*f(num-1);
  }
}
console.log(f(4));
console.log(f(5));

这种实现的缺点是,在函数内部直接写死了函数名称。如果进行如下设置就会报错:

var test=f;
f=null;
console.log(test(3));//报错, f is not a function

②通过arguments.callee解决,arguments.callee是一个指向正在执行的函数的指针。这样就避免了上述问题。

function f(num){
  if(num==1){
  return 1;
  }else{
  return num*arguments.callee(num-1);
  }
}
console.log(f(4));
console.log(f(5));
var test=f;
f=null;
console.log(test(3));

不过这种方式还有一个缺点,就是在严格模式下会执行失败。

添加"use strict"后执行会报错:

'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them

③采用命名函数表达式可以在严格模式下成功。

"use strict";
var f=function t(num){
if(num==1){
  return 1;
  }else{
  return num*t(num-1);
  }
}
console.log(f(4));
console.log(f(5));
var test=f;
f=null;
console.log(test(3));

三、闭包

闭包是有权访问另一个函数作用域内变量的函数。创建闭包的常见方式就是在一个函数内创建另外一个函数。在另一个函数内部定义的函数,会把外部函数的作用域添加到其作用域链中。

1.闭包与变量

①闭包只能取得包含函数中任意变量的最后一个值。例如:

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

这个方法调用传入1-10返回结果都是10,这并不符合预期。

②通过匿名函数进行改造:

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

改造后的运行结果符合我们的预期了。因为将i传递给num命名参数时是按值传递的。

2.闭包中的this

this变量是在运行时基于函数的执行环境绑定的。

在全局执行环境中,this指向window对象;

当函数作为某个对象的方法时,this等于那个对象;

匿名函数的执行具有全局性,this通常指向window对象。

①闭包中this实例:

var name='window';
var object={
  name:"object",
  getName:function(){
    return function(){
        return this.name;
    }
}
};
object.getName()();//window

②先将闭包外部作用域中的this保存到一个闭包能访问到的变量中,这样就可以让闭包访问相应的对象了。例如:

var name='window';
var object={
  name:"object",
  getName:function(){
var that=this;
     return function(){
        return that.name;
    }
}
};
object.getName()();//object

读javascript高级程序设计03-函数表达式、闭包、私有变量的更多相关文章

  1. 读javascript高级程序设计00-目录

    javascript高级编程读书笔记系列,也是本砖头书.感觉js是一种很好上手的语言,不过本书细细读来发现了很多之前不了解的细节,受益良多.<br/>本笔记是为了方便日后查阅,仅作学习交流 ...

  2. 读javascript高级程序设计08-引用类型之Global、Math、String

    一.Global 所有在全局作用域定义的属性和方法,都属于Global对象. 1.URI编码: encodeURI():主要用于对整个URI编码.它不会对本身属于URI的特殊字符进行编码. encod ...

  3. 读javascript高级程序设计02-变量作用域

    一. 延长作用域链 有些语句可以在作用域前端临时增加一个变量对象,该变量对象在代码执行完成后会被移除. ①with语句延长作用域. function buildUrl(){ var qs=" ...

  4. 读javascript高级程序设计01-基本概念、数据类型、函数

    一. javascript构成 1.javascript实现由三部分组成: ECMAScript:核心语言功能 DOM:文档对象模型,提供访问和操作网页内容的方法和接口 BOM:浏览器对象模型,提供与 ...

  5. 读javascript高级程序设计16-几条函数小技巧

    内容概要 作用域安全的构造函数 惰性载入函数 函数绑定 函数节流 一.作用域安全的构造函数 我们知道,当使用new操作符调用构造函数时,构造函数内部的this会指向新创建对象的实例. function ...

  6. 读javascript高级程序设计10-DOM

    一.节点关系 元素的childNodes属性来表示其所有子节点,它是一个NodeList对象,会随着DOM结构的变化动态变化. hasChildNodes():是否有子节点. var headline ...

  7. 读javascript高级程序设计13-JSON

    JSON是一个轻量级的数据格式,可以简化表示数据结构的工作量.在实际工作中,我们经常用它来传递数据,不过对于其使用的一些细节还是需要注意的.在ECMAScript5中定义了原生的JSON对象,可以用来 ...

  8. 读javascript高级程序设计14-错误处理与调试

    一  错误类型 ECMA规定了常见的7种错误类型: Error: 基类型.其他常见的错误类型都继承自该类型,一般供开发人员抛出自定义错误. EvalError:该类型会在eval()函数使用异常时被抛 ...

  9. 读javascript高级程序设计15-Ajax,CORS,JSONP,Img Ping

    平时用惯了jQuery.ajax之类的方法,却时常忽略了它背后的实现,本文是学习了AJAX基础及几种跨域解决方案之后的一些收获. 一.AJAX——XMLHttpRequest 谈起Ajax我们都很熟悉 ...

随机推荐

  1. PHP获取某月天数

    方式一: <?php function days($year,$month){ if($month<10){ $month = '0'.$month; } if($month == 12) ...

  2. 记录 android 开发的一个 &quot;面试&quot; 问题

    前序: 3天前,有幸得到师兄赏识,和他一起去帮一间珠海的本地的IT公司担任面试官,虽说如此,我自己本身就还没毕业,充其量是去见识下世面罢了.当天共面试了13人,这只是上午,下午我闪了.在笔试的部分,我 ...

  3. window安装jekyll

    安装Ruby Ruby 切记添加环境变量: 安装 RubyGems RubyGems 解压后进入目录输入: ruby setup.rb 安装Jekyll gem install jekyll 安装je ...

  4. Linux 下没有conio.h 已解决

    原文:http://blog.sina.com.cn/s/blog_6a95e00b0100zqvf.html #include <stdio.h>//#include <conio ...

  5. 安卓问题集-Installation error: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED

    错误出现原因: 1.没有 AndroidManifest.xml file文件(出现几率较小) 2. 是你在外面修改了包名而在 AndroidManifest.xml file.文件中没有同步过去导致 ...

  6. java String部分源码解析

    String类型的成员变量 /** String的属性值 */ private final char value[]; /** The offset is the first index of the ...

  7. 在线富文本编辑器kindeditor配置(.Net Framework 3.5)

    下载地址:http://kindeditor.net/down.php 解压放在项目要目录下, 在Bin目录下添加引用:LitJSON.dll 在页面头部加: <link rel="s ...

  8. jstl fn标签

    JSTL使用表达式来简化页面的代码,这对一些标准的方法,例如bean的getter/setter方法,请 求参数或者context以及session中的数据的访问非常方便,但是我们在实际应用中经常需要 ...

  9. SQL Server批量数据导出导入BCP使用

    BCP简介 bcp是SQL Server中负责导入导出数据的一个命令行工具,它是基于DB-Library的,并且能以并行的方式高效地导入导出大批量的数据.bcp可以将数据库的表或视图直接导出,也能通过 ...

  10. Maven(1)-安装和配置

    Maven(1)-安装和配置 一.本机必须安装好Jdk 二 .maven下载 http://maven.apache.org/download.cgi ,下载后把maven-bin解压到自己的目录即可 ...