18Function类型
Function类型
Function类型与函数
函数是这样的一段 Javascript代码,它只定义一次,但可能被执行或调用多次。
Function类型是 JavaScript提供的引用类型之一,通过 Function类型创建 Function对象。
在Javascript中,函数也是以对象的形式存在的。每个函数都是一个 Function对象。
函数名,本质就是一个変量名,是指向某个Function对象的引用。
每一个函数都是一个Function类型的函数、
1 | function fn() { |
通过Function创建函数
语法:var 函数名 = new Function(args,statement);
args
字符串类型,表示当前创建函数的形参。如果是多个形参用逗号分隔
statement
表示当前创建函数的函数体(字符串类型)。
1 | var fun = new Function("a,b", 'console.log("this is function "+a+" "+b)'); |
Function与Object
Function即是自身类型也是Object类型。Object同理。
1 | /** |
自定义构造函数
构造函数又称对象模板或构造器,它的作用是创建JavaScript对象。构造函数有两种,分别如下:
- JavaScript提供的构造函数 - 引用类型
- 自定义构造函数
自定义构造函数声明方式
函数声明方式
1
2
3
4
5
6
7
8function Hero() {
// 定义属性
this.name = "张无忌";
// 定义方法
this.sayMe = function () {
console.log("this is function ");
};
}字面量声明方式
1
2
3
4
5
6
7
8var Hero = function (name) {
// 定义属性
this.name = name;
// 定义方法
this.sayMe = function () {
console.log("this is function ");
};
};
利用构造函数创建对象
创建对象的类型为声明时的函数。例如使用Hero构造函数创建对象,那么对象就是Hero类型的。
1 | var hero = new Hero("张无忌"); |
构造函数与函数的异同点
相同点
- 语法结构相同
不同点
函数
函数包括函数体,而函数体里包括局部变量和函数
构造函数
构造函数包括属性和方法
Constructor属性
JavaScript中所有对象都包含一个constructor
属性,这个属性来源于Object对象。
1 | // 定义一个构造函数 |
构造函数与函数
定义一个函数时,它既是一个函数也是一个构造函数,同时又是一个对象。
1 | function Hero() { |
定义函数的方式与区别
定义方式 | 执行 | 效率 |
---|---|---|
函数定义语句 | 函数名被声明提前 | 不存在效率问题 |
字面量表达式 | 函数体固定,无法动态执行 | 不存在效率问题 |
Function类型定义 | 函数体是字符串,可以动态执行 | 效率低 |
Function的属性与方法
length属性
获取形参的个数。调用方式如下:
1 | // Function类型的length属性 - 获取函数(形参)的参数的个数 |
Function的apply()方法
用于调用一个函数,并且接受指定的this值,以及一个数组作为参数。语法结构如下
func.apply(thisArg,[argsArray])
thisArg
指定
this
的值,表示当前调用函数的对象。如果不使用this
值时,提供默认为null
或者undefined
值argsArray
用于接收指定参数的形参。
与函数调用体的区别在于接收的this值
1 | function fn(a, b) { |
Function的call()方法
Function的 call()方法用于调用一个函数,并且接收指定的this值作为参数,以及参数列表。
func.call(thisArg,arg1,arg2,...)
thisArg
用于指定this的值
后边的参数御用接收函数的实参
call()与apply()方法区别 - 在于第二个参数
1 | /** |
Function的bind()方法
Function的bind()方法用于创建一个新的函数(称为绑定函数),井且接收指定的this值作为参数,以及参数列表。其语法结构如下
fun.bind(thisArg[,arg1[,arg2[,...]]])
thisArg
指定
this
的值,表示当前调用函数的对象。如果不使用this
值时,提供默认为null
或者undefined
值arg
用于接收指定参数的形参。
返回值
返回新创建的函数
作用
实现函数的深复制
验证复制为深复制
1 | var fn = function () { |
通过以上代码测试,当声明一个函数后,再次修改这个函数,并不会影响前边复制的f。因此bind方法实现的是深复制。
函数赋值也为深复制
1 | var a = function () { |
关于bind()方法的参数
在复制函数时,bing()方法传入的参数会作为参数调用时默认传入的参数。例如:
1 | var fn = function (v) { |
但是这并不意味着不能在向这个函数传递参数,例如给f()
传入参数'a'
那么相当于调用fn
函数时传入了两个参数fn('zhangwuji','a')
。例如如下测试:
1 | var fn = function (v+w) { |
函数的重载
在其他开发语言中,函数具有一种特性,叫做重载。所谓重载,就是定义多个同名的函数,但每一个函数接收的参数的个数不同,程序会根据调用时传递的实参个数进行判断,具体调用的是哪个函数。
但是在JavaScript中不可以像下面的方式定义:
1 | // 在JavaScript如果定义多个同名函数 - |
arguments对象
存在于函数体中的特殊对象(原本是Function类型的arguments属性)。arguments对象是一个类数组对象,其中包含length
属性:函数实参的个数,其作用是用于接收函数的参数(实参)
1 | function fn() { |
模拟函数重载
1 | function add() { |
JavaScript中没有函数重载,只能通过模拟来实现
递归
函数的递归:函数在当前函数体调用自身。
执行方式类似于循环语句的执行方式即反复执行指定的语句块内容。
执行递归函数时,必须提供结束执行的条件(出口)
如下为最简单的递归:
1 | var v = 0; |
如果在外部需要释放函数,那么函数内部的自调应该改为arguments.callee()
。
1 | var v = 0; |
特殊函数(高阶函数)
匿名函数
所谓匿名函数就是没有名字的函数,但JavaScript的语法并不支持匿名函数。因此匿名函数的用法有两个
回调函数
将一个函数作为另一个函数的参数使用,作为参数的函数称为回调函数
自调函数
函数调用自身(定义即调用函数)
回调函数
将一个函数作为另一个函数的参数使用,作为参数的函数称为回调函数
回调函数的优势:
- 匿名回调函数节省了全局命名空间
- 将私有的数据内容开放给指定位置使用(仅仅)
- 虽然可以使用私有数据,但不清楚来源一封装
1 | var n = function (w) { |
自调函数
自调函数就是自己调用自己。简单语法如下两种:
1 | // 国内常用方式 |
语法结构
第一个括号用于定义函数,第二个括号用于调用函数。
作用
用于执行一次性的逻辑任务
应用
作为整体逻辑代码的外层结构
作为值的函数
在函数的函数体中定义另一个函数 -> 内容(私有)函数
1 | // 作为值的函数 |
或者如下,返回一个函数
1 | function fn() { |
函数作为对象的方法
1 | var fn = function fn() { |
当函数作为对象的方法时,再次修改函数同样不会影响对象中已经赋值。
1 | var fn = function fn() { |
闭包
作用域链
作用域是一层一层向下传递的。
例如
1 | var a = "a"; |
闭包是什么
简单来说,闭包就是访问在全局范围内访问局部作用域的变量。
以下三种方式均可称为闭包。
1 | // 对象与函数 |
1 | // 函数与构造函数 |
1 | // 全局变量 |
回调函数不属于闭包。但加上参数可以改为闭包:
1 | function fn1(v) { |
闭包结构并不固定,但当内部函数以某一种方式被任何一个外部函数作用域访问时,就可以成为闭包
闭包的特点
局部变量
在函数中定义有共享意义(如:缓存、计数器等)的局部变量。(注:定义成全局变量会对外造成污染)
内部函数
在函数(f)中声明有内嵌函数,内嵌函数(g)对函数(f)中的局部变量进行访问。
外部使用
函数(f)向外返回此内嵌函数(g),外部可以通过此内嵌函数持有并访问声明在函数(f)中的局部变量,而此变量在外部是通过其他途径无法访问的。
闭包的作用
- 提供可共享的局部变量。
- 保护共享的局部变量。提供专门的读写变量的函数
- 避免全局污染。