博客原文地址:Claiyre的个人博客

如需转载,请在文章开头注明原文地址

在许多传统的OO语言中,对象可以包含数据,还可拥有方法,也就是属于该对象的函数。但在JavaScript中,函数也被认为是一个对象,一个Function对象,因此函数被称为JavaScript的一级公民( first-class objects)!

普通函数定义与初始化

1.通过构造器Function

我们知道,JavaScript中Array,Date等基本类型的声明是通过其对应的构造器(关键字)来声明的。如

var arr1 = new Array();   #声明一个空数组
var date1 = new Date(); #声明一个时间对象,获取当前时间

与定义其他基本对象类型如Array,Date一样,JavaScript的函数是通过关键字Function来定义并初始化的

 new Function([arg1],[arg2](,[arg3,...]),functionBody);

举个栗子

var f1 = new Function('name','age','console.log("hello," + name);console.log("You are " + age)');
f1("Claiyre",20);

当然,除了这种‘吃力不讨好’的定义方法外,你还有其他更简洁的方法来定义一个函数!

2.通过函数声明(function statement)

语法:

function name([arg1,[,arg2,[...argn]]]) {
functionBody;
}

name是指定的函数名,arg是函数的参数,可以为任意多个(当然,不能超过可以表示的范围),functionBody为函数体。

栗子如下

function sayHi (name,age){
console.log("hello," + name);
console.log("you are " + age);
}

3.通过函数表达式(function expression)

语法

   function [name]([arg1,[,arg2,[...argn]]]) {
console.log("hello," + name);
console.log("you are " + age);
}

4.总结

  • 方式2和方式3拥有几乎相同的语法,极其相似。但聪明的你一定发现了它们的不同之处了对不对O(∩_∩)O——函数表达式定义一个函数时可以省略函数名,从而创建一个匿名函数或一个立即执行函数(IIFE)。
  • 相比于方式2和方式3,方式1用Function构造器声明函数的方式更为低效,因为后者生成的对象是在函数被创建时解析的,前者是和其他代码一起解析的。
  • 通过函数调用的方式调用Function 的构造函数(不用new关键字)跟方式1是一样的
  • 使用Function构造器,并不会在创建它的上下文(Context)中创建闭包,所以它们只能访问自身局部变量和全局变量,相当于它们总是在全局作用域中被创建的,即便实际并不是!
myName = 'outer';
var person = {
myName: 'inner',
sayHi: new Function('like','console.log("I am "+ myName + "!I like " + like)')
};
person.sayHi("banana");

结果如下:

generator(生成器)函数的定义

generator是ES6标准引入的新的数据类型,旨在利用生成器函数返回一个对象,该对象遵守迭代器协议,而generator的环境(context)在每次执行后都会被保存,以便迭代器对象再次使用,每次迭代就相当于生成一个新的函数,这也是命名为generator(函数生成器)的缘故吧。迭代器协议是ES6标准引入的新协议之一,具体参见 the iterable protocol

与普通函数类似,generator函数也有三种定义方式,但与普通函数稍有不同,具体如下

  1. 通过GeneratorFunction构造器
    new GeneratorFunction ([arg1[, arg2[, ...argN]],] functionBody)
  1. 通过function* 声明(function* statement)
    function* name([param[, param[, ... param]]]) {
statements
}
  1. 通过function表达式(function expression)
    function* [name]([param1[, param2[, ..., paramN]]]) {
statements
}

调用一个生成器函数并不会立即执行它的主体,而是返回一个与该函数对应的迭代器对象,当调用这个迭代器对象的next()方法时,生成器函数的主体才会被执行,直到遇见第一个 yield表达式

纸上谈兵终觉浅,我们来看一个例子

function* idMaker(){
var index = 0;
while(index < 3)
yield index++;
} var gen = idMaker(); // 此时并没有执行idmaker的主体 console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined

即可用yield指定要返回的值,也可用 yield* 委派另一个generator函数对象

如下

function* generatorOne(index){
yield index;
yield* generatorTwo(index);
yield index+10;
} function* generatorTwo(index){
yield index+1;
yield index+2;
yield index+3;
} var ge = generatorOne(10);
console.log(ge.next());
console.log(ge.next());
console.log(ge.next());
console.log(ge.next());
console.log(ge.next());
console.log(ge.next());

运行结果如下:

我们可以看到ge.next()返回了一个对象,该对象有两个属性,value是其返回的值,done代表迭代器是否迭代到了尽头

generator就像是一个不用占用任何全局变量就可以记住执行状态的函数,它的好处当然不只是上面例子那样简单,关于优点和用处,个人认为廖雪峰老师写的已相当不错,参见generator

箭头函数的定义

ES6标准有一个深受广大程序猿喜爱的新属性,那就是箭头函数。它的定义就是用一个箭头。其具体语法如下

let add = x => x+1 ;
add(10); //11

是不是很简便呢?

当然如果有多个参数的话,需要给所有参数加上括号

let add = (x,y) => x+y ;
add(5,6);

以此类推,如果函数体有多条语句的话,也应该给函数体加上{}

此外,箭头函数的另一个特殊之处是它的this总是指向词法作用域,不能被改变,比如:

var myName = "outer";
var person = {
myName:"inner",
age:20
};
var sayHi= ()=>console.log(this.myName);
sayHi(); //outer
sayHi.call(person); //outer

参考资料:

MDN JavaScript

JavaScript函数学习总结(一)---函数定义的更多相关文章

  1. Excel函数学习:HLOOKUP函数

    Excel函数学习:HLOOKUP函数 HLOOKUP函数查找表的第一行中的值,返回该表中与找到的值在同一列的另一个值. 什么情况下使用HLOOKUP? HLOOKUP函数可以在查找行中找到精确匹配值 ...

  2. JavaScript入门学习之二——函数

    在前一章中讲了JavaScript的入门语法,在这一章要看看函数的使用. 函数的定义 JavaScript中的函数和Python中的非常类似,只不过定义的方式有些不同,下面看看是怎么定义的 //定义普 ...

  3. c++函数学习-关于c++函数的林林总总

    本文是我在学习c++过程中的一些思考和总结,主要是c++中关于函数的林林总总.欢迎大家批评和指正,共同学习. os version: ubuntu 12.04 LTS gcc version: gcc ...

  4. Python --函数学习3 (将函数存储在模块中)

    将函数存储在模块 函数可以将代码块和主程序分离,通过给函数指定描述性名称,可以让主程序更加容易理解,还可以更进一步,将函数存储在模块的独立文件中,再将模块导入到主程序.import 语句允许再当前运行 ...

  5. JMeter学习笔记--函数学习(_csvRead 函数)

    JMeter函数可以很方便实现一些小功能,几乎可以用于测试计划中的任何元件.一个函数的调用如下:${_functionName(var1,var2,var3)},_functionName匹配函数名, ...

  6. thinkphp函数学习(3): C函数详解

    function C($name=null, $value=null,$default=null) { static $_config = array(); // 无参数时获取所有 if (empty ...

  7. AutoIt 函数学习之----Send函数

    Send: 作用:向激活窗口发送模拟键击操作. 语法: send('按键'[,标志]) 参数: 按键:要发送的按键序列. 标志:[可选参数] 更改程序处理“按键”的方式:  标志 = 0 (默认),按 ...

  8. MySQL函数学习(一)-----字符串函数

    一.MySQL 字符串函数 \ 函 数 名 称 作 用 完 成 1 LENGTH 计算字符串字节长度 勾 2 CONCAT 合并字符串函数,返回结果为连接参数产生的字符串,参数可以是一个或多个 勾 3 ...

  9. JS中的运算符_函数学习

    js中的运算符:     算数运算符:     + - * / % ++ --          逻辑运算符:     & | !  && || < > <= ...

随机推荐

  1. zabbix分布式系统监视

    http://blog.chinaunix.net/uid-25266990-id-3380929.html

  2. Windows Server 2012如何实现双网卡绑定

    在windows server 2012 之前我们在服务器上如果要实现双网卡绑定则需要向服务器厂家所要相应的软件,但是现在强大的windows server 2012的到来使我们省去了所有的麻烦,因为 ...

  3. 【C#】VS2015开发环境的安装和配置(转)

    出处: http://www.cnblogs.com/rainmj/p/5636518.html http://www.cnblogs.com/rainmj/p/5636529.html http:/ ...

  4. C++之类和对象的使用(三)

    对象数组 如果构造函数只有一个参数,在定义数组时可以直接在等号后面的花括号内提供.Student stud[3]={90,92,01};//合法 如果构造函数有多个参数,则不能用在定义时直接所提供所有 ...

  5. 程序员面试50题(1)—查找最小的k个元素[算法]

    题目:输入n个整数,输出其中最小的k个.例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4. 分析:这道题最简单的思路莫过于把输入的n个整数排序,这样排在最前面的k个数 ...

  6. Django 必会面试题总结

    1 列举Http请求中常见的请求方式 HTTP请求的方法: HTTP/1.1协议中共定义了八种方法(有时也叫“动作”),来表明Request-URL指定的资源不同的操作方式   注意: 1)方法名称是 ...

  7. 如何更改myecelipse、eclipse的Project Explorer的背景颜色

    这个是我研究了很久发现的,因为myecelipse.eclipse本身是随着系统的颜色改变而改变的,windows系统都会随着系统改变而改变的,所以找了很多资料都没能改变它的背景色,今天发现了一个不错 ...

  8. mysql中要根据某个逗号分割的字符串关联查询另一张表的数据

    首先观察下面的查询 select * from company where f_id in ('210','205','208') select * from company where f_id i ...

  9. hdu 1799 循环多少次?

    题目 题意:给出n,m,其中m表示有几层循环,求循环的次数 ①如果代码中出现 for(i=1;i<=n;i++) OP ; 那么做了n次OP运算: ②如果代码中出现 fori=1;i<=n ...

  10. Java动态绑定与静态绑定

    Java动态绑定来自于继承体现,子类继承父类,子类重新覆盖了父类的方法,就是动态绑定,以下举例: (动态绑定是在运行期间) 动物类: /** * 创建一个动物类 * @author Liudeli * ...