简析JavaScript中的Function类型(一)——函数名是指针

提及来ECMAScript中什么最有意思,用原书(《JavaScript高级程序设计》)做者的话说——莫过于函数了,有意思的根源在于函数其实是对象。每一个函数都是Function类型的实例,并且都与其余引用类型同样具备属性和方法。因为函数是对象,所以函数名实际上也就是一个指向函数对象的指针,不会与某个函数绑定。javascript

函数的定义方式有三种:java

  1. 函数声明
  2. 函数表达式
  3. 使用Function构造函数

函数声明的方式是比较常见的一种,以下面例子所示:安全

function sum(num1, num2){
  return num1 + num2;
}

这与下面使用函数表达式定义函数的方式几乎相差无几:函数

var sum = function(num1, num2){
  return num1 + num2;
};

上面的函数表达式语法定义了变量sum,并将其初始化为一个函数。有读者可能会注意到,function关键字后面没有函数名,这是由于在使用函数表达式定义函数的时候,没有必要使用函数名,经过变量sum便可以引用函数。另外,还要注意函数未尾有个分号,就像声明其它变量同样。性能

使用Function构造函数定义函数时,Function构造函数能够接收任意数量的参数,但最后一个参数始终都被看做是函数体,而前面的参数则枚举出了新函数的参数。来看下面的例子:设计

var sum = new Function('num1', 'num2', 'return num1 + num2');

从技术上讲,这也是一个函数表达式。可是,咱们不推荐使用这种方式定义函数,由于这种函数定义方式会致使解析两次代码(第一次是解析常规ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能。不过,这种方式对于理解“函数是对象,函数名是指针”来讲却是很是直观的。指针

因为函数名仅仅是指向函数的指针,所以函数名与包含对象指针的其余变量没有什么不一样。换句话说,一个函数可能会有多个名字,以下例所示:code

function sum(num1, num2){
  return num1 + num2;
}
console.log(sum(10, 10));// 20

var anotherSum = sum;
console.log(anotherSum(10, 10));// 20

sum = null;
console.log(anotherSum(10, 10));// 20

上面的代码首先定义了一个名为sum的函数,用于求两个数的和。而后,又声明了变量anotherSum,赋值为sum,此时anotherSumsum就指向了同一个函数,所以anotherSum()也正常返回告终果。即便切断sum与函数对象的引用关系,也不会影响anotherSum对象

函数名做为指针,也能够理解为何ECMAScript中没有函数重载(函数名相同,参数列表不一样)的概念。来看下面的示例:ip

function add(num){
  return 100 + num;
}
function add(num, num2){
  return 200 + num;
}
console.log(add(100));// 300

按照函数重载的概念,两个add函数的参数列表不一样,当传入一个参数时应该调用第一个add,当传入两个参数时应该调用第二个add。但如上例所示,即便传入一个参数依然是调用第二个add,结果为300,这是为何呢?

答案在函数名是指针,因此第二个add覆盖了第一个add,也许用函数表达式的写法更容易理解:

var add = function(num){
  return 100 + num;
};
var add = function(num, num2){
  return 200 + num;
};

如上例所示,从新声明add会覆盖第一个add。而JavaScript中的函数调用会根据实际传入的参数个数按顺序匹配参数列表,好比这里传入了一个100,那么add中的num就为100num2undefined,若是像这样调用add(100, 20),那么num2则为20

ECMAScript 2015引入了let关键字能够避免变量覆盖的问题,以下所示:

var add = function(num){
  return 100 + num;
};
//Uncaught SyntaxError: Identifier 'add' has already been declared
let add = function(num, num2){
  return 200 + num;
};

解析的时候已经报错,提示add已经声明,因此使用let会更安全一些。

最近在重读唐浩明先生的小说《曾国藩》,里面曾国藩讲到,看书要作到四点:看读写做。看指的就是一般的默默的阅读,能够增长阅读量;读指高声朗诵,他讲一些诗词歌赋等文章,非高声朗诵不能体会其中奥妙;写是抄写,看书时遇到经典的段落文章、好的句子,要抄写下来,既能加深理解,又能以备往后查阅;做是根据本身的理解再创做,这是检测本身是否真的理解以及提升做文能力的重要途径。

本文算是抄写吧,虽然有稍些改动,但基本和原书内容一致,记录下来,一方面加深印象,另外一方面也是分享给读者。

相关文章
相关标签/搜索