前端零基础 JS 教学 第四天 04 - day 函数 重点啊重点

## 复习: 第三天课程

    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 分为 那两步

答:预解析 和代码执行 ,先把 变量 和函数 提升 然后开始运行, 预解析 提升到当前作用域,什么叫做当前作用域就是就是函数内部的 提升到函数内部

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些阅读 2,028评论 0 2
  • 如何控制alert中的换行?\n alert(“p\np”); 请编写一个JavaScript函数 parseQu...
    heyunqiang99阅读 1,084评论 0 6
  • 单例模式 适用场景:可能会在场景中使用到对象,但只有一个实例,加载时并不主动创建,需要时才创建 最常见的单例模式,...
    Obeing阅读 2,058评论 1 10
  • 一、数组 数组是一个有序列表,所以有下标. 并且数组在js中可以存在任意类型的数据.并且同一个数组中可以存放不同的...
    空谷悠阅读 506评论 0 1
  • 1、基本常识 浏览器的组成:1)shell部分 2)内核部分:(1)渲染引擎(语法规则...
    MrLsss阅读 327评论 0 4