1. Function的介绍
创建函数的方式
code block:
+ : 声明式
function foo() {
console.log(arguments);
}
foo(1, 2, "3", {name:'jerry'});
+ : 表达式
var foo = function() {
console.log(arguments);
};
foo(1, 2, "3", {name:'jerry'}, true);
+ : 构造函数:
Function(arg1, arg2, ...,argN ,body)所有的参数类型均为 字符串;
arg1, arg2, ...,argN 为可选的参数列表,表示 为 生成函数的形参列表;
body 为必选参数,表示为 生成函数的 函数体部分。
var foo = new Function('val1', 'val2', 'return val1 + val2;');
- 由于函数也可以通过Function构造函数来创建,那么函数也是对象;具有proto属性
2. 相关结论:
1. 所有的函数都是Function实例。
1 2 3 4 5 6 7
| console.log(Object.constructor); console.log(Array.constructor); console.log(Date.constructor); console.log(RegExp.constructor); var foo = function() {}; console.log(foo.constructor);
|
2. 所有的函数的构造函数为Function;
1 2 3 4 5
| console.log(foo.__proto__ === Function.prototype); console.log(Object.__proto__ === Function.prototype); console.log(Array.__proto__ === Function.prototype); console.log(Date.__proto__ === Function.prototype); console.log(RegExp.__proto__ === Function.prototype);
|
3. 所有的函数的原型对象 为 Function.prototype.
1 2 3 4
| console.log( Function.prototype.__proto__ === Object.prototype ); console.log( typeof Function.prototype ); console.log(Function.prototype.prototype); // Array -> Function.prototype -> Object.prototype -> null
|
3. 小结
将函数 称为 函数对象
其他对象 称为 普通对象
4. 绘制函数的原型链
5. arguments对象属性(这是一个类数组,保存着的是这个)
1> : length 实参的个数
2>:callee 返回正在执行的函数; 应用在匿名函数递归调用
1 2 3 4 5 6 7 8 9 10
| var v = (function (n) { if (n < 1) { return undefined; } else if (n === 1 || n === 2) { return 1; } else { return arguments.callee(n - 1) + arguments.callee(n - 2); } }(8)); console.log(v);
|
6. 函数相关属性
1>:caller 返回调用当前函数的函数
2>: length 形参的个数
3>: name 存储函数的名字
7. 模拟函数重载
在js中,没有函数重载,只能通过arguments对象进行模拟
// 如果函数没有传递实参,就直接打印false;
// 如果传递一个实参,就将其直接打印出来;
// 如果传递两个实参,就将两个实参拼接起来,在打印出来;
// 如果传递一个实参并且类型为 数字的话,就加1,在打印。
function foo() {
if(arguments.length === 0){
console.log(false);
} else if(arguments.length === 1){
if(typeof arguments[0] === 'number'){
console.log(arguments[0] + 1);
} else {
console.log(arguments[0]);
}
} else if(arguments.length === 2){
console.log(arguments[0] + '' + arguments[1]);
}
}
foo();
foo(1);
foo("JQK");
foo('A', '2');
8. 函数递归:
1> 概念:函数调用自身
2> 经典递归案例
a: 等差数列第n项值
b: fibonacci数列第n项值
var v = (function (n) {
if (n < 1) {
return undefined;
} else if (n === 1 || n === 2) {
return 1;
} else {
return arguments.callee(n - 1) + arguments.callee(n - 2);
}
}(8));
console.log(v);
9. 词法作用域: 规定变量的作用域是由变量声明的位置决定,而不是由使用变量的位置决定。
在词法作用域中,只有函数可以分割作用域。在函数内部是一个完整作用域。与外界隔离
也就是,在函数内部可以访问函数外部的数据;但是函数外部无法访问内部的数据。
10. 变量名(函数名)提升
在js预解析阶段执行的操作。
js本身是边解析边执行的。
11. 在预解析阶段:
首先,分析代码语法,如果有语法错误,就直接抛出异常。
其次,将变量名以及函数声明提升 到当前作用域最顶端。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var a; if( 'a' in window ) a = 10; } else a = 20; } console.log(a); var a = 10; if( a in window ) a = 10; } else a = 20; } console.log(a);
|
12. in运算符
1》 规则:前面的属性名字,要用字符串来表示;如果为变量,那么会将变量的值隐式转换成字符串,然后去判断变量的值是否为指定对象的属性(可以为继承过来的属性)。
2》注意: 后面的参数必须为对象;否则报错。