函数
函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。这是一般得定义,简单翻译成正常人能听懂的话就是函数是一坨可以重复使用的实现内容定义的一系列动作的代码块,当被调用时就作出规定动作。
函数的语法
函数语法由关键字function
声明,后接函数名
加(参数)
代码块组成{ }
,如这就是一个简单的函数声明过程:
function test () {
doucument.write('abc')
}
这段代码定义了一个test的函数,功能就是当它被调用或触发时向页面打印abc。如此就实现了一个函数的定义,这种方式称为函数声明。函数还有另一种函数的定义方式——函数表达式,分为命名函数表达式和匿名函数表达式,注意函数表达式一般指匿名函数表达式,如:var test = function (){ }.
参数
函数的参数分为形参和实参,形参是函数被定义时在函数名后的括号内声明的参数,实参则是在调用时向函数传递的实际参数。注意形参与实参并不一定要个数相等,不需要严格一一对应。当实参的数量大于形参的数量时,实参会被函数内部的类数组——实参列表arguments保存。实参和实参列表有对应关系时是保持映射关系的(不是同一个),如以下情况,但是没有对应关系时就没有映射关系。
function sum(a, b) {
a = 2; //改变实参值
arguments[0] = 3; //改变实参列表第一项的值
console.log(arguments[0]);
}
sum(1);
函数的返回值
return
可以将函数执行的结果返回被调用的地方,同时停止函数的执行。
作用域
函数内部声明的变量只能在函数内部使用,称为局部变量。在函数外部声明的变量称为全局变量,他能被所有的函数使用。一般局部函数在函数执行完毕时即被“销毁”,因此在另外的函数中可以使用同样的变量名声明局部变量。
递归
例:使用函数实现阶乘的算法
- 找规律
- 找到出口(停止条件)
function mul(n) {
if(n < 0){
return '请输入正整数';
}
if(n == 1 || n == 0) {
return num = 1;
}
return n * mul(n - 1);
}
var num = mul(n);
递归是在函数中调用自己,递归的思想就是找到规律,并找到跳出条件即可。
预编译
JS执行三部曲
JS代码在浏览器执行的过程分为三步,分别为通篇语法分析、预编译、解释执行。语法分析就是指js引擎去判断检查你的代码是否存在语法错误,解释执行更不用多说,自然就是执行你的代码,然而重中之重的是预编译,预编译简单理解就是在内存中开辟一些空间,存放一些变量与函数
- 函数声明整体提升
- 变量 声明提升
预编译前奏
- imply global 暗示全局变量:即任何变量,如果未经声明就复制,那么此变量就为全局对象window所有。
- 一切声明的全局变量,全是window的属性。
预编译四部曲(函数执行前)
- 创建AO对象(Active Object)(执行期上下文)
- 查找函数形参及函数内变量声明,形参名及变量名作为AO对象的属性,值为undefined //变量 声明提升(值为undefined)
- 实参形参相统一,实参值赋予形参。
- 在函数体里面找函数声明,值赋予函数体
预编译(JS脚本执行前)
- 生成GO对象(Global Object)(全局执行期上下文)
- 查找全局变量声明(包括隐式全局变量声明,省略var声明),变量名作全局对象的属性,值为undefined
- 查找函数声明,函数名作为全局对象的属性,值为函数引用
*上一节提到的window实际上就是GO
作用域
- [[scope]]:每个JS函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供JS引擎存取,[[scope]]就是其中一个。[[scope]]指的就是我们所说的作用域,其中储存了运行期上下文的几何。
- 作用域链: [[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式连接,我们把这种链式连接叫做作用域链。
- 运行期上下文:当函数执行时(执行前一刻预编译环节),会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次被执行时对应的执行期上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文即被销毁。
- 查找变量:从作用域的顶端依次向下查找.