函数
一、函数的概念
- 什么是函数?
- 首先明确一点,和我们数学中的函数是两个概念
- 在 JS 中,函数可以理解为将一段在程序中多次出现的代码封装起来的盒子,以便在多个地方调用执行
- 换句话说:函数就是一个内部封装了部分代码的盒子,可以在多个位置被调用
- 函数的使用
- 创建函数(定义函数)
- 调用函数
二、函数的定义
1. 声明式定义
- 语法:
function 函数名(参数: 非必传, 暂时不写) { 函数被调用的时候需要执行的某一段代码 }
function fn() {
}
/**
* 分析:
* function:声明函数的关键字,代表接下来这段代码是一个函数
* fn:函数名,调用函数时需要使用,函数名自定义,符合命名规范和见名知意即可(!** 匿名函数时可以不写)
* ():小括号内存放函数的参数(后续讲解)
* {}:存放函数代码,调用函数时,想执行的代码都写在内部
*/
2. 赋值式定义
- 语法:
var 函数名 = function (参数: 非必传, 暂时不写) {}
var fn = function () {
}
三、函数的调用
- 调用的时候 不管如何定义, 都是使用 函数名()
- 注意: 如果一个函数只定义, 而不调用, 那么永远不会执行
function fn1() {
}
var fn2 = function () {
}
fn1()
fn2()
四、变量和函数的预解析(预解释)
变量的规则(变量提升):
- JS 在运行我们的代码的时候, 会先整体阅读一次我们的 JS 代码,此时读取完毕后, 会将变量的声明(定义) 提取到页面的最顶部(JS代码的最顶部)。
- 注意: 提升的只有变量的声明, 没有变量的赋值。那么换句话说, 也就是在变量定义前去使用, 得到的是一个 undefined
console.log(a) // undefined
var a = 100
console.log(a) // 100
/*
原本的代码
console.log(a)
var a = 100
console.log(a)
开始运行代码, 浏览器读取我们JS整体代码
读取完毕, 预解析 后的代码
var a
console.log(a) // undefined
a = 100
console.log(a) // 100
*/
函数的规则(函数提升):
- JS 在运行我们的代码的时候, 会先整体阅读一次我们的 JS 代码,此时读取完毕后, 会将声明式定义的函数 提取到页面的最顶部(JS代码的最顶部)。所以我们在书写代码的时候, 可以在 声明式定义的函数前, 去调用函数
console.log(a) // undefined
var a = function () { console.log('我是a函数') }
console.log(a) // ƒ () { console.log('我是a函数') }
/*
原本的代码
console.log(a)
var a = function () { console.log('我是a函数') }
console.log(a)
开始运行代码, 浏览器读取我们JS整体代码
读取完毕, 预解析 后的代码
var a
console.log(a) // undefined
a = function () { console.log('我是a函数') }
console.log(a) // ƒ () { console.log('我是a函数') }
*/
console.log(a) // ƒ a () { console.log('我是a函数') }
function a() {
console.log('我是a函数')
}
console.log(a) // ƒ a () { console.log('我是a函数') }
/**
原本的代码
console.log(a) // ƒ a () { console.log('我是a函数') }
function a () { console.log('我是a函数') }
console.log(a) // ƒ a () { console.log('我是a函数') }
浏览器读取我们的JS整体代码, 开始函数提升
提升后的代码:
function a () { console.log('我是a函数') }
console.log(a)
console.log(a)
*/
四、函数的参数
- 参数是什么?
- 如果没有参数,那么函数的执行功能是固定的,写好函数后内部内容将不会变
- 比如:函数内部的代码为 1 + 1,那么始终执行时始终都是 1 + 1,如果此时想要计算 1 + 2 的值,需要重新封装一个 1+2 的函数
- 参数在哪里?如何使用
- 书写函数时有一个 () 内部就是书写参数的,函数分为两种,形参---实参
- 1)形参:函数定义时小括号中书写的内容,相当于在函数中创建了一个变量 具体的值由实参提供,如果实参没有传递对应的内容,那么值为undefined
- 2)实参:函数调用时小括号中书写的内容,这里书写的内容会传递给对应的形参
function num () {
console.log(1 + 1)
}
num() // 打印值为 1+1
function num (a, b) { // 此处 a b 为形参
console.log(a + b)
}
num(1, 1) // 此处为 实参,分别传递给 a 和 b
num(1, 2) // 此处打印值为 1 + 2
注意: 函数的形参与实参是按照从左到右的顺序一一对应的
// 少传参数
function num1(a, b, c, d) {
console.log(a,b,c,d)
}
num1(1, 2, 3, 4) // 打印1,2,3,4
num1(1, 2, 4) // 打印1,2,4,undefined
num1(4) // 打印4,undefined,undefined,undefined
// 多传参数
function num2 (a) {
console.log(a)
}
num2(1, 2) // 打印 1
num2(1) // 打印 1
五、函数的返回值
- 每一个函数调用完毕后 都会有一个结果(值), 默认为 undefined
- 如果想要更改那么我们需要借助一个 关键字 return
- return 的后边可以跟 任何的数据, 包括表达式
- 注意:函数中 return 只会生效一个, 因为 return 具有中断函数的能力,所以一般 return 会写在函数的末尾。如果想要写在函数的开头, 必须结合分支语句
六、作用域
- 简单来说: 就是一个变量生效的范围
全局作用域
- 整个 script 标签内部的区域声明的变量就是在全局作用域创建
- 如果是在全局作用域创建的变量或者函数我们统称为 全局变量或者全局函数,那么能在当前代码的所有位置去使用
- JS 在全局作用域中提供了一个 对象, 叫做 window, 我们书写的所有的 全局变量或者全局函数, 都在 window 对象内部存放
局部作用域(函数作用域)
- 在一个函数内部生成的变量就是存在于局部作用域的
- 在局部作用域创建的变量只能在当前作用域内使用
七、作用域链
- 每一个作用域上一层会有一个全新的作用域, 每个作用域之间的一个连接, 我们称之为作用域链
- 如果我们在一个作用域内寻找一个变量, 那么我们会在当前作用域内查找, 如果找到直接使用;如果没有找到, 那么会继续去上一层作用域继续查找, 找到就使用, 如果没有找到继续去上一层查找。所以我们将这个层层查找的顺序之间的连接, 称之为作用域链
作用域链分为两个规则:
1. 查找规则
- 在一个作用域内查找一个变量, 如果有直接使用, 如果没有会去上一层继续查找, 如果找到直接使用, 没有的话继续去上一层查找, 直到找到了全局作用域, 找到了直接使用, 如果没有找到直接报错
- 注意: 查找的时候只会层层向上, 不会向下
2. 赋值规则
- 在一个作用域对一个变量进行赋值, 那么会先在当前作用域内查找变量, 找到直接修改, 如果没有, 会去上一层作用域查找。如果找到直接修改, 没有继续向上, 如果找到了全局作用域还是没有, 那么会在全局作用域创建一个变量, 然后对他进行赋值操作
八、递归函数
- 在编程中就是指 自己调用自己的一种手段。递归函数就是在一个函数内部调用了自身. 循环执行
- 递归函数有点类似于循环,也需要有初始化, 自增, 执行的代码, 判断条件。如果上述的内容缺少, 那么就是一个死递归, 永远不会结束
求 1~5 的所有数字相加的和
function fn(n){
if(n === 1) return 1
return n + fn(n - 1)
}
let res = fn(4)
console.log(res)
递归求阶乘
function fn(n) {
if(n === 1) return 1
return n * fn(n - 1)
}
let res = fn(5)
console.log(res) //120
使用递归封装一个函数, 能够计算出斐波那契数列中某一个位置的具体数值
function fn(n) {
if (n === 1 || n === 2) return 1
return fn(n - 1) + fn(n - 2)
}
var res1 = fn(4)
console.log(res1) //3
对象
对象是一个 复杂数据类型, 也叫做 引用数据类型
var obj = {
num: 100,
str: "hello",
boo: true,
};
- 这里的 {} 和函数中的 {} 不一样, 函数内部书写代码, 对象里面是书写数据的
- 对象就是一个键值对的集合
- 什么是键值对?
- 对象 obj 中, num 是键, 100 是值
- 对象 obj 中, str 是键, 'hello' 是值
- 对象 obj 中, boo 是键, true 是值
- 什么是键值对?
创建对象
- 字面量方式创建对象
- 语法:
var obj = {}var obj1 = {键值对, 键值对}
- 语法:
- 内置构造函数创建
- 语法:
var obj = new Object()
- 语法:
- 对象内对于 键(key) 的要求
- 推荐使用符合变量命名规则和规范的名字
- 可以使用纯数字当作 键名
- 这种情况下该属性会排列在最前面
- 可以使用任何特殊符号
- 使用特殊符号的时候,在书写时需要被引号包裹
对象数据类型的操作(增删改查)两种语法
1. 点语法
var obj = {};
obj.name = "qianfeng"; // 增
obj.name = "qianfeng123"; // 改
console.log(obj.name); // 查
delete obj.name; // 删
2. 中括号语法(数组语法)
var obj = {}
obj["name"] = "qianfeng" //增
obj["name"] = "qianfeng123" //改
console.log(obj["name"]) //查
delete obj["name"] //删
- 两者的差异
- 符合变量命名规范与规则的情况,两者并无差异
- 操作不符合变量命名规范与规则的名称时,比如纯数字或者带有特殊符号的,就只能用中括号语法
- 涉及变量相关的时候,只能使用中括号语法