Skip to content

javaScript中的函数

在学习编程的过程中,你可能会经常看到foo、bar、baz这些名词:

  • 它们通常被用来作为函数、变量、文件的名词;
  • 目前已经编程了计算机编程的术语一部分;
  • 但是它们本身并没有特别的用途和意义;
  • 常被称之为 “伪变量”(metasyntactic variable)

事实上,foo、bar这些名词最早从什么时候、地方流行起来的一直是由争论的;

  • 一种说法是通过Digital(迪吉多,数字设备公司,成立于1957年的美国电脑公司)的手册说明流行起来的;
  • 一种说法是说源自于电子学中的反转foo信号;
  • 也有一种说法是foo因为出现在了一个漫画中,漫画中foo代表“好运”,与中文的福读音类似;
  • 总之,foo、bar、baz已经是编程领域非常常用的名词。

函数就是一段具有特殊功能代码的封装,用来提高编写的效率以及代码的重用;

默认情况下JavaScript引擎或者浏览器会给我们提供一些已经实现好的函数;

例:console.log() alert() prompt()

函数的默认调用就是,自行调用,无论在那段代码里面自行调用this就是windows

函数的返回值默认 undefined;

  1. 如果函数中没有使用 return语句 ,那么函数有默认的返回值:undefined;
  2. 如果函数使用 return语句,但是return后面没有任何值,那么函数的返回值也是 undefined;
  3. 如果在函数执行到 return关键字时, 函数会 立即停止执行, 退出函数
  4. 在 javaScript 代码当中 return 不能在 for 循环中使用
  • 注意:箭头函数 一行代码 的时候可以省略大括号的return

5、函数的形参、实参、arguments参数

Section titled “5、函数的形参、实参、arguments参数”

函数的参数,增加函数的 通用性,针对 相同的数据处理逻辑,能够 适应更多的数据

形式参数:定义 函数时,小括号中的参数,是用来接收参数用的,在函数内部 作为变量使用

函数在定义的时候用来接受参数的

// name/age/height称之为函数的参数(形参, 形式参数, parmaters)
function printInfo(name, age, height) {
console.log(`my name is ${name}`)
console.log(`age is ${age}`)
console.log(`height is ${height}`)
}

实际参数:调用 函数时,小括号中的参数,是用来把数据传递到 函数内部 用的

函数调用的时候传入的实际参数

// why/18/1.88称之为函数的参数(实参, 实际参数, arguments)
printInfo("why", 18, 1.88)
printInfo("kobe", 30, 1.98)

arguments 是一个类数组对象,不是数组对象,存在当前函数执行上下文当中,执行代码之前会初始化这个对象用来保存实参

  • arguments变量的类型是一个object类型( array-like ),不是一个数组,但是和数组的用法看起来很相似

    //node中展示的类型 看着比较像数组实际是个类数组
    [Arguments] { '0': 123, '1': 123, '2': 124 }
  • 该对象中存放着所有的调用者传入的参数,从0位置开始,依次存放;

  • 在函数的代码块中直接获取,无论有没有设置参数

    function baz(){
    //这样也能获取到
    console.log(arguments)
    //将一个可迭代的对象转化成数组
    var arr = Array.form(arruments)
    }
    baz(1123,31231,3123)

注意“类数组” 表示arguments具有 length 从零开始索引的属性和属性,但它没有像Array这样的内置方法。

  • 可以使用 Array.form(arguments)生成数组.来使用数组中的方法

参数传递就是将实参的 值传递 给形参

  • 值传递:原始类型的参数传递就是值传递,会将栈空间的值复制一份 最后赋值给形参
  • 引用传递:对象类型的参数传递就是引用传递,会将栈空间的16进制0x…的地址值复制一份,赋值给形参。
function baz(...args){
//这样也能获取到
console.log(arguments)
}
baz(1123,31231,3123)

箭头函数中使用 …rest 不能像arguments那样单独的打印rest 就是个概念

  1. 不会计算在函数对象的 length 属性当中
  2. 只能放到,参数的最后面

5.6、函数形参和实参不匹配的情况

Section titled “5.6、函数形参和实参不匹配的情况”
  • 实参多于形参的时候,有几个形参就取几个,不会报错 arguments会存在所有实参
  • 实参少于形参的时候,同样不会报错,有几个便用几个

递归:一种函数调用自身的操作,会占用较大资源,性能是比较低,会创建多个执行上下文栈(占用过多的栈内存),默认情况下会产生无限调用的情况,谨慎使用添加判断

  • 内部的变量: 定义在函数内部的变量,被称之为局部变量(Local Variables)。

  • 外部的变量: 定义在函数外部的变量,被称之为外部变量(Outer Variables)。

  • 全局变量: 函数之外声明的变量(在script中声明的),称之为全局变量

    • 注意:通过var声明的全局变量会在window对象上添加一个属性 很重要的一点全局变量不会被垃圾回收机制回收

      这个特性在不使用框架的情况下可以定义全局变量,因为变量的添加在window对象上的,windows又是全局变量。

      不适用var 声明的全局变量是不规范的。

7.1、函数中变量访问的顺序链式查找(作用域链)

Section titled “7.1、函数中变量访问的顺序链式查找(作用域链)”

优先访问自己函数(当前作用域)中的变量,没有找到时,在外部中访问,就是一层一层的找就近原则,最后会找到window 找不到返回undefined

表示一些标识符的、语句、表达式的有效范围, JavaScript(ES5之前中没有块级作用域的概念 例:if ),但是函数可以有自己的作用域。

  • 函数的作用域表示在函数内部定义的变量,只有在函数内部可以被访问到;
function foo(){
console.log(message)
//这种情况不会提示Uncaught ReferenceError: message is not defined
//而是打印undefined,因为变量会提升
var message=null;
}

无论函数是如何创建的,函数都是一个值(这个值的类型是一个对象)。

8.1、JavaScript创建函数的时机(预解析)

Section titled “8.1、JavaScript创建函数的时机(预解析)”

当 JavaScript 准备 运行脚本时,首先会在脚本中寻找全局函数声明,并创建这些函数

  • 函数表达式是在代码执行时被创建的,并且仅从那一刻起才可调用。
  • 函数声明则是 在JavaScript 准备运行脚本时就被创建了,在函数中也是一样,所以可以直接调用。
  • 这样的话优先使用函数声明的方式

8.2、第一种函数表达式(Function Expressions)

Section titled “8.2、第一种函数表达式(Function Expressions)”

函数表达式:在一个表达式中或另一个语法结构中创建的函数。

  • 函数表达式允许省略函数名。添加也不会生效,就是不报错而已 但个人觉得不规范
var bar = function(){
console.log("这里是bar函数")
}

函数声明:在主代码流中使用function关键字声明单独语句的函数。

function foo() {
console.log(message)
var message=null;
}

javaScript运行机制-变量和函数的预解析

Section titled “javaScript运行机制-变量和函数的预解析”

JavaScript代码是由浏览器中的JavaScript解析器来执行的。JavaScript引擎(解析器)在运行JavaScript代码的 时候分为两步: 预解析代码执行

  1. 预解析:js引擎会把js里面 所有的 var 还有 function提升到当前作用域的最前面
  2. 代码执行:按照代码书写的顺序从上往下执行

变量提升就是将所有的变量声明提升到当前作用域最前面 只是提升变量没有赋值的操作

例如:

console.log(num)
var num = 100;
// 解析之后 变量的声明提升到当前作用域的最前面
var num;
//这里打印的是undefiined
console.log(num)
num=100

函数提升就是把所有的函数声明提升到当前作用域的最前面 不调用函数

  • 所以函数声明会预编译

  • 函数的表达式是变量赋值的形式,所以只能是变量提升

    foo()
    var foo = function() {}
    //解析之后是
    var foo;
    foo() //所以这里报foo不是一个函数
    foo = function() {}

头等函数(first-class function;第一级函数)是指在程序设计语言中,函数被当作头等公民 。

  • 头等函数:函数可以作为别的函数的参数、函数的返回值,赋值给变量或存储在数据结构 例:Array 和{}…等数据结构中具有这些特征的函数就是头等函数;

  • 有人主张也应包括支持匿名函数

    var bar = function(){
    return () => {
    console.log("bar")
    }
    }
    //注意:这里bar要加()
    var bar1=bar();

函数作为作为头等公民的编程方式,称之为函数式编程

javaScript就是符合函数式编程的语言,这个也是JavaScript的一大特点;

执行某些操作后执行的函数

回调函数是作为参数传递给另一个函数,并在其父函数完成后执行的函数。

接受一个或多个函数作为输入或者输出一个函数,这种函数称之为高阶函数;

//通常异步调用的时候没有等待返回值的时候使用,什么时候执行完什么时候调用函数,应该是这个意思
function baz(result,fu=function(){}){
result="这里是fn"
fu(result)
}
var result=null;
baz(result,(rs)=>{
console.log(rs)
})
//output 这里是fn

11、JavaScript 中的数字分隔符(es12)

Section titled “11、JavaScript 中的数字分隔符(es12)”

引入数字分隔符 ( ) 是为了通过在数字之间使用 “_” 创建视觉分隔,来使数字更具可读性。分隔符可用于十进制、二进制、十六进制或 BigInt 数字。这个特性是在ES12中引入的

  • 数字末尾不允许使用数字分隔。因此,以下号码无效。

    123_00_

  • 此外,如果数字以_开头_JavaScript 会将其视为变量。在 JavaScript 中,变量可以以_.

    const a = _123;

  • 浏览器兼容性

    所有主流浏览器都支持数字分隔符。我们可以通过访问此CanIuse链接查看准确信息

  • js数字分隔符文章所在地址

例:1000_0000_0000 可以提高代码的可读性

在java中数字分割符是Java7引入的新特性。分割数字增强可读性

js中应该也是吧

Java数组分隔符所在oracle官方文档

专业名字:Immediately-Invoked Function Expression(IIFE 立即调用函数表达式)

普通Script标签内的代码 和 和 立即执行函数都会在加载js的时候被执行

  1. 会创建一个独立的执行上下文环境,可以避免外界js访问或修改内部的变量,也避免了对内部变量的冲突
  2. 因为S5之前中没有块级作用域的概念,最早用来解决javaScript没有作用域的问题,例:for循环之后i值的问题

立即执行函数必须是函数表达式,不能式函数声明。所以可以将函数声明成表达式的情况下都可以用()立即执行

简单来说使用表达式声明的函数都是可以立即执行的

  1. 立即执行函数(常用的写法)

    使用分组运算符来让函数变成一个表达式,例(2+3)*8,(function() {})

    var result = (function(i) {
    console.log("立即执行函数被调用~")
    })(i)
  2. 立即执行函数的其他写法

    使用 !+ - 可以让函数变成表达式的都可以

    (function() {}) ()//常用的
    !function(){}()
    +function foo() {}()

注意事项 立即执行函数要使用分号结尾

Section titled “注意事项 立即执行函数要使用分号结尾”

**当一行代码后面紧跟着{} ,() 或者[] 的时候,js引擎不会将换行符转换成 ;的,会被认为于后面的代码是一个整体 **

例如

  • if会将后面的()和{}当作整体
  • 获取对象值的时候会将[]当作整体

结论:当后面如果要使用立即执行函数的时候前一行记得添加;, 表示当前行代码结束,最好后面也添加上

  1. foo和()之间不需要有空格
  2. 多参数 , 后面加上一个空格
  3. () 和 { 之间有一个空格
  4. { 和其他函数定义在同一行中
  5. for 和 ()之间和 ; 后要有空格
  6. 运算符之间要有一个空格
  7. if else 前后的 () {} 间隔一个空格
  8. es6 字符串字面量 ${} 前后要留一个空格
  9. 逻辑块之间 留取一个空行的间隔

Snipaste_2022-05-12_22-29-28.png

OLQeds.png

  • Chrome开发者工具Console区域: 可以查看代码中使用console.log() 输出的信息
  • 给代码添加断点(breakpoint): 代码运行时遇到断点便会停止执行
    • VSCode中,点击对应的代码行号左侧的红点即可添加断点,或者在代码上方加上 debugger
    • Chrome中Source区域:找到要调试的文件,在代码左侧的行号处点击即可添加断点
  • Watch区域: 输入对应的变量,可以观察代码运行过程中变量的值的变化情况
  • Breakpoints区域: 可以查看js代码中所有非代码 debugger 添加的断点
  • Scope区域: 查看代码生成的作用域
  • 上方工具栏按钮作用(从左到又):
    • 控制调试程序的暂停和恢复
    • 跳过下一个函数调用,执行下一行代码
    • 进入下一个函数调用,可查看函数内部执行顺序
    • 跳出当前函数
    • 进入下一个函数调用,不会进入setTimeout内部的函数

重点:函数的调用还有返回值

E:\coder why前端系统课\练习作业\4.node_webpack工程化\03_包管理工具使用\06_why_utils\src