函数
- 函数声明:function 函数名(参数){函数体;}
- 函数表达式:var 函数名=function(参数){函数体;}
//命名函数表达式定义函数,但是此时只有test表示的是这个函数,abc不是。
var test = function abc() {
alert('hello world');
}
//匿名函数表达式定义函数 --> 一般说函数表达式指的是这个
var test2 = function () {
alert('hello world');
}
console.log(test.name); //abc
console.log(test2.name); //test2
- 命名规则:小驼峰
function theFirstFunc() {
alert('hello world');
}
//和java、c++输出地址不同,js输出函数体
document.write(theFirstFunc); //function theFirstFunc(){ alert('hello world'); }
- 形参实参:形参实参传递的个数可以不同,函数会从第一个形参开始往后依次匹配
var test = function (a, b, c) {
console.log('a:' + a + ' b:' + b + ' c:' + c);
console.log(arguments); //arguments -->实参列表
console.log(test.length); //test.length --> 形参的长度
}
test(1, 2); //a:1 b:2 c:undefined
//Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//3
test(1, 2, 3, 4); //14 a:1 b:2 c:3
//Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//3
//实参a和arguments[0]虽然不是指向同一块地址,
//但是存在映射关系,一个发生变化另一个就会跟着变化
var test = function (a, b) {
console.log(a);//1
a = 10;
console.log(arguments[0]);//10
arguments[0] = 2;
console.log(a);//2
}
test(1, 1);
//但是如果实参没有传递,就不会存在映射
var test = function (a, b) {
console.log(b);//undefined
b = 10;
console.log(arguments[1]);//undefined
arguments[1] = 2;
console.log(b);//10
}
test(1);
- 变量作用域:
定义:变量(变量作用又称上下文)和函数生效(能被访问)的区域
在<script>标签里面定义的变量为全局变量,在函数里面定义的为局部变量,函数里面可以访问全局变量。
var a = 1;
function test() {
var b = 2;
console.log(a); //1
}
test();
console.log(b);//b is not defined
递归
- 找到规律
- 找到结束条件
- 简单应用:求阶乘、求费伯纳西数列
预编译
js执行步骤
- 语法分析
- 预编译
- 解释执行
预编译规则
- 函数声明整体提升:函数声明会被提升到逻辑的最前面
test();//test
function test(){
console.log('test');
}
- 变量 声明提升:即变量的声明会被提升到逻辑的最前面,但是变量赋值不会
//如果直接打印一个未声明的变量就会报错
console.log(a);//a is not defined
//但是如果在其他地方给出声明就不会报错
console.log(a);//undefined
var a = 10;
- imply global暗示全局变量:即任何变量,如果未经声明就赋值,此变量就为全局对象(window)所有
a = 10;
console.log(a); //10
console.log(window.a); //10
- 一切声明的全局变量,全是window的属性 --> window就是全局的域
var a = 10;
// 在全局访问a其实就是访问window.a
console.log(window.a); //10
例子:
function test() {
//由于赋值操作的顺序为从右向左,在给b赋值的时候b还未声明,所以b被提升为全局对象
var a = b = 10;
}
test();
console.log(window.a);// undefined
console.log(window.b);// 10
函数预编译详解:
function fn(a) {
console.log(a); //ƒ a() {}
var a = 123;
console.log(a); //123
function a() {};
console.log(a); //123
var b = function () {}
console.log(b); //ƒ () {}
}
fn(1);
// 函数预编译发生在函数执行的前一刻
// 1. 创建AO对象
// AO{}
// 2. 找到形参和变量声明,将变量和形参名作为AO属性名,值为undefined
// AO{
// a:undefined
// }
// 3. 将实参值和形参统一
// AO{
// a:1
// }
// 4. 在函数体里面找函数和变量声明,值赋予函数体
// AO{
// a:ƒuncrion a() {},
// b:undefined
// }
// 5. 函数执行
全局预编译详解:
console.log(a);//ƒ a(){}
function a(){}
var a=100;
// 全局预编译发生在全局执行的前一刻
// 1. 创建GO对象(GO === window)
// GO {}
// 2. 找到变量声明,将变量名作为AO属性名,值为undefined
// GO{
// a:undefined
// }
// 3. 在全局找函数声明,值赋予GO中属性
// GO{
// a:function a(){}
// }
练习:
global = 100;
function fn() {
console.log(global);// undefined
global = 200;
console.log(global);// 200
var global = 300;
}
fn();
console.log(global);//100
var global;
// 1. 创建GO对象,找到变量声明和函数表达式
// GO{
// global:undefined,
// fn:function fn(){...}
// }
// 2. 开始解析执行 执行到global=100的时候
// GO{
// global:100,
// fn:function fn(){...}
// }
// 3. 然后开始执行fn(),创建AO对象,找到变量声明和函数表达式
// AO{
// global:undefined
// }
// 4. 开始执行函数,打印global,此时为undefined,然后再给global赋值,此时:
// AO{
// global:200
// }
// 5. 再打印global,它的值为200
// 6. 函数执行完毕再次打印global为AO对象中的global,为100
function test() {
console.log(b);// undefined
if (a) {
var b = 100;
}
console.log(b);// undefined
c = 234;
console.log(c);// 234
}
var a;
test();
a = 10;
console.log(c);// 234
//和上面的例子一样,只不过需要注意的是不要受到if(a){var b = 100;}的干扰,只要是在函数中的变量都会被提升为AO对象里面的属性,此处的b同样会被提升。