【亡羊补牢】JS灵魂之问 第14期 修炼内功 函数基础 形参实参映射关系,是什么?

本文主要是介绍【亡羊补牢】JS灵魂之问 第14期 修炼内功 函数基础 形参实参映射关系,是什么?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言

有几天没有更新JS灵魂之问的专栏系列文章了,秋招季,也在忙着备战笔试面试。今天得空再来写一篇文章,本篇要讲解的内容是关于 函数基础 ,那今天这篇看能不能问倒你了,一起来探索一下吧。

仰望星空的人,不应该被嘲笑

文章目录

    • 引言
    • 函数基础
      • 函数种类、字面量
      • 形参实参映射
      • 作用域引入
      • 函数默认参数
    • 最后

函数基础

函数种类、字面量

开门见山,下面代码会输出什么,不知道小伙伴平常有咩有想过这类问题

var test = function test1() {var a = 1;console.log(a);
}
test()
test1()

答案是 1报错,报错信息如下:


这是为什么呢?实际上,我们申明了一个变量 test,把这个函数 test1赋给它的时候,就已经把这个变量赋予了函数的功能,调用 test()方法当然能够正常运行,输出 1。而对于表达式赋值,会自动忽略后面的函数名称,也就是说写与不写并不影响 test()方法的执行。不信,看看下面代码会输出什么?

var test = function() {var a = 1;console.log(a);
}
test() // 1

那这样,是不是说 test1完全没作用了,那写着干嘛,还多几个字符。当然不是!test1在函数体内部是可见的,而在外部却不可见,通过这样,我们就可以实现递归操作

var test = function() {var a = 1;console.log(a);
}

而对于上述代码,后面函数体没有名字,我们称之为 匿名函数,是不是有点印象了,原来就是这东西,哟西~

而通过这种方式赋值的表达式,我们称之为 匿名函数表达式,也称为 函数字面量,这些专有名词一出来,瞬间觉得有点逼格了有没有!

字面量这种东西,简单来说就是数据,例如下述,有数字字面量,字符串字面量,数组字面量等等。简单理解就是,对于赋值的过程,右边的数据就是字面量。

var a = 10
var b = '111'
var c = [1,2,3]

形参实参映射

补充:如何获取形参和实参对应的长度?

function test (a,b) {console.log(test.length)  // 形参的长度 2console.log(arguments.length) // 实参的长度 3
}
test(1,2,3)

我想小伙伴们应该清楚实参和形参是什么玩意,但是我们可以更改实参的值吗?例如下述代码,会输出什么呢?

function test(a, b) {a =3;console.log(arguments[0]);
}
test(1,2);

答案是 3,我们可以修改实参的值。

刚刚那题只是简单热个身,继续下一题吧,我们可以改变 b 的值吗?(提示:注意我并没有传对应实参哦~)

function test(a, b) {b = 3;console.log(arguments[1]);
}
test(1);

答案是 undefined,因此对于上一题表述,要修改一下:对于实参传递过来确定的值,我们是可以进行修改的,而如果实参并没有传递值过来,我们是不能进行修改的。这就是形参和实参的映射关系

简单解释一下形参和实参的映射关系,其实实参形参不能说是一类的,看上述代码,我们可以通过 arguments 来获取我们的实参,可以看做是一个数组里面的某一项值,而数组是存放堆内存的,而对应我们形参其实是存放在栈内存的,它们之间会有一个映射关系,并且是一对一对应的,上述我们实参没有对b进行赋值,尽管修改了形参,但改变不了我们的 arguments[1] 就是这个道理。(没有建立一对一映射关系)。

作用域引入

再来一道引申题,为后续内容做铺垫。下面 a b c 分别会输出什么?

a = 1;
function test1 () {var b = 2;console.log(a)  // function test2() {var c = 3console.log(b); // }test2();console.log(c); // 
}
test1();

答案是 1 2 报错,这就牵扯到 scope 问题了,简单理解就是函数内部能访问外面的变量,而函数外面却不能访问内部的变量,也就是闭包问题。(这个后文会提到)

函数默认参数

如果实参没有赋值,那么形参怎样设置默认参数呢?说到默认参数,我想你应该会想到如下代码:

function test(a = 1, b = 1) {console.log(a)console.log(b)
}
test() // 1 1

好的,上述问题算是开胃小菜,我们继续,我如果给 a 设定默认值,而 b 通过实参传递过来呢?可以实现吗?之前没有传参的话,不是默认打印 undefined吗,那我现在给 a 传递一个 undefined,是不是就会定为默认值。

function test(a = 1, b) {console.log(a)console.log(b)
}
test(undefined, 2)

答案是可以的,上述代码输出结果为 1 2。简单解释一下,在之前我们将了形参实参是有一个映射关系,对于堆内存 arguments 里面,如果给了 undefined,那么就会去栈内存形参里面找,如果不为 undefined,则会设置形参的默认值。(其实这是 es6 的语法了)

那么,可以用es5的方式实现一下吗?(当然可以,见代码)

function test(a, b) {a = arguments[0] || 1b = arguments[1] || 1console.log(a)console.log(b)
}
test(undefined, 2)

最后

文章产出不易,还望各位小伙伴们支持一波!

往期精选:

小狮子前端の笔记仓库

访问超逸の博客,方便小伙伴阅读玩耍~

学如逆水行舟,不进则退

这篇关于【亡羊补牢】JS灵魂之问 第14期 修炼内功 函数基础 形参实参映射关系,是什么?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/451523

相关文章

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

Kotlin 作用域函数apply、let、run、with、also使用指南

《Kotlin作用域函数apply、let、run、with、also使用指南》在Kotlin开发中,作用域函数(ScopeFunctions)是一组能让代码更简洁、更函数式的高阶函数,本文将... 目录一、引言:为什么需要作用域函数?二、作用域函China编程数详解1. apply:对象配置的 “流式构建器”最

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Tomcat版本与Java版本的关系及说明

《Tomcat版本与Java版本的关系及说明》:本文主要介绍Tomcat版本与Java版本的关系及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Tomcat版本与Java版本的关系Tomcat历史版本对应的Java版本Tomcat支持哪些版本的pythonJ

C#基础之委托详解(Delegate)

《C#基础之委托详解(Delegate)》:本文主要介绍C#基础之委托(Delegate),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 委托定义2. 委托实例化3. 多播委托(Multicast Delegates)4. 委托的用途事件处理回调函数LINQ

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

kotlin的函数forEach示例详解

《kotlin的函数forEach示例详解》在Kotlin中,forEach是一个高阶函数,用于遍历集合中的每个元素并对其执行指定的操作,它的核心特点是简洁、函数式,适用于需要遍历集合且无需返回值的场... 目录一、基本用法1️⃣ 遍历集合2️⃣ 遍历数组3️⃣ 遍历 Map二、与 for 循环的区别三、高

C语言字符函数和字符串函数示例详解

《C语言字符函数和字符串函数示例详解》本文详细介绍了C语言中字符分类函数、字符转换函数及字符串操作函数的使用方法,并通过示例代码展示了如何实现这些功能,通过这些内容,读者可以深入理解并掌握C语言中的字... 目录一、字符分类函数二、字符转换函数三、strlen的使用和模拟实现3.1strlen函数3.2st