刚开 始学习 JS 时,挺不习惯它函数的用法,就比如一个 function 里面会嵌套一个 function,对于函数里创建变量的作用域也感到很迷惑,这个的语法和 JAVA 相差太多,为此,阅读了《JavaScript高级程序设计》这本书里的相关内容,在 Google 查 阅相关资料,并在此做个总结

函数的创建

// 这是最普通的创建方法
function sum(sum1,sum2){
  return num1+num2;
}
// 将函数赋值给一个变量,需要这样调用 sum(10,10)
var sum = function(num1,num2){
  return num1 + num2;
};
// 利用这种方式创建的函数阅读性差
// 不推荐使用这种方法
var sum = new Function("num1","num2","return num1 + num2");

参数

说到函数,第一个不可避免的话题就是参数了。在 JS 中,函数对于参数的传递方法和 JAVA 相差无几,都是通过复制变量值的方法来进行传递的。变量一般分为基本变量(Boolean、int 等类型)和引用变量(对象)。基本变量的复制是直接将值复制给对应的变量,而引用变量的复制是将变量的地址复制给对应的变量,接下来这两个例子有助于理解。

// 在这个例子中,changeNumber 接收一个 args 变量,这个变量是一个基本类型
// 然后在函数中对 args 进行修改,最后查看这次修改会不会影响外部 num 的值
// 从结果可知,参数对于基本类型的复制仅仅是对它的值进行复制,不会对原来的值进行修改
var num = 9;
function changeNumber(args){
 args = 8;
}
changeNumber(num);
alert(num);               // 结果为 9

// 在这个例子中,我们传入的参数是一个 Array 对象
// 修改 Array 第一个元素的值,查看是否会影响外部的 Array
// 通过结果我们可以看到,对外部的 Array 会产生影响。
var array = new Array();
array[0] = 9;

function changeArray(arr){
 arr[0] = 8;
}
changeArray(array);
alert(array[0]);          // 结果为 8

函数是个对象

在 JAVA 中,经常听到是一句话便是:“在 JAVA 的世界里,无处不对象”,在 JS 中,这句话也是成立的。那么函数是否也是一个对象呢?答案是肯定的。作为一个对象,应该具备独立的属性和方法,接下来就介绍下 Function 这个对象的属性与方法。

  • this 属性

    this 是 JavaScript 中的一个关键字。

    它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。由于函数使用的场合不同,this 代表的对象不同,但是有一个总的原则,那就是 this 指的是调用这个函数的那个对象。

    借助例子我们可以更好的理解这个概念

    var name = "window";
    function getName(){
      var name = "function";
      alert(this.name);
    }
    getName();             // 结果为 window
  • arguments 属性

    在 JS 的函数中,对于传入参数的个数和类型都是不做限制的,这样显得有点无拘无束了,那么,它是怎么做到这一点的呢? arguments 起了很大的作用。arguments 是一个类似 Array 的对象,它包含了函数中传入的所有参数,我们可以通过 arguments[i] 的方式来访问指定位置的参数。

    function add(num1,num2){
      alert(arguments[0]+arguments[1]);
    }
    add(1,2);               // 结果为 3

    arguments除了这个功能之外,还有一个重要的方法:callee,该属性指向函数对象,我们可以借助一下这个例子感受下 callee 的作用,也可以顺便理解一下这句话:“函数是一个对象,函数名是指针”

    // 首先,这是一个递归函数
    function factorial(num){
      if(num<=1){
        return 1;
      }else{
        return num * factorial(num-1);
      }
    }
    // 调用过程把 factorial 置为 null
    var trueFactorial = factorial(10);
    factorial = function(){
      return 0;
    }
    alert(trueFactorial(5));     // 结果为 120
    alert(factorial(5));         // 结果为 0
    // 从中我们可以看出,factorial 是一个指向函数的指针
    // 因此 var trueFactorial = factorial(10)是把函数地址赋予 trueFactorial
    // 当 factorial 函数改变了内容之后,trueFactorial 指向的地址并不会受到影响
    // 这样的写法有可能会使结果出错,而且难免会使函数名和函数产生耦合
    // 这时 callee 就派上用场了
    function factorial(num){
      if(num<=1){
        return 1;
      }else{
        return num*arguments.callee(num-1);
      }
    }

    思考:

通过上面的例子,我们也应该思考下在 JS 中是否有重载这个概念呢?

  • prototype 属性

    我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。如下面的例子:

    ``` javascript

    function Person(){}

    Person.prototype.name = "Nicholas";

    Person.prototype.age = 29;

    Person.prototype.job = "Software Engineer";

    Person.prototype.sayName = function(){

    alert(this.name);

    };

var person1 = new Person();

person1.sayName(); // "Nicholas"

var person2 = new Person();

person2.sayName(); // "Nicholas"

alert(person1.sayName == person2.sayName); // true

```

当创建了一个函数之后,就会根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向原型对象。默认情况下,所有原型对象都会自动会的一个 construct(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。当创建一个实例之后,这个实例会存在一个指向构造函数的指针,我们称这个指针为[[Prototype]]。我们可以通过下面的关系图来理解这段话:



虽然存在着 [[Prototype]] 这个指针,但是我们并不能访问它,不过我们可通过 isPrototypeOf 来确定对象之间是否存在这种关系。

alert(Person.prototype.isPrototypeOf(person1));      // true
alert(Person.prototype.isPrototypeOf(person2));      // true

在 ECMAScipt 5 增加了一个新方法,叫 Object.getPrototypeOf,这个方法返回[[Prototype]] 的值。例如:

alert(Object.getPrototypeOf(person1) == Person.prototype);  // true
alert(Object.getprototypeOf(person1).name);       // "Nicholas"

当想要使用 person1 的 name 属性时,搜索过程是这样子的:首先,编译器会问“person1 有 name 属性吗?”没有。那么编译器就会接着问,person1 的原型有 name 属性吗?有,就返回 “Nicholas”。

根据上面搜索的过程,我们就可以理解下面这段代码了:

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age  = 29;
Person.prototype.job  = "Software Engineer";
Person.prototype.sayName = function(){
  alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name = "Greg";
alert(person1.name);         // "Greg"
alert(person2.name);         // "Nicholas"
  • call 和 apply 方法

    这两个函数都是在特定的作用域中调用特定的函数,实际上等于设置函数体内 this 对象的值。
  • apply

    apply 方法接收两个参数,一个是在其中运行函数的作用域,另一个是参数数组。其中参数数组可以是 Array 的实例,也可以是 arguments 对象。

     function sum(num1,num2){
       return num1 + num2;
     }
     function callSum1(num1,num2){
      return sum.apply(this,arguments);         // 传入 arguments 对象
    }
    function callSum2(num1,num2){
      return sum.apply(this,[num1,num2]);   // 传入数组
    }
    alert(callSum1(10,10));                          // 20
    alert(callSum2(10,10));                          // 20
  • call

    call 方法与 apply 方法的作用域相同,它们的区别仅在于接收参数的方式不同。对于 call 而言,第一个参数 this 值没什么变化,变化的是其余参数都直接传递给函数。

    function sum(sum1,sum2){
     return num1 + num2;
    }
    function callSum1(num1,num2){
      return sum.call(this,num1,num2);
    }
    alert(callSum(10,10));                      // 20
  • 作用扩充函数作用域

    下面这个例子就是通过 call 方法改变函数的作用域。

    window.color = "red";
    var o = {color:"blue"};
    function getColor(){
      alert(this.color);
    }
    sayColor();             // red;
    
    sayColor.call(this);    // red
    sayColor.call(window);  // red
    sayColor(o);            // blue     
  • bind 方法

    我个人认为 bind 和 call、apply 方法没有什么差别。还是通过看一个例子来了解它的看法。

    ``` javascript

    window.color = "red";

    var o = {color:"blue"};

function sayColor(){

alert(this.color);

}

var objectSayColor = sayColor.bind(o);

objectSayColor(); // blue

```

JavaScript 之函数的更多相关文章

  1. JavaScript中函数函数的定义与变量的声明<基础知识一>

    1.JavaScript中函数的三种构造方式 a.function createFun(){ } b.var createFun=function (){ } c.var createFun=new ...

  2. 理解 JavaScript 回调函数并使用

    JavaScript中,函数是一等(first-class)对象:也就是说,函数是 Object 类型并且可以像其他一等对象(String,Array,Number等)一样使用.它们可以"保 ...

  3. 5种 JavaScript 调用函数的方法

    一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正理解Javascript函数是如何工作而导致的(顺便说一下,许多那样的代码是我写的).JavaScript拥有函数式编程的特性 ...

  4. javascript escape()函数和unescape()函数

    javascript escape()函数和unescape()函数 escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串. 语法: escape(string) stri ...

  5. JavaScript调用函数的方法

    摘要:这篇文章详细的介绍了Javascript中各种函数调用的方法及其原理,对于理解JavaScript的函数有很大的帮助! 一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正 ...

  6. Javascript常用方法函数收集(二)

    Javascript常用方法函数收集(二) 31.判断是否Touch屏幕 function isTouchScreen(){ return (('ontouchstart' in window) || ...

  7. javascript工具函数

    第一部分 JavaScript工具函数 转义特殊字符为html实体   HtmlEncode: function(str){ return str.replace(/&/g, '&') ...

  8. [转]javascript eval函数解析json数据时为什加上圆括号eval("("+data+")")

    javascript eval函数解析json数据时为什么 加上圆括号?为什么要 eval这里要添加 “("("+data+")");//”呢?   原因在于: ...

  9. javascript篇-----函数作用域,函数作用域链和声明提前

    在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的(也就是我们不能在代码段外直接访问代码段内声明的变量),我们称之为块级作用域,然而,不同于 ...

  10. JavaScript 常用函数总结

    javascript函数:  ·常规函数  ·数组函数  ·日期函数  ·数学函数  ·字符串函数 .cookie函数 1.常规函数 javascript常规函数包括以下9个函数:  (1)alert ...

随机推荐

  1. H5学习之旅-H5的格式化(4)

    H5的格式设置: b代表是粗体 i斜体 big 字体变大 small变小 em强调 strong 加强和变粗差不多 sub 定义下标字 sup 定义上标字 ins 插入字 del 删除字 代码实例 & ...

  2. Leetcode_36_Valid Sudoku

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42528601 Determine if a Sudoku ...

  3. 一堆C++人找不出内存泄露

    一堆C++人找不出内存泄露 内存泄露就像痔疮对于男人,对于C/C++程序员来说,是顽疾.尤其一堆C++人聚集在一起,准备把程序深处的虫子抓出来的时候,那景象是热火朝天,不亦乐乎. 突然,小白甲发布了一 ...

  4. Dynamics CRM2013/2015 禁止欢迎界面(Disable the Welcome Screen)

    首次打开Dynamic CRM  2013会出现一个欢迎界面如下图,要想它不出现勾选图中的复选框就行,OK下回再打开就没有了. 但是当我们打开F12开发人员工具,清除域的缓存后再次打开CRM,这个欢迎 ...

  5. UML之概述

              UML,英文名曰:Unified  Modeling Language,她还有个中文名字叫统一建模语言,简单的来说,她就是一种绘制软件蓝图的标准语言.她的表达能力特别强,可以描述开 ...

  6. Leetcode_204_Count Primes

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/46366207 Description: Count the ...

  7. 地产IT人福利:帆软地产BI解决方案全解析

    解决方案下载地址 帆软大型地产集团项目解决方案 下载地址:http://pan.baidu.com/s/1pJGeqKF帆软地产BI解决方案之KPI考核系统 下载地址:http://pan.baidu ...

  8. git push 小结

    $ git push ssh://git@dev.lemote.com/rt4ls.git master // 把本地仓库提交到远程仓库的master分支中 $ git remote add orig ...

  9. LeetCode(56)-Add Binary

    题目: Given two binary strings, return their sum (also a binary string). For example, a = "11&quo ...

  10. windows下ruby中显示中文的3种方法

    A: 1将x.rb编码为ascii格式 2 在x.rb开头加上 #code:gbk或者 #coding:gbk B: 1 将x.rb编码为utf-8格式 2 在x.rb开头加上 #code:utf-8 ...