函数
概念
函数: 将具有独立功能的代码块整合命名的代码
作用: 减少页面代码 提高页面执行速度 页面结构更加清晰
使用:
\1. 事件处理函数: 元素.事件 = function(){}
function(){}--->函数
\2. 对象的方法:
var obj = {
abs: function(){} ---> 函数
}
\3. 封装复用
声明
函数: 由事件驱动的或者在有需要的时候被调用的代码块
注意: 函数只声明 没有任何效果
声明函数:
-
函数声明:
1.1 函数:
语法: function 函数名(){
函数体;
}
1.2 调用函数:
函数名();
fn(); function fn() { console.log(1); }; // fn(); // fn(); // fn(); // fn(); // fn();
-
字面量声明:
2.1 函数:
语法: var 变量名 = function(){
函数体;
}
2.2 调用函数:
函数名();
// fn1 is not a function: fn1不是一个函数 // fn1(); var fn1 = function () { console.log(2); }; // fn1();
注意
函数名和变量名在这里是一样, 命名规范一致的
区别: 函数声明的方式调用可以在声明之前或者之后, 字面量声明的方式调用只能在声明之后;
参数
当遇到不确定的值, 就需要抽取成形参, 在调用的时候, 不同数据传进去
形参: 形式参数, 写在函数function后面的()里, 用来接收实际传递过来的数据
类似变量, 命名规范和变量一致
实参: 实际传递过来的数据, 写在函数调用的()里
arguments:存在于每一个函数中, 是实参的集合
一般形参和实参一一对应
单个参数
// 单个参数 function sum(a) { // 求和 var s = 0; // 1 + 2 + 3 + 4 + ... + 100 for(var i = 1; i <= a; i++){ // s = s + i; s += i; } console.log(s); }; // 调用 sum(100); sum(1000); sum(2000);
多个参数
多个参数: 用,隔开
// 50-80 90-100 1000-10000 // 多个参数: 用,隔开 function sum1(start, end) { // 求和 var s = 0; // 1 + 2 + 3 + 4 + ... + 100 for(var i = start; i <= end; i++){ // s = s + i; s += i; } console.log(s); }; sum1(1, 100); sum1(50, 80);
arguments
如果参数个数不确定, 形参和实参干脆一个都不写, 直接使用arguments
arguments: 存在于每一个函数中, 是实参的集合
function sum2() { console.log(arguments); // 将arguments中的每个数据加起来 var s = 0; for(var i = 0; i < arguments.length; i++){ console.log(arguments[i]); s += arguments[i]; } console.log(s); } sum2(3,4,5,6,7,8); sum2(40,50,60);
形参和arguments的关系:
两者互相影响
function fn(a) { console.log(a, arguments); a = 50; console.log(a, arguments); arguments[0] = 100; console.log(a, arguments); }; fn(30);
函数问题
-
形参实参不一一对应:
形参 > 实参: 多余的形参就是undefined
实参 > 形参: 多余的实参不能通过形参获取
function fn(a, b) { console.log(a, b); }; fn(10); // a = 10 b = undefined fn(10, 20, 30); // a = 10 b = 20
-
函数重名:
函数名重名: 后面的覆盖前面的
函数和变量名重名: 变量覆盖函数
function a() { console.log('a'); } function a() { console.log('a1'); } a(); // a1 var b = 30; function b() { console.log('b'); } // b(); // b is not a function
-
函数封装
\1. 声明空函数
\2. 实现单个效果
\3. 调用
\4. 抽参
\5. 传参: 把谁抽出来 把谁传进去
function getOdd(a) { // 0--10 for(var i = 0; i <= a; i++){ // 偶数: 被2整除 取余等于0 if(i % 2 == 0){ console.log(i); } } } getOdd(10); getOdd(66); getOdd(100);
参数的数据类型
所有数据类型都可以做为参数
一般不用null和undefined作为参数
由于null好undefined不具有实际意义 所以一般不使用
function getType(a) { console.log(a, typeof a); } getType(10); getType('中公'); getType(true); getType(null); getType(undefined); var m = {a: 1}; getType(m); getType([1,2,3,4]); function fn() { console.log(1); } getType(fn);
作用域
作用: 读(获取)、写(设置)
域: 区域
作用域: 变量和函数被读写的区域
es5中 作用域通过函数来划分, 又叫做函数作用域
全局作用域: script标签下
全局变量、全局函数, 可以在整个js中被读写
局部作用域: function的{}里
在局部作用域中, 用var\function声明的变量和函数, 叫做局部变量、局部函数, 只在当前作用域起作用, 如果出了{} 会被销毁
// 全局作用域 var n = 10; // 全局变量 function fn() { // 全局函数 // 局部作用域 console.log(n); // 10 var z = 1; console.log(z); // 1 } fn(); console.log(z); // 报错
作用域链
作用域链: js的一种查找机制, 决定了变量和函数向上一级作用域查找的过程
查找过程: 先找自身作用域, 如果自身作用域有,直接返回, 如果自身没有,往上一级作用域查找, 直到到全局作用域,如果全局作用域也没有,报错: is not defined;
var n = 10; // 全局变量 function fn() { // 局部作用域 var z = 20; // 局部变量 console.log(n, z); } fn();
变量提升
js在解析代码的时候, 不是按照单纯的从上到下的顺序来执行
至少会执行两步:
\1. 预解析: 找var、function, 将var声明的变量的声明提到最前, function声明的函数整个存储在内存中
\2. 逐行解析: 从上到下的顺序一行行执行代码
函数的形参在函数被调用的第一行代码优先执行, 形参接收实参, 执行函数体
函数每调用形成一个新的局部作用域, 代码的解析过程遵循预解析过程
var
console.log(a); // undefined var a = 10; /* 解析过程: var a; console.log(a); a = 10; */
function
// function function sum() { console.log('函数1'); } console.log(sum); function sum() { console.log('函数2'); }; console.log(sum); /* 解析过程: function sum() { console.log('函数1'); } function sum() { console.log('函数2'); }; console.log(sum); 函数2 console.log(sum); 函数2 */
var和function
// var function 函数声明 字面量声明的区别 var fn = 'abc'; function fn() { console.log(1); } console.log(fn); /* 解析过程: var fn; function fn() { console.log(1); } fn = 'abc'; console.log(fn); abc */
形参
// 传参 // 函数的形参在函数被调用的第一行代码优先执行, 形参接收实参, 执行函数体 // 函数每调用形成一个新的局部作用域, 代码的解析过程遵循预解析过程 function fun(a) { console.log(a); var a = 30; console.log(a); }; fun(10); /* 解析过程: function fun(a) { console.log(a); var a = 30; console.log(a); 解析过程: var a;-->声明形参 var a; a = 10; ---> 接收实参 console.log(a); // 10 a = 30; console.log(a); // 30 }; fun(10); */
函数返回值
函数在执行的时候 就像一个小黑屋 里面的数据不能直接出来 如果想要出来需要越狱
函数的返回值: 每个函数执行后都会有返回值, 默认返回值 undefined
就是函数调用的结果
接收函数的返回值: var 变量 = 函数();
想要将函数内的数据 在函数外能使用 需要将函数内的数据设置成返回值返回回来
设置函数的返回值:
函数最后: return value;
接收返回值
function a() { console.log(1); } var b = a(); console.log(b);
设置返回值
// 设置返回值 function fn() { var mn = 20; return mn; } var q = fn(); console.log(q);
return作用
设置函数的返回值: 函数最后: return value;
return: 结束函数 return后面的代码不执行
function fn1() { console.log(1); return 'abc'; // 不执行 console.log(2); } var m = fn1(); console.log(m); // 'abc'
返回多个
return设置返回值的时候 一次只能返回一个数据 如果用,返回多个, 只会返回最后一个;
如果想要返回多个数据, 建议 数组 或者 对象, 更推荐用对象
function fn2() { // return 10, 20, 30; // return [10, 20, 30]; return { a: 10, b: 20, c: 30 }; } var mn = fn2(); console.log(mn);
使用情况:
\1. 封装函数 函数的最后去到的是一个数据
\2. 操作的对象 返回回来
\3. 函数内的数据 要在 函数外面用到的时候
返回值数据类型
返回值的数据类型可以是一切数据类型
function rType() { return function () { console.log(90); }; return {a: 1, b:2}; return [1,2,3,4]; return null; return true; return 30; return 'abc'; } var a = rType(); console.log(a);
封装步骤
\1. 实现单个效果
\2. 声明空函数
\3. 单个效果放在空函数里
\4. 调用
\5. 分析不确定的项, 抽取参数
\6. 传参
\7. 设置返回值
\8. 接收返回值
function getMax(data) { // 1. 假设最大值 var max = data[0]; // 2. 用这个值和数组的每一个值进行比较 for (var i = 1; i < data.length; i++) { // 如果比假设值大 if (max < data[i]) { max = data[i]; } } // console.log(max); return max; } var m = getMax(arr); console.log(m);