highlight: a11y-dark
函数
- 什么是函数?
- 首先明确一点,和我们数学中的函数是两个概念
- 在 JS 中,函数可以理解为将一段在程序中多次出现的代码封装起来的盒子,以便在多个地方调用执行
- 换句话说:函数就是一个内部封装了部分代码的盒子,可以在多个位置被调用
- 函数的使用
- 创建函数(定义/封装函数)
- 调用函数(使用函数)
函数的定义
- 声明式定义:
- 分析:
- function:声明函数的关键字,代表接下来这段代码是一个函数
- fn:函数名,调用函数时需要使用,函数名自定义,符合命名规范和见名知意即可(!** 匿名函数时可以不写)
- ():小括号内存放函数的参数
- {}:存放函数代码,调用函数时,想执行的代码都写在内部
- 分析:
function fn() {}
- 赋值式定义:
解析同声明式
var fn = function () {
}
函数(变量)预解析
- 函数(变量)的规则 : 也可以说声明提升
- JS 在运行我们的代码的时候, 会先整体阅读一次我们的 JS 代码,此时读取完毕后, 会将
函数(变量)的声明(定义)提取到页面的最顶部(JS代码的最顶部) - 注意: 提升的只有函数(变量)的声明, 没有变量的赋值;在定义前去使用, 得到的是一个undefined
- JS 在运行我们的代码的时候, 会先整体阅读一次我们的 JS 代码,此时读取完毕后, 会将
函数的调用
function fn1() {
}
var fn2 = function () {
}
fn1()
fn2()
函数的参数
- 含义 :将函数的执行方式由固定的改变为灵活的。
- 函数书写在()内,数量不限;参数分为两种,形参---实参
- 形参和实参的区别
- 形参:在函数声明时 function 后边的()内书写,每写一个参数,就相当于在函数内部创建一个变量,其值为函数调用时传递的值,只能在函数内部使用,不能在外部使用
- 实参:顾名思义,实际的参数,也就是函数在调用时传递的参数
演示
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
-
参数默认值
ES5写法:
function fn (a,b) {
if (b === undefined) {
b = '默认值'
}
}
ES6写法:
function fn (a,b = '默认值') {
}
函数的返回值
- 返回值是什么?有什么作用
- 函数内部默认有一个 return 他的值就是函数的返回值,如果函数内部不写 return 那么函数默认在函数体内部最底部返回一个 undefined
- 如果不想返回 undefined 需要手动在函数内部写上 return 并且跟上需要返回的值
- 可以中断函数(后续通过代码演示)
function num (a, b) {
a+b
}
var ab = num(1,2)
console.log(ab)
function num (a, b) {
return a + b
// console.log('函数内部执行的 a + b =',a+b)
}
var ab = num(1,2)
console.log('函数外部执行的 a + b =',ab)
作用域
- 含义 : 一个变量(函数)生效的范围
- 全局作用域
- 整个 script 标签内部声明的变量就就是在全局作用域创建
- 在全局作用域创建的变量或者函数我们统称为 全局变量或者全局函数
- 能在当前代码的所有位置去使用
- JS 在全局作用域中提供了一个 对象, 叫做 window, 我们书写的所有的 全局变量或者全局函数, 都在 window 对象内部存放
- 局部作用域
- 在一个函数内部生成的变量就是存在于局部作用域的,在局部作用域创建的变量只能在当前作用域内使用
作用域链
概念 :每一个作用域上一层会有一个全新的作用域, 每个作用域之间的一个连接, 我们称之为作用域链
解释 :如果我们在一个作用域内寻找一个变量, 那么我们会在当前作用域内查找, 如果找到直接使用,如果没有找到, 那么会继续去上一层作用域继续查找, 找到就使用, 如果没有找到继续去上一层查找。所以我们将这个层层查找的顺序之间的连接, 称之为作用域链
- 作用域链的规则
- 查找规则 :在一个作用域内查找一个变量, 如果有直接使用, 如果没有会去上一层继续查找, 如果找到直接使用, 没有的话继续去上一层查找。
注意: 查找的时候只会层层向上, 不会向下 - 赋值规则 : 在一个作用域对一个变量进行赋值, 那么会先在当前作用域内查找变量, 找到直接修改, 如果没有, 会去上一层作用域查找,如果找到直接修改, 没有继续向上, 如果找到了全局作用域还是没有, 那么会在全局作用域创建一个变量, 然后对他进行赋值操作
- 查找规则 :在一个作用域内查找一个变量, 如果有直接使用, 如果没有会去上一层继续查找, 如果找到直接使用, 没有的话继续去上一层查找。
递归函数
- 递归函数就是一个函数直接或间接地调用自身
- 斐波那契数列
// 斐波那契数列
// 1 1 2 3 5 8 13 21 34 55
// 递归函数
const fn = (m) => {
if (m === 1 || m === 2) {
return 1
}
return fn(m - 2) + fn (m - 1)
}
console.log(fn(4));
递归函数---斐波那契原理
对象
- 含义:
- 对象是一个 复杂数据类型, 也叫做 引用数据类型
- 虽然我们说是复杂类型, 但是也没有很复杂, 只不过是存储了一些基本数据类型的集合
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) 的要求
- 推荐使用符合变量命名规则和规范的名字
- 可以使用纯数字当作 键名
- 这种情况下该属性会排列在最前面
- 可以使用任何特殊符号
- 使用特殊符号的时候,在书写时需要被引号包裹
对象数据类型的操作(增删改查)两种语法
- 点语法
var obj = {}; obj.name = "qianfeng"; // 增 obj.name = "qianfeng123"; // 改 console.log(obj.name); // 查 delete obj.name; // 删 - 中括号语法(数组语法)
var obj = {}; obj["name"] = "qianfeng"; // 增 obj["name"] = "qianfeng123123"; // 改 console.log(obj["name"]); // 查 delete obj["name"]; // 删 - 两者的差异
- 符合变量命名规范与规则的情况,两者并无差异
- 操作不符合变量命名规范与规则的名称时,比如纯数字或者带有特殊符号的,就只能用中括号语法
- 涉及变量相关的时候,只能使用中括号语法
数组
-
定义 :
准确的说法应该是
存放数据的的集合
var arr = [1, 2, 3, "qwe", "abc", true, false, undefined, null];
// 我们把一堆数据存放到一个盒子中, 这就叫做数组 对应我们上述的 数组是存放一些数据的集合
数组的创建
- 字面量创建:
//创建一个空数组
var arr = [];
//创建一个有内容数组
var arr2 = [1,2,3]
- 内置构造函数创建数组:
- 可以先设置数组的长度,使里面的值为empty
// 创建一个空数组
var arr = new Array()
// 创建一个有长度的数组
var arr1 = new Array(5)
// 创建一个有内容的数组
var arr2 = nee Array(4,5,6)
数组的length属性
- length: 表示数组长度,数组内有多少个数据;
var arr = [1, 2, 3];
console.log(arr.length); // 3
var arr1 = [4, 5];
console.log(arr1.length); // 2
数组的索引
- 定义:索引也叫下标,指每个数据在数组中排列的位置,
- 注意:在所有的语言中,索引都是从0开始的。
var arr = ["hello", "world"];
console.log(arr[0], arr[1]); //'hello','word'
for循环遍历数组
- 定义:遍历数组就是想办法拿到数组的每一个元素, 通常我们可以通过下标获取到元素的某一项, 所以我们只需要想办法拿到数组的所有下标即可
案例1:
// 数组遍历
var arr = [1,2,3,4,5,6,7,8,9,10];
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
案例2:
// 找出数组中的最大值
var max = arr[0];
for (var i = 0; i < arr.length - 1; i++) {
if (arr[i+1] > max) {
max = arr [i+1];
}
}
console.log(max);
案例3:
// 2. 计算数组中所有内容相加的和
var sum = 0;
for (var i = 0; i < arr.length; i++) {
sum += arr[i];
}
console.log(sum);
冒泡排序
var arr = [9, 6, 3, 1, 4, 7, 8, 2, 5];
console.log(arr);
// 决定执行几轮 数组九个数据,8次确定了8个数据,最后一个自然也确定了,所以不用执行第九次了
for (var i = 0; i < arr.length - 1; i++) {
// 决定比较次数
// arr.length - 1 - i - i是为了减少比较次数,执行一次最大的数到了最后面,下面的
// 循环可以不用比较了 -1是因为arr[arr.length - 1] >arr[arr.length]没意义,
// arr[arr.length]没有数据
for (var j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j+1]) {
var temp = arr[j];
arr[j] = arr[j+1]
arr[j+1] = temp;
}
}
}
console.log(arr);
选择排序
var arr = [9, 6, 3, 1, 4, 7, 8, 2, 5];
console.log(arr);
for (var i = 0; i < arr.length - 1; i++) {
// 假设arr[i] 是最小值 ,把i赋值给minIndex
var minIndex = i;
// 依次比较,本身不用比较,所以 j=i+1
for (var j = i + 1; j < arr.length; j++) {
// 如果arr[minIndex]不是最小,交换索引值
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// 如果后面没有比arr[minIndex]更小的(minIndex=i),那么判断为假,不进行交互
if (minIndex !== i) {
var temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
console.log(arr);