JavaScript -- 06.函数知识汇总

news2025/8/4 7:47:09

文章目录

  • 函数
    • 1 函数介绍
    • 2 函数的创建方式
      • 2.1 函数声明
      • 2.2 函数表达式
      • 2.3
    • 3 参数
      • 3.1 函数声明
      • 3.2.函数表达式
      • 3.3 箭头函数
      • 3.4 默认参数
      • 3.5 使用对象作为参数
      • 3.6 函数作为参数
    • 4 函数的返回值
    • 5 作用域
      • 5.1 函数作用域
      • 5.2 作用域链
      • 5.3 练习
    • 6 window对象
    • 7 提升
      • 7.1 变量的提升
      • 7.2 函数的提升
      • 7.3 为什么要有提升
    • 8 debug
    • 9 立即执行函数
    • 10 函数中的this
      • 10.1 普通函数的this
      • 10.2 箭头函数的this
    • 11 严格模式

函数

1 函数介绍

函数(Function)

  • 函数也是一个对象
  • 它具有其他对象所有的功能
  • 函数中可以存储代码,且可以在需要时调用这些代码

语法:

function 函数名(){
	语句...
}

调用函数:

  • 调用函数就是执行函数中存储的代码
  • 语法:函数对象()

使用 typeof 检查函数对象时会返回 function

image-20221201140842209

2 函数的创建方式

三种方式

  • 函数声明
  • 函数表达式
  • 箭头函数

2.1 函数声明

function 函数名(){
    语句...
}

示例:

function fn(){
    console.log("函数声明所定义的函数~")
}

2.2 函数表达式

const 变量 = function(){
    语句...
}

示例:

const fn2 = function(){
    console.log("函数表达式")
}

2.3

() => {
    语句...
}

示例:

const fn3 = () => {
    console.log("箭头函数")
}

const fn4 = () => console.log("箭头函数")

3 参数

  • 形式参数

    • 在定义函数时,可以在函数中指定数量不等的形式参数(形参

    • 在函数中定义形参,就相当于在函数内部声明了对应的变量但是没有赋值

  • 实际参数

    • 在调用函数时,可以在函数的()传递数量不等的实参

    • 实参会赋值给其对应的形参

    • 参数:

      • 如果实参和形参数量相同,则对应的实参赋值给对应的形参

      • 如果实参多于形参,则多余的实参不会使用

      • 如果形参多于实参,则多余的形参为undefined

    • 参数的类型

      • JS中不会检查参数的类型,可以传递任何类型的值作为参数
// 计算两数之和
function sum(a, b){
    console.log(a + b)
}

3.1 函数声明

function 函数名([参数]){
    语句...
}

3.2.函数表达式

const 变量 = function([参数]){
	语句...
}

3.3 箭头函数

([参数]) => {
	语句...
}

例子:

const fn = (a, b) => {
    console.log("a =", a);
    console.log("b =", b);
}

fn(123, 456)

箭头函数只有一个参数的时候可以省略()

const fn2 = a => {
    console.log("a =", a);
}

3.4 默认参数

定义参数的时候,可以指定默认值,默认值会在没有对应实参时候生效

const fn3 = (a=10, b=20, c=30) => {
    console.log("a =", a);
    console.log("b =", b);
    console.log("c =", c);
}

fn3(1, 2) // a = 1, b = 2, c = 30

3.5 使用对象作为参数

对象可以作为参数传递,传递的是变量中存储的值,也就是对象的内存地址,所以形参和实参指向的就是同一个对象

  • 当修改形参指向的时候,只会影响当前变量(形参指向改变)
  • 当修改对象中的参数的时候,如果有其他变量指向该对象则所有指向该对象的变量都会受到影响

这个必须得区分清楚

function fn(a){
    console.log("a =", a)
    // a = {} // 修改变量时,只会影响当前的变量
    a.name = "猪八戒" // 修改对象时,如果有其他变量指向该对象则所有指向该对象的变量都会受到影响
    console.log(a)
}

let obj = {name:"孙悟空"}
fn(obj)

如果形参的默认值是一个对象的话,那么在函数每次调用的时候,都会重新创建新对象

// 函数每次调用,都会重新创建默认值
function fn2(a = {name:"沙和尚"}){
    console.log("a =", a)
    a.name = "唐僧"
    console.log("a =", a)
}

fn2() // 沙和尚 唐僧
fn2() // 沙和尚 唐僧

但是如果是下面这个样子的话,每次指向的都是obj2,不会重新创建对象

let obj2 = {name:"沙和尚"}

// 函数每次调用,都会重新创建默认值
function fn2(a = obj2){
    console.log("a =", a)
    a.name = "唐僧"
    console.log("a =", a)
}

fn2() // 沙和尚 唐僧
fn2() // 唐僧 唐僧

3.6 函数作为参数

在JS中,函数也是一个对象(一等函数),别的对象能做的事情函数也可以

所以别的对象可以作为参数传递到函数中,函数也可以作为参数传递到函数中

function fn(a) {
    console.log("a =", a)
    a()
}

function fn2() {
    console.log("fn2被调用了")
}

fn(fn2) 

image-20221201143035741

有了这种功能之后,我们就可以动态的执行代码

fn(() => console.log("我是箭头函数"))

function exec(desc, fn, arg1, arg2) {
    console.log(desc + " = " + fn(arg1, arg2))
}

function add(arg1, arg2) {
    return arg1 + arg2
}

function sub(arg1, arg2) {
    return arg1 - arg2
}

exec("3 + 5", add, 3, 5)
exec("5 - 3", sub, 5, 3)
exec("5 * 3", (arg1, arg2) => {return arg1 * arg2}, 5, 3) // 使用匿名函数作为参数

image-20221201143416306

4 函数的返回值

在函数中,可以通过return关键字来指定函数的返回值,返回值就是函数的执行结果,函数调用完毕返回值便会作为结果返回

任何值都可以作为返回值使用(包括对象和函数之类),如果return后不跟任何值,则相当于返回undefined,如果不写return,那么函数的返回值依然是undefined

function sum(a, b) {
    // console.log(a + b)
    // 计算完成后,将计算的结果返回而不是直接打印
    return a + b
}

let result = sum(2,3) // 5

return一执行函数立即结束

function sum(a, b) {
    return a + b
    console.log(a + b) // 不会执行这条语句
}

箭头函数的返回值可以直接写在箭头后,如果直接在箭头后设置对象字面量为返回值时,对象字面量必须使用()括起来

const sum = (a, b) => {
    return a + b
}

const sum1 = (a, b) => a + b
const fn = () => ({name: "张三"})

5 作用域

  • 作用域指的是一个变量的可见区域
  • 作用域有两种:
    • 全局作用域
      • 全局作用域在网页运行时创建,在网页关闭时销毁
      • 所有直接编写到script标签中的代码都位于全局作用域中
      • 全局作用域中的变量是全局变量,可以在任意位置访问
    • 局部作用域
      • 块作用域
        • 块作用域是一种局部作用域
        • 块作用域在代码块执行时创建,代码块执行完毕它就销毁
        • 在块作用域中声明的变量是局部变量,只能在块内部访问,外部无法访问

5.1 函数作用域

  • 函数作用域也是一种局部作用域
  • 函数作用域在函数调用时产生,调用结束后销毁
  • 函数每次调用都会产生一个全新的函数作用域
  • 在函数中定义的变量是局部变量,只能在函数内部访问,外部无法访问
function fn(){
    let a = "fn中的变量a"
    console.log(a)
}

fn()
console.log(a) // undefined 

5.2 作用域链

当我们使用一个变量时,JS解释器会优先在当前作用域中寻找变量,就近原则

  • 如果找到了则直接使用
  • 如果没找到,则去上一层作用域中寻找,找到了则使用
  • 如果没找到,则继续去上一层寻找,以此类推
  • 如果一直到全局作用域都没找到,则报错 xxx is not defined

参照下面的例子理解

报错的原因看下一节提升相关概念

let a = 10

{
    console.log(a) // 报错,Cannot access 'a' before initialization
    let a = "第一代码块中的a"
    console.log(a) // "第一代码块中的a"
    {
        console.log(a) // 报错,Cannot access 'a' before initialization
        let a = "第二代码块中的a"
        console.log(a) // "第二代码块中的a"
    }
    console.log(a) // "第一代码块中的a"
}
console.log(a) // 10
let b = 33

function fn() {
    console.log(b) // 报错,Cannot access 'b' before initialization
    let b = 44
    console.log(b) // 44
    function f1() {
        console.log(b) // 报错,Cannot access 'b' before initialization
        let b = 55
        console.log(b) // 55
    }
    f1()
}

fn()

5.3 练习

练习1

var a = 1

function fn() {
    a = 2
    console.log(a) // 2
}

fn()
console.log(a) // 2

练习2

var a = 1

function fn() {
    console.log(a) //undefined
    var a = 2
    console.log(a) // 2
}

fn()
console.log(a) // 1

练习3

var a = 1

function fn(a) {
    console.log(a) //undefined
    a = 2 	// 修改的是形参
    console.log(a) // 2
}

fn()
console.log(a) // 1

练习4

var a = 1

function fn(a) {
    console.log(a) //10
    a = 2
    console.log(a) // 2
}

fn(10)
console.log(a) // 1

练习5

var a = 1

function fn(a) {
    console.log(a) //1
    a = 2
    console.log(a) // 2
}

fn(a)
console.log(a) // 1

练习6

console.log(a)  // a指向的是第五行的函数,var只是声明,并不赋值,如果声明过不会重复赋值

var a = 1
console.log(a) // 1
function a() {
    alert(2)
}
console.log(a) // 1
var a = 3
console.log(a) // 3
var a = function () {
    alert(4)
}
console.log(a) // 打印11行函数
var a	// 已经声明过了,根本不执行
console.log(a) // 打印11行函数

6 window对象

  • 在浏览器中,浏览器为我们提供了一个window对象,可以直接访问
  • window对象代表的是浏览器窗口,通过该对象可以对浏览器窗口进行各种操作,除此之外window对象还负责存储JS中的内置对象和浏览器的宿主对象
  • window对象的属性可以通过window.对象名访问,也可以直接通过对象名访问
  • 函数就可以认为是window对象的方法
  • 向window对象中添加的属性会自动成为全局变量
window.a = 50
console.log(window.a) // 50
console.log(a) // 50

var:用来声明变量,作用和let相同,但是var不具有块作用域

  • 在全局中使用var声明的变量,都会作为window对象的属性保存

    • var b = 20 等价于 window.b = 20
  • 使用function声明的函数,都会作为window的方法保存

    function fn(){
        alert('我是fn')
    } 
    fn() // 等价于window.fn()
    
  • 使用let声明的变量不会存储在window对象中,而存在一个秘密的小地方(无法访问)

  • var虽然没有块作用域,但有函数作用域

    function fn2(){
        var d = 10 // var虽然没有块作用域,但有函数作用域
        m = 10 // 在局部作用域中,如果没有使用var或let声明变量,则变量会自动成为window对象的属性 也就是全局变量
    }
    
    fn2()
    
    console.log(d) // d is not defined 
    console.log(m) // 10
    

7 提升

7.1 变量的提升

使用var声明的变量,会在所有代码执行前被声明(而不是赋值),所以就可以在变量声明前就访问变量

let声明的变量实际也会提升,但是在赋值之前解释器禁止对该变量的访问

console.log(a) // 打印undefined
var a = 10 

console.log(b) // 报错 b is not defined
b = 10

console.log(c) // Cannot access 'c' before initialization
let c = 10

7.2 函数的提升

使用函数声明创建的函数,会在其他代码执行前被创建,所以我们可以在函数声明前调用函数

只有以var, let或者function开头的变量才会提升

fn() // 可以正常调用执行
fn2() // 报错fn2 is not a function

function fn(){
    alert("我是fn函数~")
}
var fn2 = function(){
    alert("我是fn函数~")
}

7.3 为什么要有提升

是为了解决性能问题,要根据变量和函数的数量决定开多大的内存空间

8 debug

两种方式

https://www.bilibili.com/video/BV1mG411h7aD?p=67

  1. 直接在代码中写debugger,在浏览器中打开控制台刷新页面后会停到这个位置

    debugger // 在代码中打了一个断点
    
    console.log(a) // 2
    var a = 1
    console.log(a) // 1
    
  2. 直接打开浏览器,F12 -> 源代码 -> 指定位置点击行号 -> 刷新

    image-20221201185036935

9 立即执行函数

在开发中应该尽量减少直接在全局作用域中编写代码

所以我们的代码要尽量编写的局部作用域

如果使用let声明的变量,可以使用{}来创建块作用域,这样也不会相互干扰

{
    let a = 10
}
{
    let a = 20
}

而如果现在函数里面,哪怕是使用var声明的变量也不会相互干扰,但是使用函数的时候需要再单独调用一下

function fn(){
    var a = 10
    }

fn()

function fn2(){
    var a = 20
    }

fn2()

我们希望可以创建一个只执行一次的匿名函数

立即执行函数(IIFE)

  • 立即是一个匿名的函数,并它只会调用一次
  • 可以利用IIFE来创建一个一次性的函数作用域,避免变量冲突的问题
  • 外面包裹的括号不能少,是用来防止这个函数被提升;另外,最后的分号也不能省略,不然js会解析成(xxx)(xxx)
(function(){
    let a = 10
    console.log(111)
}());

(function(){
    let a = 20
    console.log(222)
}());

10 函数中的this

10.1 普通函数的this

  • 函数在执行时,JS解析器每次都会传递进一个隐含的参数,这个参数就叫做 this
  • this会指向一个对象
    • this所指向的对象会根据函数调用方式的不同而不同
      • 1.以函数形式调用时,this指向的是window

      • 2.以方法的形式调用时,this指向的是调用方法的对象

      • 但实际上都是指向调用的对象,以函数方式调用的时候默认调用的对象是window

  • 通过this可以在方法中引用调用方法的对象
function fn() {
    // console.log(this === window)
    console.log("fn打印", this)
}
fn()	// 就相当于 window.fn()

const obj = { name: "孙悟空" }
obj.test = fn
obj.test()

案例:为两个对象添加一个方法,可以打印自己的名字

方法一:

const obj3 = {
    name: "沙和尚",
    sayHello: function () {
        console.log(this.name)
    },
}
const obj4 = { 
    name: "唐僧",
    sayHello: function(){
        console.log(this.name)
    }
}

// 为两个对象添加一个方法,可以打印自己的名字
obj3.sayHello()
obj4.sayHello()

方法二:

const sayHello = function(){
    console.log(this.name)
}

const obj3 = {
    name: "沙和尚",
    sayHello: sayHello
}
const obj4 = { 
    name: "唐僧",
    sayHello: sayHello
}

// 为两个对象添加一个方法,可以打印自己的名字
obj3.sayHello()
obj4.sayHello()

10.2 箭头函数的this

箭头函数:([参数]) => 返回值

例子:

  • 无参箭头函数:() => 返回值

  • 一个参数的:a => 返回值

  • 多个参数的:(a, b) => 返回值

  • 只有一个语句的函数:() => 返回值

  • 只返回一个对象的函数:() => ({...})

  • 有多行语句的函数:

    () => {
    	....    
    	return 返回值
    }
    

箭头函数没有自己的this,它的this由外层作用域决定,箭头函数的this和它的调用方式无关,外面的this是谁,它就是,如果在最外层,那么它的this就是window

function fn() {
    console.log("fn -->", this)
}

const fn2 = () => {
    console.log("fn2 -->", this) // 总是window
}

fn() // window
fn2() // window

const obj = {
    name:"孙悟空",
    fn, // fn:fn的简写
    fn2,
    sayHello(){
        console.log(this.name)

        function t(){
            console.log("t -->", this)
        }
        t() // window

        const t2 = () => {
            console.log("t2 -->", this)
        }
        t2() // obj
    }
}

obj.fn() // obj
obj.fn2() // window

obj.sayHello()// 

11 严格模式

JS运行代码的模式有两种:

  • 正常模式

    • 默认情况下代码都运行在正常模式中,
      • 在正常模式,语法检查并不严格,它的原则是:能不报错的地方尽量不报错
    • 这种处理方式导致代码的运行性能较差
  • 严格模式

    • 在严格模式下,语法检查变得严格

      • 禁止一些语法
      • 更容易报错
      • 提升了性能
    • 使用方式

      "use strict" // 全局的严格模式
      let a = 10
      
      function fn(){
          "use strict" // 函数的严格的模式
      }
      
      // 如果在严格模式下定义如:
      a = 10 // 则会报错a is not defined
      
  • 在开发中,应该尽量使用严格模式,这样可以将一些隐藏的问题消灭在萌芽阶段,同时也能提升代码的运行性能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/52531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【深度学习】详解 ViLT

目录 摘要 一、引言 二、背景 2.1 视觉和语言模型的分类法 2.2 模态交互模式 2.3 视觉嵌入方案 2.3.1 区域特征 2.3.2 网格特征 2.3.3 图像块投影 三、视觉和语言 Transformer 3.1 模型概述 3.2 预训练目标 3.2.1 图像文本匹配 3.2.2 掩码语言建模 3.2.3 全…

文件包含漏洞详解

文件包含漏洞详解1.文件包含漏洞介绍1.1.文件包含漏洞解释1.2.文件包含漏洞原理1.3.文件包含的函数1.3.1.常见的文件包含函数1.3.2.PHP函数区别:1.4.文件包含漏洞特征1.5.文件包含漏洞分类1.5.1.本地文件包含漏洞  1.5.1.1.本地文件包含漏洞案例1.5.2.远程文件包含…

echarts-wordcloud ——文字云制作企业标签——基础积累

最近看到同事在写文字云的效果,最终效果图如下: 使用的是echarts-wordcloud插件: 下面介绍一下使用步骤: 1.npm安装echarts-wordcloud——npm install echarts-wordcloud --save 安装echarts-wordcloud的前提是也要安装echart…

谷粒学院——Day09【整合阿里云视频点播】

❤ 作者主页:Java技术一点通的博客 ❀ 个人介绍:大家好,我是Java技术一点通!( ̄▽ ̄)~* 🍊 记得关注、点赞、收藏、评论⭐️⭐️⭐️ 📣 认真学习,共同进步!&am…

YOLOv5使用方法记录

YOLOv5使用方法记录 本次主要是记录使用yolov5检测图片和视频的过程 下载源码 地址为:https://github.com/ultralytics/yolov5 配置环境 有两种方法 按照requirements 通过下述命令安装源码中给出的配置环境文件 pip install -r requirements.txt选择自己需…

诠释韧性增长,知乎Q3财报里的社区优势和商业化价值

当内容平台开始做生意,往往意味着它要扮演一个大包大揽的角色:从内容的可持续性到最终变现,设计一套完整的生态系统是必需的。 但并非所有平台都对此感到棘手,或者说在某些平台,生态已经不是困难,而是优势…

linux内核源码分析 - nvme设备的初始化

驱动的加载 驱动加载实际就是module的加载,而module加载时会对整个module进行初始化,nvme驱动的module初始化函数为nvme_init(),如下: static struct pci_driver nvme_driver {.name "nvme",.id_table nvme_id_table,.probe nvme_probe,.remo…

leetcode 746. 使用最小花费爬楼梯

文章目录题目思考代码和注释总结题目 给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。 你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。 请你计算并返回达到…

Charles抓取接口报文并修改各种参数信息调试

1.首先介绍Charles面板 图上顶部工具栏常用介绍: 1是清除按钮:点击后将清空左侧抓取的接口列表,如果接口太多,可以点击该按钮清空列表,重新发起请求,一目了然; 2.是停止按钮:点击该按…

玩转redis(一)——基础数据结构

文章目录前言安装一、String1.常用命令和操作2.应用场景3.对应业务场景举例二、Hash1.常用命令和操作2.应用场景3.对应业务场景举例优缺点三、List1.常用命令和操作2.应用场景3.对应的业务场景举例四、Set1.常用的命令和操作2.应用场景3.对应的业务场景举例五、Zset1.常用的命令…

总结:SpringBoot内嵌Tomcat原理

一、介绍 一般我们启动web服务都需要单独的去安装tomcat,而Springboot自身却直接整合了Tomcat,什么原理呢? 二、原理 SpringBoot应用只需要引入spring-boot-starter-web中这个依赖,应用程序就默认引入了tomcat依赖,其…

[附源码]SSM计算机毕业设计疫情环境下的酒店管理系统JAVA

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

【HAL库】STM32CubeMX开发----STM32F407----ETH+LAN8720A+LWIP----ping通

STM32CubeMX 下载和安装 详细教程 【HAL库】STM32CubeMX开发----STM32F407----目录 LAN8720A数据手册(中文英文) 前言 本次实验以 STM32F407VET6 芯片为MCU,使用 25MHz 外部时钟源。 以太网PHY层芯片为 LAN8720A,由MCU引脚 PA8 提供时钟。 LAN8720A引脚…

springboot整合mybatis实现增删改查

前言 在学习Springboot过程中,整合mybatis框架实现表数据的增删改查,话不多说,开始贴代码! Spring Boot提供了一个名为spring-boot-starter-parent的工程,里面已经对各种常用依赖(并非全部)的版本进行了管理&#xff…

基于51单片机智能IC卡电表控制系统

资料编号:201 功能介绍: 采用51单片机作为主控CPU,使用按键进行模拟冲卡(模拟缴费冲卡),通过按键来控制当前是否使用电力,并且LCD1602实时显示当前电力可用量剩余多少,当电力余额不…

3. JVM对象创建与内存分配机制

1. JVM对象创建过程详解 对象创建的主要流程 1.1 分配内存空间的方法 指针碰撞(默认使用指针碰撞) 如果JAVA堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放一个指针作为分界点&#xf…

Tableau长期免费使用的方法总结

目录方法一:使用Tableau Public第一步:在Product中点击Tableau Public第二步:向下滚动找到下载链接第三步:进入下载页面点击下载方法二:每一个可下载版本滚动试用14天第一步:**resource** → **support** →…

06【SpringMVC的Restful支持】

文章目录六、SpringMVC的Restful支持6.1 RESTFUL示例:6.2 基于restful风格的url6.3 基于Rest风格的方法6.4 配置HiddenHttpMethodFilter6.5 Restful相关注解六、SpringMVC的Restful支持 REST(英文:Representational State Transfer&#xff…

.vcxproj.filters 误删后如何重建

背景: 今天碰到这样一种情况,我在删除这个VS文件夹下的.user文件时,不小心把.vcxproj.filters也删除了。当然为什么删.user呢,因为换电脑了。 删除之后,我发现:我的解决方案目录变成这样了: 对…

基于springboot企业客户信息反馈平台设计与实现的源码+文档

摘 要 网络的广泛应用给生活带来了十分的便利。所以把企业客户信息反馈管理与现在网络相结合,利用java技术建设企业客户信息反馈平台,实现企业客户信息反馈的信息化。则对于进一步提高企业客户信息反馈管理发展,丰富企业客户信息反馈管理经…