在前面我们已经对函数作了简单的介绍,比如函数的定义、函数的声明、函数的调用和函数的传参等。本节将进一步介绍函数的应用,深度理解函数的各种使用。

函数是一个对象,每个函数时Function类型的一个实例,与其他引用类型一样有属性和方法。由于函数时对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。函数通常是函数声明语法定义的。

function sum(x,y){
return x+y;
}

上面使用函数声明语法定义的。

var sum=function(a,b){
return a+b;
};

上面使用函数表达式声明了一个函数。定义了变量sum,并将其初始化为一个函数。在使用函数表达式定义函数时,没有必要使用函数名。通过变量sum可以引用函数,另外函数的末尾有个分号,与普通的变量定义一样。

另外可以使用Function构造函数来定义函数。Function构造函数可以定义任何数量的参数,最后一个函数被看成是函数体。

var sum= new Function("a","b","return a+b");
function sum(a,b){
return a+b;
}
var anotherSum=sum;
console.log(sum(1,2));
sum=null;
console.log(anotherSum(2,3));

上面定义了函数sum,用于求两个数之和。定义了变量anotherSum,并将sum赋值给anthorSum。这样anotherSum与sum指向了同一个指针。最后调用的时候,即使将sum=null,依然可以调用anotherSum。

var sum=function(a,b){
return a+b;
}
sum=function(a,b){
return a*b;
}
console.log(sum(2,4));//输出8

上面的代码可以清楚地看出函数时没有重载的。后定义的sum将前面的sum覆盖。

JavaScript解析器在执行环境时,对于函数声明和函数表达式定义的函数并不是一视同仁的。解析器会先调用函数的声明,在执行其他代码之前可用。函数表达式,只有当函数执行到当前行,才会被解释执行。

console.log(sum(2,3));//输出5
function sum(a,b){
return a+b;
}
console.log(subtract(2,3));//报错,subtract is not function
var subtract=function(a,b){
return a*b;
}

上面的代码可以看出区别。函数的声明在调用前已经添加到执行环境中,会将函数声明添加到顶部环境中。而通过函数表达式定义的函数,在声明变量前,就调用会发生错误。经过上面的比较,不管是函数声明,还是函数表达式,我们都要养成先定义,再使用的习惯。

JavaScript函数本身就是变量,所以函数可以作为值来使用。函数不仅可以作为参数来传递,而且可以将函数作为另一个函数的结果返回。

function callFunction(func,num){
return func(num);
}
function sum(num){
return num+10;
}
console.log(callFunction(sum,10));

  上面的代码就是将函数作为另一个函数的结果返回,输出20.

函数内部包含一个子函数,并且返回子函数,这就是所谓的函数闭包。闭包的好处就是可以缓存数据。

function closeTest(){
var n=1;
Add=function(){
n=n+1;
}
return function F(){
return n+1;
}
}
var result = closeTest();
console.log(result());
Add();
console.log(result());

上面的代码就是一个闭包函数。在闭包函数内部可以使用函数的内部变量。第一个调用result,返回2.第二次调用result输出3,因为前面已经调用了add方法,将n+1,所以最好输出的结果是3.

var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
var result=object.getNameFunc();
  console.log(result());//undefined,this的指向是window

通过上面的代码可以看清楚,调用result方法的时候,this指向了window,this.name为undefined

var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      }.bind(this);
    }
  };
var result=object.getNameFunc();
  console.log(result());//My Object

这个代码我们加了bind方法,bind函数用于改变this的指向。this.name指向的是object对象,所以result有输出值。bind函数并不会立即执行,当调用该函数的时候才会执行,同时bind函数可以给函数绑定参数。

var substract=function(a,b){
return a*b;
};
var sum=function(a,b){
var that=this;
console.log(that);
return a+b;
}.bind(substract,3,4);
console.log(sum(1,2));//输出7

上面的代码使用bind函数改变了sum函数的this指向,this指向了substract函数,同时为sum添加了两个参数3,4.虽然我在调用的时候又传递了参数1,2,但是我们bind的参数值是在前面的,所有输出7.arguments[2]=1,arguments[3]=2。传递的参数通过arguments依然可以访问到。

函数还有两个常用的方法apply和call。apply和call两个方法的效果是改变函数的指向,并能传递参数,但是立即执行。apply第一个参数是对象,用于改变函数的this指向;第二个参数是数组,是传递给函数的值。call的第一个参数与apply一样,但是call的第二个参数不是数组,与bind类似,参数是一个一个传递的。

function sayHello(str){
console.log(str);
}
sayHello.bind(this,"bind");
sayHello.call(this,"call");
sayHello.apply(this,["apply"]);

上面的代码,我们比较了函数的bind、call和apply方法的不同。最后我们看输出的值为 call apply。但是bind并没有输出,所以说bind并不能让函数立即调用。函数调用bind方法之后,函数依然是一个函数。

sayHello.bind(this,"bind")();这个代码会输出“bind”

apply方法和call方法还可以在函数内部进行调用,并能改变this的指向。

function Super(){
this.a="10";
}
function Sub(){
Super.call(this);
this.b="20";
}
var sub = new Sub();
console.log(sub.a);
console.log(sub.b);

上面的代码有点面向对象继承的意思。通过在sub内部调用super的call方法,让sub也拥有了super的属性。最后的输出结果是 10 20。

函数还拥有一些属性可以使用。如果让我们写一个阶乘函数,大多数人都会这样写:

function factorial(n){
if(n<1){
return 1;
}
else{
return n*factorial(n-1);
}
}

阶乘算法会用到函数的递归,上面的方法将函数名在函数内部再次调用,增加了函数的耦合。我们可以使用函数的属性callee来解耦。callee是函数的属性,它是一个指针,指向拥有这个函数名的函数。

上面的代码我们可以使用arguments.callee替换函数。

function factorial(n){
if(n<1){
return 1;
}
else{
return n*arguments.callee(n-1);
}
}
console.log(factorial(10));//

闭包可以减少全局变量的使用。

(function() {

                    window.oEvent=window.oEvent||{};
var addEvent = function() { /*代码的实现省略了*/ }; function removeEvent() {} oEvent.addEvent = addEvent;
oEvent.removeEvent = removeEvent;
})(window);
console.log(oEvent.addEvent());

上面的代码只定义了一个全局变量

JavaScript函数(二)的更多相关文章

  1. javascript函数 (二 定义函数的三种方法)

    javascript定义函数(声明函数)可以有三种方法:正常方法.构造函数.函数直接量 <html><head></head><body> <sc ...

  2. 第一百零二节,JavaScript函数

    JavaScript函数 学习要点: 1.函数声明 2.return返回值 3.arguments对象 函数是定义一次但却可以调用或执行任意多次的一段JS代码.函数有时会有参数,即函数被调用时指定了值 ...

  3. 深入浅出javascript(二)函数和this对象

    一.函数对象的属性和方法 函数是一种数据类型,也是对象,这一点很明确.因此,函数对象也可以添加属性和方法,但是这里的属性和方法是静态的,之所以这样说,就是为了区别构造函数. 示例如下: ①创建一个空的 ...

  4. JavaScript 函数(二)

    一.匿名函数 1.匿名函数 没有名字的函数即称为匿名函数. 2.使用方法 a.将匿名函数赋值给一个变量,这样就可以通过变量进行调用 b.匿名函数自调用 3.关于自执行函数(匿名函数自调用)的作用:防止 ...

  5. JavaScript 函数声明,函数表达式,匿名函数,立即执行函数之区别

    函数声明:function fnName () {-};使用function关键字声明一个函数,再指定一个函数名,叫函数声明. 函数表达式 var fnName = function () {-};使 ...

  6. 初探JavaScript(二)——JS如何动态操控HTML

    除去五一三天,我已经和<JavaScript Dom编程艺术>磨合了六天,第一印象很好.慢慢的,我发现这是一块排骨,除了肉还有骨头.遇到不解的地方就会多看几遍,实在不懂的先跳过,毕竟,初次 ...

  7. JavaScript函数劫持

    一.为什么我会写这篇文章 这篇文章其实是在一个偶然的机会下发现了居然有JavaScript劫持这种东西,虽然这种东西在平时用的比较少,而且一般实用价值不高,但是在一些特殊的情况下还是要使用到的,所以在 ...

  8. JavaScript函数之美~

    JavaScript函数之美~ 这篇文章,我将就以下几个方面来认识JavaScript中的函数. 函数为什么是对象,如何定义函数? 如何理解函数可以作为值被传递 函数的内部对象.方法以及属性 第一部分 ...

  9. JavaScript引用类型(二)

    Date类型 Javascript中的Date类型是采用Java中的java.util.Date类基础上构建的,使用UTC时间来保存数据,可以精确到1970年1月1日之前或之后的285616年 创建一 ...

随机推荐

  1. 方格取数洛谷p1004

    题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 ...

  2. Android破解学习之路(一)——简单的登录破解

    最近突然心血如潮开始学了Android破解,初入门,便是将经验记录下来. 准备工作: 1.一个登录简单APP 在我们破解之前,我们需要做一个简单的登录APP,输入相应的账号与密码便是弹出登录成功的对话 ...

  3. codeforces #446 892A Greed 892B Wrath 892C Pride 891B Gluttony

    A  链接:http://codeforces.com/problemset/problem/892/A 签到 #include <iostream> #include <algor ...

  4. Redis各个数据类型的使用场景

    Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). Redis列表命令 参考:http://www.r ...

  5. THinkPHP简单漂亮的分页类 DownLoad

    PHP include_once("config.php"); require_once('page.class.php'); //分页类 $showrow = 10; //一页显 ...

  6. Hibernate学习之路-- -映射 继承关系(subclass , joined-subclass,union-subclass )

    1.继承映射 举例:对于面向对象的程序设计语言而言,继承和多态是两个最基本的概念.Hibernate 的继承映射可以理解持久化类之间的继承关系.例如:人和学生之间的关系.学生继承了人,可以认为学生是一 ...

  7. Android破解学习之路(三)——Android游戏 切水果破解

    经过前两篇破解教程,想必大家也是明白了破解的简单流程了. 先对APP进行试用,了解APP运行的大概流程,之后从APP中找出关键字(一般的关键字差不多都是支付失败),之后使用Androidkiller进 ...

  8. 从无到有<前端异常监控系统>落地

    导火索 有一天一个测试同事的一个移动端页面白屏了,看样子是页面哪里报错了.  我自己打开页面并没有报错,最后发现报错只存在于他的手机,移动端项目又是在微信环境下,调试起来会比较麻烦,最后用他手机调试才 ...

  9. HDU 1671 Phone List (Trie)

    pid=1671">Phone List Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ( ...

  10. POJ 2367 topological_sort

    Genealogical tree Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 2920 Accepted: 1962 Spe ...