## 复习: 第三天课程
1、数组创建方法 2种方法
答:1、var arr = new Array(); 使用 new Array 方法
答:2、var arr = [] 字面量方式
2、var arr = [1,2,3,4];说出什么是数组元素,什么是下标
答 :[1,2,3,4] 是数组元素 ,下标是序号0,1,2....开始的
3、如何获取数组的长度
答:length 就是数组的个数
4、如何遍历数组
答:for 从头到尾选择的for里面有个i 当索引号看
5、增加数组元素是如何实现的
答:数组名[索引号] = '值'
arr[0] = 123,
6、为什么需要函数
答:代码多次复用,多次调用
7、函数是怎么声明的和调用的
答:function 声明 使用 函数名加小括号 调用 function fn(){} fn();
8、function f(x,y){xxxx} f(1,3) 请说出那个是实参那个是形参
答:f(1,3)实参, f(x,y)是形参,x,y相当于变量
9、函数的返回值,是返回给谁的?
答:return 谁调用return 返回给谁
## 今天全天都讲函数:就是这么多 对我来说都很重要
### 每个练习题我会详细讲到每个步骤
1、函数练习
2、函数参数和返回值注意事项
3、arguments 的使用
4、定义函数的两种方式
5、自执行函数
6、函数也是一种数据类型 function
7、函数可以作为参数
8、函数可以作为返回值
9、作用域
10、作用域链
11、预解析
## 1、练习
1、函数 封装 翻转数组
思路:
1、翻转数组,返回一个新数组
2、把内容封装到函数里面去reverse 反转 reverse记住后面有个方法
//这里的arr 是形参
function reverse(arr){
// 新数组接收方
var newArr = [];
// 遍历循环
for(var i=0; i<arr.length;i++){
// 接收方 旧数组长度 - i-1,每次循环都给一次
newArr[i] = arr[arr.length-i-1];
}
// 谁调用给谁,不然就会undefined
return newArr;
}
//把数组要传输到函数里面通过 形参 参数 传递
var arr = [1,2,3,4,5]; //这个arr 是数组名
reverse(arr); //函数调用是 实参
// 打印数组 翻转成功
console.log(reverse(arr));
// 第二种数组传参方法
console.log(reverse(['red','pink','green']));
2、函数 封装冒泡
//冒泡 需要两个for 循环 外层 for 需要趟数 长度减去 1
// 里层的for 循环 管交换次数 长度 减去 i 减去 1
// 交换2个值
// 后面会学到sort 算法
function sort(arr){
for(var i=0; i<arr.length-1;i++){
for(var j=0; j<arr.length-i-1;j++){
// 比较 arr[j] 是0 开始比较
if(arr[j] < arr[j+1]){
var temp = arr[j]; //保存第一个
arr[j] = arr[j+1]; //第二个给第一个
arr[j+1] = temp;
}
}
}
// return 出去
return arr;
}
var arr = [1,3,5,7,8,10];
console.log(sort(arr))
3、函数 封装闰年
//函数 需要接受的年份,能被4这整除 并且不能被100整除,或者能被400 整除
function isRun(year){
// 这里的flag 一个变量来控制 用来存储 是不是闰年的
var flag = false; //刚开始默认的就是false 默认的是 平年 flag 是开关
// 你这里的条件是不是闰年啊?
if(year % 4 === 0 && year % 100 !==0 || year % 400 ===0 ){
//是true 就会覆盖掉了,flag 里面存储的要么是true要不就是false
flag = true;
}
// 然后return 出去
return flag
}
console.log(isRun(2019));
4、计算2019年2月15日是一年中的第几天
这个案例的核心就函数可以调用函数
//获得天数的函数
function getDays(year,month,day){
// days 存储的总天数,
// day先存储当月的天数
// var days = 0;
// days += day;
var days = day
// 月份有很多我们需要for 循环,详细介绍当月天数只能从 1月份开始,小于你输入的天数
for(var i=1; i<month; i++){
switch (i) {
case 1 :
case 3 :
case 5 :
case 7 :
case 8 :
case 10 :
case 12 :
days += 31;
break;
case 4:
case 6:
case 9:
case 11:
days +=30;
break;
case 2:
// 如果是闰年 +=29年
// 否则是平年 +=28天
// 在函数里面右调用了一个函数
if(getRun(year)){
days+=29;
}else {
days+=28;
}
break;
}
}
// 先return days
return days
}
console.log(getDays(2018,2,15));
// 这里我们拿到之前写的函数 进行平年润年的判断
function getRun(year){
var flag = false;
if(year % 4 === 0 && year % 100 !==0 ||year % 400 === 0){
flag = true
}
return flag;
}
思路:
1、输入某年某月某日判断这一天是这一年的第几天
2、比如要输入年份,因为有闰年和平年,也要区分开
3、月份不一样 有的是30天 有的是31天
4、先算当月的天数
5、前面几个月的总天数 + 不断的相加 for 循环
## 斐波那契额数列:1,1,2,3,5,8,13,21
会发现处理第一个和第二个之外 后面第三个都是前一个数字相加
//思路就是
var n1 = 1;
var n2 = 1;
var n3 = 0;
// n3 = n1 + n2 等出来的
for(var i=3; i<= 9; i++){
// 第一轮求出n3
n3 = n1 + n2;
// n1等于1
n1 = n2;
// n2 是 2
n2 = n3
// 正好是下一轮的 n1+n2
}
看图来操作:n1 正好是1 n2 也是1 n3是n1+n2的结果
![](https://user-gold-cdn.xitu.io/2019/2/17/168fa2a11b557f6c?w=932&h=584&f=png&s=55244)
封装斐波那契数列 :
function getFei(num){
var n1 = 1;
var n2 = 1;
var n3 = 0;
for(var i=3; i<=num;i++){
n3 = n1 + n2;
n1 = n2;
n2 = n3;
}
return n3;
}
console.log(getFei(9));
详细解释:
前面两项相加得到第三项
所有我们需要 三个变量 n1 + n2 = n3;
var n1 = 1;
var n2 = 1;
var n3 = 0;
问的是第 n 个 88 个? 循环 i就是几个 循环几次
for(var i= 3; i<=9; i++){
n3 是 第n个数的数字 多少
m3 = n1 + n2;
n1 = n2 ;
n2 = n3;
}
console.log(9)
## 函数参数和返回值注意事项
function fn(){
return 555;
}
// 函数调用返回函数值 555 函数名+ 括号 调用函数 执行函数
console.log(fn());
// 打印出函数的 本身 函数名 输出的函数本身
console.log(fn);
这里为了arguments 参数 铺垫 请看好
function funn(){
}
// 如果函数没有返回值 返回undefined 没有return
console.log(funn());
function getSum(x,y,z){
return x + y + z;
}
console.log(getSum(1,2,3)); //6
console.log(getSum(1,2,3,6));//6
console.log(getSum(1,2));//NaN 1+ 2 + undefined = NaN
// undefined + 任何数值 都是NaN 除了字符串
// 疑问? 用户要是想输入多少是多少怎么办呢? 使用arguments 的使用
## 疑问? 用户要是想输入多少是多少怎么办呢? 使用arguments 的使用
arguments 的使用
js中arguments 对象是比较特别的一个对象,实际上是当前函数的内置属性,也就是伙食所有函数都内置了一个
arguments对象 arguments 对象中存储了传递的所有的实参,arguments是一个伪数组
### arguments 对象中存储了传递的所有的实参
function getSum() {
// 可以接受 传递过来的所有的 实参
// arguments 是一个伪数组
console.log(arguments);
// 存储形式 伪数组
// 遍历数组 可以把值取出来
}
getSum(1,2,3,1,2,3);
案例: 可以求任意数值的和
function getSum(){
var sum = 0;
for(var i=0; i<arguments.length;i++){
sum += arguments[i];
}
return sum;
}
console.log(getSum(1,2,3));
案例:求任意数的最大值
function gemMax(){
var max = arguments[0];
console.log(max);//1
for(var i=0;i<arguments.length; i++){
if(max < arguments[i]){
max = arguments[i];
}
}
return max;
}
console.log(gemMax(1,2,3,4,5,));
## 函数的定义撒三种方式
定义函数的3中方式
1、声明函数 命名函数
function fn(){
}
fn();
答:实际工作使用多
2、函数表达式 匿名函数
var fun = function(){};
答:Dom操作的时候使用较多
3、自执行 函数
答:匿名函数除了 作为参数传递外,也可以作为启动函数,定以后立即执行,为了防止变量污染
匿名 函数自执行函数,最大的好处,就是防止命名冲突 后面会讲
函数不调用不执行,但是自执行函数自己调用自己
(function (){
}) ();
## 函数作为参数使用
解答:函数可以接受任何类型的数据作为参数,数值,字符甚至是函数类型
var fn = function(){
console.log('这里是一个函数');
}
// 声明
function fun(x){
console.log(x);
x();
}
// 调用
fun(fn);
## 函数 可以作为返回值
/*
function fn(){} //声明函数
console.log(fn); //输出整个函数 代码
console.log(fn()) //fn()调用函数 执行函数
function fn(){
retrun 666;
}
console.log(fn(666)); //返回值 666
*/
function fn(){
//返回的是一个函数
return function (){
console.log('返回这里的函数');
}
}
// console.log(fn()); function (){console.log('返回这里的函数')};
var ff = fn(); //function (){console.log('返回这里的函数')};
ff();
//console.log(ff); //function (){console.log('返回这里的函数')};
## 作用域
答: 作用域: 变量可以起作用的范围
全局变量和局部变量
全局作用域
供所有代码执行的环境整个Script 标签内部 或者一个独立的js 文件中
局部作用域
在调用函数的时候 会形参一个执行函数内代码的新环境
全局变量
在全局作用域下声明的变量叫做全局变量
全局变量在代码任何位置都可以使用
局部变量
在局部作用域下声明的变量叫做局部变量
局部变量只能在该函数内部使用
//全局作用域
//num 就是一个全局 变量
var num = 10;
console.log(num);
//在function 里面写的是 局部作用域
function fun(){
//str 在 局部内写的是局部变量
var str = '';
//全局变量可以全局使用
console.log(num);
}
fun()//进行调用
console.log(str);
注意 : 函数的形参实际上就是局部变量
局部变量当其所在的代码块被执行时候,会被初始化,当代码块运行结束后,就被销毁了,节省内存空间
全局变量因为任何一个地方都可以使用,只有在浏览器关闭才会销毁,比较占内存
## 作用域链:
只要是代码,就至少有一个作用域
写在函数外部的就全局作用域
写在函数内部的就是局部作用域
如果函数中还有函数,那么在这个作用域中就又诞生一个作用域
根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
练习题:
function f1(){
function f2(){
}
}
var num = 123;
function f3(){
function f4(){
}
}
// 解答: f1 和 num f3 是属于 零级链 就是最牛的那个 相当于盘古
案例:
function f1(){
var num = 123;
function f2(){
console.log(num);
}
f2();
}
var num = 456;
f1();
// 案例
function f1(){
// var num = 123;
function f2(){
console.log(num);
}
f2();
}
// var num = 456;
var num;
f1();
// 解答: 零级链 f1 和num 是零级链
// f1里面的 num 和 f2 是一级链
// console.log(num) 是 二级链
// 假设如果 我们一级链 里面没有找到 123
就会继续冒泡向上查找 找到 456 如果还没有就会undefined
练习题: 答案 留在 评论 写:作用域练习题1与2的答案即可。
var a = 1;
function f1(){
var a = 2;
var b = '2b';
function f2(){
var a = 3;
function f3(){
var a = 4;
console.log(a); //a 的值 4
console.log(b); //b 的值 '2b';
}
f3();
}
f2()
}
f1();
练习题2:
var a = 1;
function f1(){
var a = 2;
var b = '2b';
function f2(){
var a = 3;
function f3(){
var a = 4;
console.log(a); //a 的值 4
console.log(b); //b 的值 '2b';
}
}
}
## 预解析 重要
/*
// console.log(num); //打印出什么 num is not defined 未定义
var num ;
console.log(num); // undefined 声明变量未给值
var num = 10;
console.log(num) //输出 10
console.log(num); // 请问 预解析 这里输出是undefined
var num = 10;
fun(); //函数调用把下面的注释了,在上面输出你会发现什么 下面也会打印出来
function fun(){
console.log('人啊不能偷懒');
}
//fun(); 函数调用
*/
js 解析器 就是js 引擎
解答:javascript代码是由浏览器中的js 解析器来执行的,js解析器在运行js代码的时候,分为两步预解析和代码执行
为什么学习预解析?
答:学习了预解析能够让我们知道为什么在变量声明之前访问变量,值是undefined 为什么 在函数声明之前就可以调用函数
预解析过程:
1、js解析器会在全局环境下查找 var function 关键字,变量只声明不赋值,函数声明不调用
2、预解析只发生在当前作用域下
预解析也叫做变量,函数提升
1、变量提升:定义变量的时候,变量的声明会被提升到当前作用域的最上面啊,变量的赋值不会提升
2、函数提升:js解析器首先会把当前作用的函数声明提前到整个作用域的最前面
优先等级:变量名和函数名相同,有限执行函数 重点
执行过程:
变量赋值,函数调用,表达式运算等等
上面题讲解:
console.log(num);
var num = 10;
解答: 这里为什么 会打印出undefined 是因为 变量提升,变成了
var num;
console.log(num);
num = 10; 变量的赋值不会提升也就说没有把10赋值给num 声明变量未给值
上面题讲解:
fn();
function fn(){
}
// 为什么 这么写没问题呢?
// 因为js 预解析 会把我们函数 提升回来 请看
function fn(){
// 预解析的功劳 提升回来了,但是变量的声明会被提前,但是值并不会
// 所以这里就变成了声明变量未给值 so undefined 了 函数是整体的函数声明所以提前了
}
fn();
预解析练习题:
到时候把答案 写在 留言区吧
格式: 预解析练习题- 1- 答案
题目1、
alert(a);
alert(fn);
var a =1;
function fn(){
return false;
}
题目2、
alert(a);
var a = 1;
alert(a);
function a(){
return false;
}
解答提示:变量名 和函数名 相同的情况
题目3、
var num = 10;
fun();
function fun(){
console.log(num);
var num = 20;
}
题目4、
var num = 10;
fn();
function fn(){
console.log(num);
var num = 20;
console.log(num);
}
题目5、
var a = 10;
f1();
function f1(){
var b = 20;
console.log(a);
console.log(b);
var a = '123';
}
## 全局变量的特殊形式
var num =10; //全局变量
function fun (){
var n = 20; //局部变量
str = 'jack'; //str 放在局部作用域中,全局变量的特殊形式,在局部作用域内声明,但是没写var 当全局变量看
}
fun(); //记着调用
console.log(str);
题目6、
f1()
console.log(c)
console.log(b)
console.log(a)
function f1(){
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
## 问答:
问答:
1、函数形参和实参个数 可以不匹配
答:可以不匹配,但是没什么用
2、arguments 参数什么时候用
答:我们不知道接收多少参数的时候用arguments,存储方式和数组 一样 被称为伪数组
3、定义函数有那2种方式
答: 函数表达式var a = function(){} 和函数 声明 function fn(){}
4、js 变量安卓作用域,分为哪两种变量
答:全局变量 和局部变量 ,局部变量外面不能用,在局部内没有使用var 的是全局变量
5、js 解释器 运行js 分为 那两步
答:预解析 和代码执行 ,先把 变量 和函数 提升 然后开始运行, 预解析 提升到当前作用域,什么叫做当前作用域就是就是函数内部的 提升到函数内部