函数
定义
- 函数声明
function 函数名() {} //定义函数
函数名(); //执行函数
函数名 / 变量名中, 多个单词拼接时, 第一个单词首字母小写, 第二个单词及后面的单词首字母大写
- 函数表达式
var 变量名 = function 函数名() {} // 命名函数表达式
var 变量名 = function () {} //匿名函数表达式, 函数名为变量名, 更常用, 直接称为函数表达式
函数名();
只有表达式才能被执行符号执行; 能被执行符号执行的函数表达式, 函数的名字会被自动忽略 (变为立即执行函数).
组成形式
-
函数名称
-
参数
- 形式参数
function sum(a,b){
var c = a + b;
document.write(c);
}
- 实际参数
sum(1,2);
形参与实参个数不一时不报错, 实参会被自动列入arguments[]形成实参列表(数组)
- 返回值
终止函数, 不写时默认在函数最后, return;
后面的函数不执行.
function sum(){
return 123;
}
var num = sum(); //返回123
作用域
作用域定义: 变量 (变量作用域又称上下文) 和函数生效 (能被访问) 的区域.
全局变量和局部变量: 定义在函数外的变量问全局变量, 定义在函数内的变量为局部变量.
1.里层可以访问外层的变量, 外层不能访问里层的变量.
2.彼此独立的函数不可以互相访问变量.
3.全局变量都可以被访问.
[[scope]]
: 每个JavaScript函数都是一个对象,对象中有些属性我们可以访问, 但有些不可以, 这些属性仅提供JavaScript引擎存取, [[scope]]就是其中一个.
[[scope]]
指的就是我们所说的作用域, 其中存储了执行期上下文的集合.
作用域链: [[scope]]
中所存储的执行期上下文对象的集合, 这个集合程链式链接, 我们把这种链式链接叫做作用域链.
执行期上下文: 当函数执行时, 会创建一个称为执行期上下文的内部对象.一个执行期上下文定义了一个函数执行时的环境, 函数每次执行时对应的执行上下文都是独一无二的, 所以多次调用一个函数会导致创建多个执行上下文, 当函数执行完毕, 它所产生的执行上下文被销毁.
查找变量: 从作用域链的顶端依次向下查找.
递归
- 找规律
- 找出口
立即执行函数
定义: 此类函数没有声明, 再一次执行过后即释放. 适合做初始化工作.
(function (){}());
w3c建议
(function (){})();
(function abc() {
var a = 123;
var b = 234;
console.log(a + b);
}())
(function (a,b,c) {
console.log(a + b + c * 2);
}(1,2,3))
// !/+/-
! function test() {
console.log('a');
}();
//执行一次后再次查找会报错
function (a, b, c){
console.log('a');
}();
//报错
function (a, b, c){
console.log('a');
}(1, 2, 3);
//不报错也不执行
js运行三部曲
语法分析 (语义分析)
通篇扫描但不执行
预编译
预编译发生在函数执行的前一刻
特点:
- 函数声明整体提升
函数声明整体永远提升到最前面
- 变量 声明提升
变量的声明永远提升到最前面, 但赋值不提升
预编译前奏
- imply global 暗示全局变量: 及任何变量, 如果变量未经声明就赋值, 此变量就为全局对象(window)所有.
a = 10;
window.a = 10;
console.log(a) = undefined;
var a = b = 123;
window.b = 123; //b未经声明存于window中
window.a = undefined;
- 一切声明的全局变量, 全是window的属性.
var a = 123;
window.a = 123;
function text(){
var a = 123;
}
text();
window.a = undefined;
window就是全局
四部曲
- 创建AO对象 Activation Object (执行期上下文)
全局为GO对象 Global Object
-
找形参和变量声明, 将变量和形参名作为AO属性名, 值为undefined
-
将实参值和形参统一
-
在函数体里面找函数声明, 值赋予函数体
解释执行
执行代码
闭包
当内部函数被保存到外部时, 将会生成闭包. 闭包会导致原有作用域链不释放, 造成内存泄露.
重要示例:
function test() {
var arr = [];
for(var i = 0; i < 10; i ++){
arr[i] = function () {
document.write(i + " ");
}
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j++) {
myArr[j]();
}
//输出: 10 10 10 10 10 10 10 10 10 10
function test() {
var arr = [];
for(var i = 0; i < 10; i ++) {
(function (j) {
arr[j] = function () {
document.write(j + " ");
}
}(i));
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j ++) {
myArr[j]();
}
//输出: 0 1 2 3 4 5 6 7 8 9
闭包的作用
- 实现公有变量
- 函数累加器
var count = 0;
function test() {
count ++;
console.log(count);
}
test(); // -- 1;
test(); // -- 2;
test(); // -- 3;
test(); // -- 4;
function add() {
var num = 0;
function a() {
console.log(++num);
}
return a;
}
var myAdd = add();
myAdd(); // -- 1;
myAdd(); // -- 2;
myAdd(); // -- 3;
- 可以做缓存 (存储结构)
function test() {
var food = "apple";
var obj = {
eatFood : function () {
if(food != "") {
console.log("I am eating " + food);
food = "";
}else {
console.log("There is nothing!");
}
},
pushFood : function (myFood) {
food = myFood;
}
}
return obj;
}
var person = test();
person.eatFood(); // -- I am eating apple
person.eatFood(); // -- There is nothing!
person.pushFood('banana');
person.eatFood(); // -- I am eating banana
-
可以实现封装, 属性私有化
-
模块化开发, 防止污染全局变量.