JavaScript函数

什么是函数

函数是专门用于封装代码的,函数是一段可以随时被反复执行的代码

  • 函数的格式
function 函数名称(形参列表) {
       封装的代码
}

使用函数的优点:

  1. 减少冗余代码
  2. 变更需求,修改的代码变少
  • 一个函数可以有返回值也可以没有返回值
  • 函数没有通过return明确返回值, 默认返回undefined
  • return的作用和break相似, 所以return后面不能编写任何语句(永远执行不到)
  • 调用函数时实参的个数和形参的个数可以不相同
    实参个数少于形参个数,那么剩下的形参的值就是undefined
    形参的个数少于实参的个数,那么多余的实参就直接忽略
  • JavaScript中的函数和数组一样, 都是引用数据类型(对象类型)

arguments函数

  • 作用
    保存所有传递给函数的实参,每个函数中都有arguments
  • arguments的 用法和数组一样 并且只能在函数内部使用

函数扩展运算符

扩展运算符在函数的形参列表中的作用:
将传递给函数的所有实参打包到一个数组中
注意点: 扩展运算符依然只能写在形参列表的最后

function test(a,...b){
     console.log(a);//结果为 1
     console.log(b);//结果为 [2,3,4,5]
}
test(1,2,3,4,5);

函数形参的默认值

在ES6之前可以通过逻辑运算符来给形参指定默认值
格式: 条件A || 条件B
如果条件A成立, 那么就返回条件A
如果条件A不成立, 无论条件B是否成立, 都会返回条件B

function test(a,b) {
   a = a || 666;
   b = b || 888;
console.log(a);
     console.log(b);
}
test();//结果为666 888
test(1,2);//结果为 1  2

ES6之后可以直接在形参后面通过=指定默认值
注意点: ES6开始的默认值还可以从其它的函数中获取

function test(a = 666,b = 888) {
console.log(a);
     console.log(b);
}
test();//结果为666 888
test(1,2);//结果为 1  2
let fn = function say(){
    return "我是函数"
}
function test(a = 666,b = fn()) {//通过其他函数获取默认值
console.log(a);
     console.log(b);
}
test();//结果为666 我是函数
test(1,2);//结果为 1  2

函数作为参数和返回值

将函数作为其他函数的参数

let  say = function (){
    console.log( "我是函数");
}
function test(fn) {
   fn();
}
test(say);//结果 我是函数

将函数作为其他函数的返回值
注意点: 在其它编程语言中函数是不可以嵌套定义的,
但是在JavaScript中函数是可以嵌套定义的

let  say = function (){
    console.log( "我是函数作为返回值");
}

function test() {
       
    return say;
}
let fn = test();
 fn();   //结果   我是函数作为返回值

匿名函数

没有名称的函数被称为匿名函数
注意 匿名函数不能只定义不使用,会报错

 function (){  //匿名函数的格式   
    代码;
}   //匿名函数不能只定义不使用,会报错

匿名函数的用法

  1. 匿名函数作为参数
   function test(fn) {
            fn();
        }
        test(function (){
            console.log( "我是函数");
        }); //结果为   我是函数
  1. 匿名函数作为返回值
function test() {   
    return function (){
            console.log( "我是匿名函数作为返回值");
        };
}
let fn = test();
 fn();   //结果   我是匿名函数作为返回值
  1. 匿名函数作为一个立即执行的函数
(function (){
            console.log( "我被立即执行了");
        }) (); //结果   我被立即执行了

注意点: 如果想让匿名函数立即执行, 那么必须使用()将匿名包裹起来才可以

箭头函数

箭头函数是ES6中新增的定义函数的方法
格式为
let 函数名称 = (形参) => {
代码块;
}

let  say =  (name) =>{
    console.log( "我是箭头函数"+name);
}
say("ns"); //结果  我是箭头函数ns

注意 如果只有一个形参,那么形参外面的括号可以省略

let  say =  name =>{
    console.log( "我是箭头函数"+name);
}
say("ns"); //结果  我是箭头函数ns

注意 如果代码块中只有一句代码,大括号也可以省略

let  say =  name => console.log( "我是箭头函数"+name);
say("ns"); //结果  我是箭头函数ns

递归函数

递归函数就是在函数中自己调用自己,就叫他递归函数
递归函数在一定程度上可以实现循环的功能
递归函数的注意点
每次调用递归函数都会开辟一块新的存储空间, 所以性能不是很好

 function login() {
            // 1.接收用户输入的密码
            let pwd = prompt("请输入密码");
            // 2.判断密码是否正确
            if(pwd !== "123456"){
                login(); //自己调用自己
            }
            // 3.输出欢迎回来
            alert("欢迎回来");//结果  调用了几次函数就会输出几次 欢迎回来
        }
        login();

变量在函数中的作用域

作用域分为 全局作用域,块级作用域和局部作用域

  • 全局作用域: 大括号外面的作用域
  • 块级作用域: 和函数没有关系的大括号里面的作用域
  • 局部作用域: 和函数有关的大括号里面的作用域
    在局部作用域中 var定义的变量为全局变量
{
var num = 666;
}
console.log(num); //结果  666

在局部作用域中 var定义的变量为局部变量

let say = function (){
var num = 666;
}
say();
console.log(num); //结果  报错

无论是在块级作用域还是在局部作用域, 省略变量前面的let或者var就会变成一个全局变量(在企业开发中不推荐这种用法)

let say = function (){
num = 666;
}
say();
console.log(num); //结果  666

作用域链

需要明确:
1.ES6之前定义变量通过var
2.ES6之前没有块级作用域, 只有全局作用域和局部作用域
3.ES6之前函数大括号外的都是全局作用域
4.ES6之前函数大括号中的都是局部作用域

    2.ES6之前作用域链
    1.1.全局作用域我们又称之为0级作用域
    2.2.定义函数开启的作用域就是1级/2级/3级/...作用域
    2.3.JavaScript会将这些作用域链接在一起形成一个链条, 这个链条就是作用域链
      0  --->  1 ---->  2  ---->  3 ----> 4
    2.4.除0级作用域以外, 当前作用域级别等于上一级+1

    3.变量在作用域链查找规则
    3.1先在当前找, 找到就使用当前作用域找到的
    3.2如果当前作用域中没有找到, 就去上一级作用域中查找
    3.3以此类推直到0级为止, 如果0级作用域还没找到, 就报错
 // 全局作用域 / 0级作用域
        // var num = 123;
        function demo() {
            // 1级作用域
            // var num = 456;
            function test() {
                // 2级作用域
                // var num = 789;
                console.log(num);
            }
            test();
        }
        demo();

需要明确:
1.ES6定义变量通过let
2.ES6除了全局作用域、局部作用域以外, 还新增了块级作用域
3.ES6虽然新增了块级作用域, 但是通过let定义变量并无差异(都是局部变量)

    2.ES6作用域链
    1.1.全局作用域我们又称之为0级作用域
    2.2.定义函数或者代码块都会开启的作用域就是1级/2级/3级/...作用域
    2.3.JavaScript会将这些作用域链接在一起形成一个链条, 这个链条就是作用域链
      0  --->  1 ---->  2  ---->  3 ----> 4
    2.4.除0级作用域以外, 当前作用域级别等于上一级+1

    3.变量在作用域链查找规则
    3.1先在当前找, 找到就使用当前作用域找到的
    3.2如果当前作用域中没有找到, 就去上一级作用域中查找
    3.3以此类推直到0级为止, 如果0级作用域还没找到, 就报错
// 全局作用域 / 0级作用域
        // let num = 123;
        {
            // 1级作用域
            // let num = 456;
            function test() {
                // 2级作用域
                // let num = 789;
                console.log(num);
            }
            test();
        }

函数预解析

预解析是指浏览器在执行JS代码的时候会分成两部分操作:预解析以及逐行执行代码也就是说浏览器不会直接执行代码, 而是加工处理之后再执行,这个加工处理的过程, 我们就称之为预解析.

  • 预解析规则
  1. 将变量声明和函数声明提升到当前作用域最前面
    2.将剩余代码按照书写顺序依次放到后面
      注意点
       通过let定义的变量不会被提升(不会被预解析)
       */
       /*
       // 预解析之前
       console.log(num); //undefined
       var num = 123;
       // 预解析之后
       var num;
       console.log(num);
       num = 123;
       */
       /*
       // 不会预解析之前
       console.log(num); // 报错
       let num = 456;
       */

       // ES6之前定义函数的格式
       /*
       console.log(say);
       say();
       // ES6之前的这种定义函数的格式, 是会被预解析的, 所以可以提前调用
       function say() {
           console.log("hello it666");
       }
       */
       /*
       // 预解析之后的代码
       function say() {
           console.log("hello it666");
       }
       say();
       */

       /*
       console.log(say);
       say(); // say is not a function
       // 如果将函数赋值给一个var定义的变量, 那么函数不会被预解析, 只有变量会被预解析
       var say = function() {
           console.log("hello itzb");
       }
       */
       /*
       var say; //undefined
       say();
       say = function() {
           console.log("hello itzb");
       }
       */

ES6定义函数的格式不会预解析
如果变量名称和函数名称同名, 那么函数的优先级高于变量
一定要记住, 在企业开发中千万不要让变量名称和函数名称重名

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