# JavaScript 笔记

# 常用效果插件

# 基本概念

# 预解析

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

  1. JavaScript 引擎运行 JavaScript 分为两步:预解析、代码执行

    • (1) 预解析 JavaScript 引擎会把 JavaScript 里面所有的 let 还有 function 提升到当前作用域的最前面
    • (2) 代码执行按照代码书写的顺序从上往下执行
  2. 预解析分为变量预解析(变量提升)和函数预解析(函数提升)

    • (1) 变量提升:把所有的变量声明提升到当前的作用域最前面,不提升赋值操作
    • (2) 函数提升:把所有的函数声明提升到当前作用域的最前面,不调用函数
let num = 10;
function fn(){
    console.log(num);
    let num = 20;
    console.log(num);
}
fn();

// 相当于以下代码:
let num;
function fn(){
    let num;
    console.log(num);
    num = 20;
    console.log(num);
}
num = 10;
fn();

// 结果:
// undefind
// 20

# 基本语法

# 注释

  • 单行注释

    //注释内容
    
  • 多行注释

    /*
      注释内容
      注释内容
    */
    

# 声明变量

提示

变量区分大小写

let 变量名;

# 声明常量

提示

常量区分大小写

const 变量名;

# 解构赋值

提示

  • 左右两边结构必须一样
  • 右边必须是个东西
  • 声明和赋值赋值不能分开,必须在一句话里
// 解构 Object 对象
let 变量 = {元素1:, 元素2:};
const {元素1, 元素2} = 变量;

// 解构数组
let [元素1, 元素2, 元素3] = [1, 2, 3];
console.log(元素1, 元素2, 元素3)

let [元素1, 元素2, 元素3, 元素4] = [{ :, :}, [1, 2, 3], 8, "字符串"]
console.log(元素1, 元素2, 元素3, 元素4)

# 数据类型

提示

  • ture 参与加法运算当 1 来看, false 参与加法运算当 0 来看;
  • Undefined 和 数字相加 最后的结果是 NaN (Not a number);
  • nubmer : 数值
    • float : 浮点型
  • string : 字符串
  • boolean : 布尔值
  • undefined : 声明了变量但没有赋值,此时变量的值为 Undefined
  • null : 声明的变量为空值
  • object : 对象

# 数据类型转换

提示

转布尔除 ""0undefinednullNaN值均为 true

  • 转数字:
    • 转整数parseInt(变量)
    • 转浮点parseFloat(变量)
    • 强制转换:Number(变量)
    • 隐式转换:"10" - 0
  • 转文本:
    • 强制转换:String(变量);
    • 转成字符串: 变量.toString()
    • 加号拼接字符串变量 + "字符串"
  • 转布尔:Boolean(变量)

# 获取数据类型

typeof 变量;

# 判断是否为数字

如果是数字则返回 true,不是则返回 false

isNaN();

# 关系运算符

  • 等于 : ==
  • 恒等于 : == (检查数据类型)
  • 不等于 : !=
  • 大于 : >
  • 小于 : <>
  • 小于等于 : >=
  • 大于等于 : <=

# 与或非

  • 与:&&
  • 或:||
  • 非:!

# 三元运算符

返回值 = 条件 ? 返回值-: 返回值-;
let a = x > 10 ? 'red' : 'blue';

# 取余运算符

在 JavaScript 中可以通过取余运算符%实现数值取余

const result = 6 % 2;

# 四舍五入

将数字四舍五入,转为指定小数位的数字,返回字符串。

变量.toFixed(小数位数);

const num = 100.153;
console.log(num.toFixed(1)); // 100.1
console.log(num.toFixed(2)); // 100.15

# 打印内容

console.log('打印内容');

# 弹出提示

alert("提示信息");

# 跳转页面

location.assign("URL");

# 自动补齐数字

需要补充的数字.padStart(位数,填充数字)

# 控制流

# if 语句

if (条件) {
} else {
}

# switch 语句

switch () {
  case1:
    break;
  case2:
    break;
  default:
    break;
}

# for 循环语句

实现条件循环,当条件成立时,执行语句集,否则跳出循环体。

for(let 变量=初始值;条件;变量++){

}

# while 循环语句

while 语句是带条件判断的循环语句。如果条件满足,则持续循环执行结果语句块。

while (条件) {}

# 函数

# 声明写法

/**
 * 函数说明
 * @author 作者
 * @version	@version 版本号
 * @param {参数类型} 参数说明
 * @return {返回值类型}
 */
function 函数名() {

}

function 函数名(参数1, 参数2 = 默认值) {
    return 返回值;
}

# 表达式写法

命名函数表达式:

let 变量 = function 函数名() {

};

// 使用
变量();

匿名函数表达式:

let 变量 = function() {

};

// 使用
变量();

提示

{}后加()即可成为立即执行函数

# 可变参

提示

所有参数会放在函数的arguments对象中,可当作数组使用。
arguments 对象是伪数组,没有数组的一些方法(如 pop()、push())

function 函数名() {
  console.log(arguments)
}

# 剩余参数

收集剩余的参数,必须当到最后一个参数位置

function 函数名(参数1, 参数2, ...剩余参数) {
  console.log(参数1, 参数2, 剩余参数);
}

# 立即执行函数

立即执行函数,IIFE(Immediately Invoked Function Expression),定义后便会立即执行的函数,返回值为undefine

(function() {

}())

# 箭头函数

箭头函数不绑定 this,也不绑定 argument 数组

const 箭头函数 = () => {

};

const 箭头函数 = (参数1, 参数2) => {

};

# 纯函数

在程序设计中,若一个函数符合以下条件,那么这个函数被称为纯函数:

  1. 确定的输入,一定会产生确定的输出
  2. 函数在执行过程中,不能产生副作用(不能修改原参数)

为什么纯函数在函数式编程中非常重要呢?

  • 因为可以安心的写和安心的用
  • 在写的时候保证了函数的纯度,只是但是实现自己的业务逻辑即可,不需要关心传入的内容或者依赖其他的外部变量
  • 在用的时候,确定了输入内容不会被任意篡改,并且自己确定的输入,一定会有确定的输出
// 纯函数
function sum(num1, num2) {
  return num1 + num2;
}

// 纯函数
function pringInfo(info) {
  console.log(info.name, info.age);
}

// 不是纯函数
let foo = 10
function add(num) {
  return foo + num;
}

add(5); //15
foo = 20;
add(5); //25

// 不是纯函数
const baz = {
  count: 10,
}

function add3(num) {
  return bar.count + num;
}

baz.count = 20;

# 类和方法

# 声明类

class 类名 {
  //构造函数
  constructor(参数) {
    this.属性 = 参数;
    this.属性 = 属性值;
  }
  方法名() {

  }
}

# 实例化类

let 对象 = new 类名();
// 使用类属性
console.log(对象.属性);
// 调用类方法
对象.方法名();

# 继承类

class 类名 extends 继承类名 {
  // 子类中必须初始化父类对象
  super();
}

# 数组

# 声明

// 字面量声明
let 数组名 = ["值1", "值2", "值3", "值4"];

// new Array
let 数组名 = new Array(); // 创建空数组
let 数组名 = new Array(10); // 创建长度为10的数组
let 数组名 = new Array(1,2); // 创建数组:[1,2]

# 使用

console.log(数组名[0]);
// 展开使用
console.log(...数组名);

# 获取数组长度

console.log(数组名.length);

# 判断是否为数组

  • instanceof 运算符

    console.log(数组名 instanceof Array);
    
  • Array.isArray

    console.log(Array.isArray(数组名));
    

# 获取指定数据索引

如果存在返回索引号,不存在则返回-1。

提示

只返回满足条件的第一个索引

数组名.indexOf(指定数据);

# 获取最后一个索引

如果存在返回索引号,不存在则返回-1。

数组名.lastIndexOf();

# 遍历数组

  • 值遍历

    for (let item of 数组名) {
      console.log(item);
    }
    
  • forEach

    数组名.forEach((item,index)=> {
      console.log(index,item);
    })
    
  • 下标遍历

    for (let n in 数组名) {
      console.log(数组名[n]);
    }
    

# 增加元素

  • 在数组最前面增加元素(支持多个参数),返回值为新数组的长度

    数组名.unshift(元素名称);
    
  • 在数组最后增加元素(支持多个参数),返回值为新数组的长度

    数组名.push(元素名称);
    

# 修改元素

数组名[下标] =;

# 删除元素

  • 删除数组第一个元素

    数组名.shift();
    
  • 删除数组最后的一个元素

    数组名.pop();
    

# slice

提示

slice()方法不会改变原数组

新数组 = 数组.slice(起始位置, 结束位置);

// 取前4位元素
新数组 = 数组.slice(0, 4);

# splice

提示

splice()方法会改变原数组

//删除元素
数组名.splice(位置, 删除几个元素);
//插入元素
数组名.splice(位置, 0, 插入的元素[, 插入的元素]...);
//替换元素
数组名.splice(位置, 替换几个元素, 替换的值[, 替换的值]...);
//截取元素个数
数组名.splice(起始位置, 结束位置);

# 颠倒数组

数组.reverse();

# 数组排序

提示

sort()方法默认按照转换为的字符串的诸个字符的 Unicode 位点进行排序,因此需要指定一个排序函数。

  • 升序的顺序

    数组名.sort(function (a, b) {
      return a - b;
    });
    
  • 降序的顺序

    数组名.sort(function (a, b) {
      return b - a;
    });
    

# 拼接数组

concat()方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3 = array1.concat(array2);

# 数组去重

function unique(arr) {
  let newArr = [];
  for(let i = 0; i < arr.length;i++){
    if(newArr.indexOf(arr[i]) === -1){
      newArr.push(arr[i]);
    }
  }
  return newArr;
}

# 数组转字符串

  • toString

    let arr = [1,2,3];
    console.log(数组名.toString()); //1,2,3
    
  • join

    let arr = ["a","b","c"];
    
    console.log(arr.join()); //a,b,c
    console.log(arr.join("-")); // a-b-c
    console.log(arr.join("&")); // a&b&c
    

# Object 对象

# 声明

let 对象名 = {
  键名1:,
  键名2: ["数组1", "数组2", "数组3"],
  键名3: {
    内嵌键名1:,
    内嵌键名2:,
  },
  函数名: function() {

  }
};

# 使用

console.log(对象名.键名);
console.log(对象名["键名"]);
对象名.函数名();

# 增加元素

对象名.键名 =;

# 修改元素

对象名.键名 =;

# 遍历元素

for (const key in 对象名) {
  console.log(对象名[key]);
}

# Set 集合

Set 集合中的元素不可重复

# 声明

let 集合名 = new Set();

# 集合方法

  • 增加元素
集合名.add(元素);
  • 删除元素
集合名.delete(元素);
  • 清空集合
集合名.clear();
  • 判断元素是否存在

存在返回 true,不存在返回 false

集合名.has(元素);
  • 获取集合大小
集合名.size;
  • 遍历集合
集合名.forEach((item) => {
  console.log(item);
});

# 转换数组

lety 数组名 = Array.from(集合名);

# 字符串

# 字符串的不可变

指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。所以字符串不能大量拼接,会消耗性能。

  • 拼接字符串,消耗性能

    let str = "";
    for (let i = 1; i <= 1000000; i++) {
      str += i;
    }
    console.log(str);
    
  • 数组形式拼接,效率较高

    let arr = [];
    for (let i = 1; i <= 1000000; i++) {
      arr.push(i);
    }
    console.log(arr.join(""));
    

# 模板字符串

const 变量 = `字符串:${变量}`;

# 字符串的拼接

提示

只要有字符串和其他类型相拼接,最终的结果是字符串类型。

提示

数值相加,字符相连

let 字符串 = "文本" + "文本"; // 文本文本
let 字符串 = "文本" + 1; // 文本1
let 字符串 = "文本" + ture; // 文本ture

# 寻找字符串

  • 找到则返回字符串所在的位置,否则返回-1

    let 位置 = 字符串.indexOf(寻找的字符串,[起始位置]);
    
  • 从后往前寻找字符串,找到则返回字符串所在的位置,否则返回-1

    let 位置 = 字符串.lastIndexOf(寻找的字符串,[起始位置]);
    

# 根据位置返回字符

  • 返回指定位置的字符(从 0 开始)

    字符串.charAt(位置);
    
  • 返回指定位置的字符的 ASCII 码

    字符串.charCodeAt(位置);
    
  • 获取指定位置处字符

    字符串.str(位置);
    

# 获取字符串长度

let 长度 = 字符串.length("字符串");

# 分割字符串

let 集合 = 字符串.split("需要分割的文本");

# 截取字符串

  • 截取指定个数

    字符串.substr(起始位置,字符个数);
    
  • 截取指定位置,区间:[起始位置,结束位置)

    字符串.slice(起始位置,结束位置);
    
  • 截取指定位置,不接受负值,区间:[起始位置,结束位置)

    字符串.substring(起始位置,结束位置);
    

# 替换字符串

提示

replace() 方法只会替换第一个字符

/**
 * 替换字符串
 * @param {String} str 字符串
 * @param {String} subStr 需要替换的字符串
 * @param {String} replacement 替换内容
 * @return {String}
 */
function replaceString(str, subStr, replacement) {
  let result = str;
  while (result.indexOf(subStr) !== -1) {
    result = result.replace(subStr, replacement);
  }
  return result;
}

# 遍历字符串

  • for 循环

    let str = "abcd";
    for (let i = 0; i < str.length; i++) {
      console.log(str[i]);
    }
    
  • for of

    let str = "abcd";
    for (let char of str) {
      console.log(char);
    }
    
  • for in

    let str = "abcd";
    for (let i in str) {
      console.log(str[i]);
    }
    

# 获取字符Unicode 编码

string.charCodeAt(index)

let str = "Hello World";
let unicode = str.charCodeAt(0);

# Json

# Object 转 Json 对象

JSON.stringify(Object);

# Json 对象 转 JavaScript 对象

JSON.parse(Json);

# Math 类

# 圆周率

Math.PI

# 向上取整

将小数向上取整,如 4.5 为 5

Math.ceil(数字);

# 向下取整

将小数向下取整,如 4.5 为 4

Math.floor(数字);

# 取绝对值

Math.abs(数字);

# 取最大值

返回给定的一组数字中的最大值。如果给定的参数中至少有一个参数无法被转换成数字,则会返NaN

Math.max(1,10,20)

# 取最小值

返回给定的一组数字中的最小值。如果给定的参数中至少有一个参数无法被转换成数字,则会返NaN

Math.min(1,10,20)

# 四舍五入

其他数字都是四舍五入,但是.5 特殊,它往大了取

Math.round(数字);

# 幂函数

// x^y
Math.pow(x,y);

# 生成随机数

Math.random()会返回区间[0,1)的随机小数

/**
 * 取随机数,区间为:[最小值,最大值]
 * @param min 最小值
 * @param max 最大值
 */
function randomNum(min, max) {
  return Math.floor(Math.random() * (max - min) + min);
}

# Date 类

提示

Date() 是一个构造函数,必须使用 new 来创建日期对象

# 获取当前时间

如果没有参数则返回当前时间

let date = new Date();

# 创建日期对象

参数常用的写法:

  • 数字型: 2019、10、01
  • 字符串型: "2019-10-1 8:8:8"
let date = new Date("2019-10-1 8:8:8");

// 返回当前年份
date.getFullYear();
// 返回当前月份(从0开始,需要+1)
date.getMonth() + 1;
// 返回当前日
date.getDate();
// 返回星期几(周一返回1,周六返回6,但周日返回的是0)
date.getDay() + 1;

// 返回小时
date.getHours();
// 返回分钟
date.getMinutes();
// 返回秒
date.getSeconds();

# 获取总毫秒数(时间戳)

提示

时间戳永远不会重复

获取距离1970 年到当前时间的总毫秒数。

Date.now();

# 格式化时间

使用:

const date = new Date(时间( 秒) * 1000);
console.log(formatDate(date, 'yyyy-MM-dd hh-mm'));
点击查看代码
/**
 * 格式化时间
 * @param {Date} date 时间
 * @param {String} fmt 需要格式化的格式
 */
export function formatDate(date, fmt) {
  if (/(y+)/.test(fmt)) {
    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
  }
  let o = {
    'M+': date.getMonth() + 1,
    'd+': date.getDate(),
    'h+': date.getHours(),
    'm+': date.getMinutes(),
    's+': date.getSeconds()
  };
  for (let k in o) {
    if (new RegExp( `(${k})` ).test(fmt)) {
      let str = o[k] + '';
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));
    }
  }
  return fmt;
};

function padLeftZero(str) {
  return ('00' + str).substr(str.length);
};

# Generator

Generator 是生成器函数,每一次使用迭代器的 next 方法便会返回一个新的返回值,直到返回值使用完毕返回 undefined

# 定义生成器

function* 生成器函数名() {
  yield 返回值1;
  yield 返回值2;
  yield 返回值3;
}

# 使用迭代器

调用一次 next,就会消耗一次迭代器

const 迭代器 = 生成器函数名();
console.log(迭代器.next().value);
console.log(迭代器.next().value);

# 高阶函数

高阶函数:至少满足一下条件之一:

  • 接受一个或多个函数作为输入
  • 输出一个函数

# filter

filter函数一般用于过滤满足条件的数组数据

回调函数有三个参数:

  • 参数一:执行时的对应元素
  • 参数二:对应的下标值
  • 参数三:完整的数组对象

filter 中的的回调函数需要返回一个布尔值

  • true : 函数内部会自动将这次回调的 item 加入到新的数组中
  • false : 函数内部会过滤掉这次的 item
let 新数组名 = 数组名.filter((item) => {

});
//需求:过滤数组中小于50的数字
let nums = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
let newnubs = nums.filter((item) => {
  return item < 50;
});
console.log(newnubs);
//结果:[10, 20, 40, 50]

# map

map函数一般用于批量改变数组中的数据

回调函数有三个参数:

  • 参数一:执行时的对应元素
  • 参数二:对应的下标值
  • 参数三:完整的数组对象

返回值为加入到新的数组中的数据

let 新数组名 = 数组.map((item) => {

});
//需求:将数组中的左右数据都乘2
newnubs = [10, 20, 40, 50];
let new2nums = newnubs.map((item) => {
  return item * 2;
});
console.log(newnubs);
//结果:[20, 40, 80, 100]

# reduce

reduce一般对数组中的所有内容进行汇总(例如将数组中的数据相加/相乘,返回一个总和)

新数组名称 = 数组名称.reduce((上一次值, item) => {

}, 初始值);
//需求:将数组内的所有数字进行求和
new2Nums = [20, 40, 80, 100];
total = new2Nums.reduce((preValue, item) => {
  return preValue + item;
}, 0);
console.log(total);
//结果:240

# Promise

Promise 让异步操作写起来,像在写同步操作的流程,不必一层层地嵌套回调函数。

特点:

  • 改善了可读性,对于多层嵌套的回调函数很方便
  • 充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口

# 定义

  • 基本使用
let Promise名 = new Promise((resolve, reject) => {
  if (1 === 1) {
    resolve("成功");
  } else {
    reject("失败");
  }
});
  • 传参
function Promise名(参数名) {
  return new Promise((resolve, reject) => {
    if (1 === 1) {
      console.log(参数名);
      resolve("成功");
    } else {
      reject("失败");
    }
  });
}

# 使用

  • 基本使用

    Promise名.then((res) => {
      console.log(res);
    }).catch((err) => {
      console.log(err);
    });
    
  • 传参

    Promise名("aaa").then((res) => {
      console.log(res);
    }).catch((err) => {
      console.log(err);
    });
    
  • 链式调用

    new Promise((resolve, reject) => {})
      .then((res) => {
        //对结果进行处理
        return res + 1;
      })
      .then((res) => {
        //对结果进行处理
        return res + 1;
      })
      .then((res) => {
        //对结果进行处理
        return res + 1;
      })
      .catch((err) => {
        // 错误处理
      });
    

# Promise.all

将多个 Promise 对象实例包装,生成并返回一个新的 Promise 实例

promise 数组中所有的 promise 实例都变为 resolve 的时候,该方法才会返回,并将所有结果传递 results 数组中 promise 数组中任何一个 promise 为 reject 的话,则整个 Promise.all 调用会立即终止,并返回一个 reject 的新的 promise 对象

const p1 = Promise名(参数);
const p2 = Promise名(参数);

Promise.all([p1, p2]).then((res) => {
  console.log(res);
});

# Promise.race

Promise.race() 类似于 Promise.all() ,区别在于它有任意一个完成就算完成

const p1 = Promise名(参数);
const p2 = Promise名(参数);

Promise.race([p1, p2]).then((res) => {
  console.log(res);
});

# Async Await

async、awai 是 Promise 的一个语法糖:

  • 可以将 await 关键字后面执行的代码,看做是包裹在(resolve,reject)=>{函数执行}中的代码;
  • await 的下一条语句。可以看做是 then(res =>{函数执行})中的代码;
async function 函数名() {
  console.log(1)
  await console.log(2)
}

# 原型

# 基本概念

原型链是以对象为基准,以__proto__为链接的这条链条一直到Object.prototype的链叫做原型链。

  • prototype: 原型。函数的一个属性:对象。
  • __proto__: 原型链(链接点)。对象Object的一个属性:对象。

对象的__proto__保存着该对象的构造函数的prototype

# 原型链

function fn() { 
  this.a = 1;
}

fn.prototype.b = 2;
console.log(fn.b);    // 2

Object.prototype.c = 3
console.log(fn.c);    // 3

// 判断属性是否存在
fn.hasOwnProperty("a");   // true
console.log("c" in fn);   // true

对应原型链结构:

fn {
  a: 1;
  b: 2;
  __proto__: Object.prototype = {
    c: 3;
  }
}
最后更新: 2023/6/25 10:37:51