相关概念
-
函数——解耦的方式
-
最基本的函数写法 - 函数声明
-
命名建议:小驼峰
myFirstFun();
or 公司内部规范function test(param){ 函数执行语句; }
匿名函数表达式(函数字面量)
var test = function test1(){}
// 这种声明情况:
var test = function test1(){
var a = 1,
b = 2;
console.log(a,b); // 1,2
// test1(); 在函数内部调用,会无限次调用,递归,
// 电脑不好的谨慎尝试!
}
// 注意!
// test1(); 在函数外调用,是报错“is not defined” ,不可见
// 这个函数的名称可以被调取,是test1
console.log(test.name); // test1
-
这种声明,实际上,在将函数赋给变量test的时候,会忽略后面写的test1;所以是否写function后面的名称
test1
,在外部对函数test()
进行调用是没有影响的;没在 function 后面写函数名称的情况下,这个函数是属于匿名函数
// 匿名函数表达式 var test = function(){ var a = 1, b = 2; console.log(a,b); // 1,2 }
函数的形参和实参问题
-
函数形参的默认值为
undefined
-
隐形参数
arguments[]
-
隐形参数
arguments[]
与函数的第一个形参是有一定的对应关系的:当
arguments[0]
为 undefined,也就是没有传实参的值的时候,第一个形参有初始化值,不是undefined,形参就会使用初始化值;反之,有传实参值的时候,就是实参的值;通过代码来理解:
// 注意是ES6写法,ES5不支持,低版本浏览器不兼容 function test (a = 1, b){ console.log(a); console.log(b); } test(); // 1 undefined test(2); // 2 undefined test(undefined,2); // 1 2 // 不用上述ES6方法也可以实现 // 通过或运算实现 最推荐写 function test1 (a, b){ // 当没有传实参值的时候,arguments为undefined,形参的值就会是后面的那个值 var a = arguments[0] || 1; var b = arguments[1] || 2; console.log(a + b); } test1(); // 3 test1(3,4); // 7 // typeof 方法实现 function test2 (a, b){ // 相对复杂,但是易懂 let a,b; if(typeof(arguments[0]) !== 'undefiend'){ a = arguments[0]; }else { a = 1; } if(typeof(arguments[1]) !== 'undefiend'){ b = arguments[0]; }else { b = 2; } console.log(a + b); } test2(); // 3 test2(3,4); //7 // 三元运算实现 推荐 function test3 (a,b){ var a = typeof(arguments[0]) !== 'undefined' ? arguments[0] : 1; var b = typeof(arguments[1]) !== 'undefined' ? arguments[1] : 2; console.log(a + b); } test3(); // 3 test3(3,4); // 7
-
函数的形参和实参的个数可以不相等
console.log(函数名.length)
看形参个数console.log(arguments)
看实参情况
// 代码逻辑:一个函数被调用时,累加它的实参值 // 实参求和的类似题目!! function sum(){ var args = 0; for (var i = 0; i < arguments.length; i++){ args += arguments[i]; } console.log(args); } sum(1,2,3,4,5,6,11);
-
在函数内可以更改在调用时传入的实参的值;但是如果形参没有传入实参的值,在函数内部给形参赋值是没有意义的;
// 调用时传入实参 function test(a,b){ a = 3; console.log(arguments[0]); // 3 } test(1,2); // 传入形参a和b的值的情况 // 调用时没有传入实参 function test1(a,b){ b = 3; console.log(arguments[1]); // undefined } test1(1); // 仅仅传入形参a的值,b并没有传的情况
-
函数中,形参和实参他们所存储的位置不同,但形参和实参是有对应关系的
return
函数的返回值
-
对于普通函数,就算你没有在函数内写上 return,JS 引擎会在函数内部的最后隐式添加上
return undefined
;- return后面的语句不会被执行,而且return也可以返回一系列的数据;
- 对于构造函数,会默认
return this
;
function test(name){ return name || '您没有填写姓名!'; } console.log(test('greeny')); // greeny console.log(test()); // '您没有填写姓名!'
-
函数体内部可以访问 or 修改外部的变量,但是函数体外部不能访问内部的变量
a = 1; // 在全局声明、赋值变量 function test1(){ var b = 2; console.log(a,b); // 1 2 function test2(){ var c = 3; console.log(a,b,c); // 1 2 3 } test2(); console.log(c); // 报错 is not defined } //console.log(b,c); // 报错 is not defined test1(); // 1 2
-
递归问题
- 递归:总是走到出口时,才向上一步的返回结果
- 要使用递归解决问题,要注意:先:找到递归的计算规律,再:找出函数结束的出口
- 性能上不占优势,慎用;
// n的阶乘 不能用for循环 -> 递归实现 // n! = n * (n-1)! 规律 function fact(n){ if(n === 1){ return 1;// 此时return后出现值,会导致前面的队列发生变化 } return n * fact(n - 1);// 此时一直在等有一个值出现 } // n = 5 // fact(5) = 5* fact(4); ---> fact(5) = 5 * 24 = 120 ----> final result // fact(4) = 4* fact(3); ---> fact(4) = 4 * 6 = 24 // fact(3) = 3* fact(2); ---> fact(3) = 3 * 2 = 6 // fact(2) = 2* fact(1); ---> fact(1) = 1; --> fact(2)=2 * 1 =2; console.log(fact(5)); // 120
构造函数
系统自带的构造函数
var obj = new Object(); // 与对象字面量相等
obj.name = '张三';
obj.sex = '男士';
自定义构造函数
-
大驼峰,用于与普通函数区分
function Teacher(){ this.name = '张三'; this.sex = '男'; this.smoke = function(){ console.log('im smoking'); } } var teacher = new Teacher(); // 此时this才指向Teacher
this 的指向
在没有实例化构造函数对象的时候就指向window,否则在不同的实例化对象中,指向那个实例化的对象,而不是构造函数本身。
在代码中理解:
function Compute(){
var res = 0;
this.plus = function() {
loop(arguments,'add',res);
}
this.times = function() {
res = 1;
loop(arguments,'mul',res);
}
function loop(args,method,res){
for(var i = 0; i < args.length; i++){
var item = args[i]
if (method === 'add') {
res += item;
}else if (method === 'mul') {
res *= item;
}
}
console.log(res);
}
}
var compute = new Compute();
compute.plus(2,4,6); // 12
compute.times(3,5,7); // 105