javascript

介绍

  • 文档
    • https://www.w3cschool.cn/javascript/dict.html
    • https://edu.aliyun.com/course/313615/
    • https://developer.mozilla.org/zh-CN/docs/web/javascript

javaScript是什么

  • js是运行在客户端(浏览器)的编制语言,实现人机交互效果
    • 网页特效、表单验证、数据通信
    • 服务端语言nodejs
  • js组成部分
    • ECMAScript
      • 规定了js的基础语法
      • 比如:数据类型、变量、语句、对象等
    • WebApi
      • DOM:文档对象,页面元素的增删改查等
      • BOM:浏览器对象,操作窗口、路由、数据缓存等

javaScript书写位置

  • 内部script,直接在html中写script脚本
  • 外部script,通过script标签的src属性引入外部脚本
  • 内连script,写在DOM元素的事件中

javaScript的注释

  • 单行注释 //
  • 多行注释 /* */
  • 结束符分号 ;

输入和输出语法

  • document.write() 向页面输入内容,替换页面内容
  • window.alert() 弹框
  • window.prompt() 弹出输入对话框
  • 字面量:在计算机科学中,用于表示事/物的量词,如:3.1415926、'a'、{}、[]
  • console.log() 控制台输出

变量

  • 定义:用于存储数据的容器,它使得计算机变得有记忆
  • 变量声明:关键字(var let const) 变量名
    • 可以一次声明多个变量,中间用逗号隔开
  • 变量赋值:变量名 = 数据
  • 变量初始化:关键字 变量名 = 数据
  • 特点:变量的值是可变的
  • 本质:是程序在内存中申请的一块用来存放数据的空间
  • 命名规则
    • 不能使用关键字
    • 只能用数字、字母、下划线、$
    • 不能以数字开头
    • 字母大小写敏感
  • 行业规范
    • 语义化
    • 遵循小驼峰命名
  • 使用var 声明变量
    • 有变量提升,可以先使用、后声明
    • 可以重复声明
    • 没有块级作用域
  • 使用let 声明变量
    • 没有变量提升
    • 块级作用域有效
    • 可以重新赋值
  • 常量:使用const声明的变量称为常量
    • 常量的值不可变,不可重新赋值
    • 块级作用域有效,没有变量提升
    • 不可以重复声明
var n = 1;
let n2 = 2;
const n3 = 3;
n4 = 4;// - 未使用关键字,直接赋值的变量会被当前window的属性,属于全局变量

数据类型

  • 基本数据类型:在栈内存中存储的是值,因此也叫值类型
    • number 数字
      • 可以是整数、小数、负数
      • NaN 特殊的数字描述,not a number。NaN != NaN
    • string 字符串
      • 单引号和双引号没有本质的区别,推荐使用单引号
      • +号遇到字符串,就不再是数学意义上的加法,而是字符串拼接
      • 模板字符串:写在反引号中的字符串
    • boolean 布尔值
      • 只有两个值:true真 false假
    • null 空值,官方解释为:尚未创建的对象
      • typeof null 返结果是'object'
      • Object.prototype.proto 是null
    • undefined 未定义(赋值)
      • 已声明未赋值的变量
      • undeclared 是未声明的意思
let num = 1111;
let str = "aaa";
let str2 = `aaa ${num} bbb`;//模板字符串
  • 引用数据类型/复杂数据类型,在栈内存中存储的是数据的地址引用,真正的数据存储在堆内存中
    • Object(Array, Function)
    • 数组
      • 数组中的数据是按顺序存储的,每个数据都有自己的编号,从0开始以次类推
      • 数组中的编号也称:索引或下标
      • 数组可以存储任意类型的数据
      • 元素:数组中的每一项数据,通过下标可以获取
      • 长度:数组中的数据个数,通过length属性获得
// - 数组声明
let arr = [1,2,3]
let arr1 = new Array(1,2,3)//[1,2,3]
let arr2 = new Array(2)//[empty × 2] 只有一个参数时,认为是数组的length
// - 判断一个变量是否是数组
// - Object.prototype.toString.call([])
// - Array.isArray([])
// - [].splice
  • typeof

    • 数据类型检测
    • typeof xxx
    • typeof(xxx)

类型转换

  • 隐式类型转换
    • 执行某些运算时,系统内部自动的类型转换
    • +号两边只要有字符串,都会把另外一个转成字符串
    • 除了+号外,其他的算术运算,都会把数据转成数字类型再计算
      • ''、[]、null 会转成0
      • undefined 转为数字时会变成NaN
  • 显示类型转换
    • 转为数字类型
      • Number、parseInt、parseFloat
      • +号作为正号解析,可以将数字字符串转成数字,如:+'123'
  • Boolean类型的转换规则
    • 为假的情况:''、0、0.0、undefined、null、false、NaN、[]
    • 其余的情况全为真
console.log(!{})//false
console.log(false == {})//false
console.log(Number({}))//NaN

console.log(![])//false
console.log(false == [])//true
console.log(Number([]))//0

运算符

  • 赋值运算符:=、+=、-=、*=、/=、%=
  • 一元运算符:自增++、自减--
  • 比较运算符:>、<、>=、<=、==、===、!=、!===
    • 字符串比较,是比较其中字符对应的ASCII码值,从左往右依次比较
    • NaN不等于任何值,包括它本身
    • 小数因为有精度丢失的问题,所以比较结果不准确
    • 不同类型的数据进行比较,会发生数据类型转换
  • 逻辑运算符
    • 与&&:遇到假则为假,返回假,否则返回真
    • 或||:遇到真则为真,返回真,否则返回假
    • 非!:取反
  • 运算符优先级
    • 赋值运算符最低,括号优先级最高
let n = 1;
let n2 = n++ //先赋值后自增
let n3 = ++n //先自增后赋值

let n4 = n || 1 + 2//当n为假时执行1+2代码逻辑并把结果赋给n4,当n为真时会把n的值赋给n4,中止后面的代码,这称为逻辑中断,这种语句也叫做短路语句

语句

  • 断点调试:debugger
  • 表达式语句:可以被求值的代码
  • 普通语句:一段可以执行的代码,不一定有计算结果
  • 分支语句:单分支、双分支、多分枝
    • if 语句
    • 三元运算/三目运算:a ? b : c
    • switch 语句
      • 遇到break或return跳出
  • 循环语句
    • while循环
      • 三要素:其实变量/条件、终止条件、变量变化
    • do while循环
    • for循环
    • break:跳出循环
    • continue:结束本次循环,进入下一次循环
let n = 1;
if(n===1){} else if(n===2){} else {}
switch(n){
    case 1:
        console.log('1')
        // break; //这里如果case 1:成立,而不使用break跳出,后面的case将不在对比,直接执行后续代码
    case 2:
        console.log('2')//如果上面的case 1:成立,而没有使用break跳出,这里的代码也会执行
        break;
    default:
        console.log('default')
        break;
}
//给循环做标记
pfor:for(let i = 0; i < 10; i++){
    for(let j = 0; j < 10; j++){//嵌套循环
        console.log(i, '--', j)
        if(i === 2 && j === 5){
            break pfor;//跳出指定循环
        }
    }
}
//无限循环
// for(;;){}

数组

  • 增删改查api
    • push(数据,...) 向后新增数据,返回数组长度
    • unshift(数据,...) 向前新增数据,返回数组长度
    • pop() 从后面删除数据,每次删除一个元素,返回被删除的元素
    • shift() 从前面删除数据,每次删除一个元素,返回被删除的元素
    • splice(起始位置,删除个数, [要插入的数据]) 数据截取,返回被删元素组成的数组
    • indexOf 查索引
    • slice(起始位置,结束位置) 返回一个新数组
  • 排序api
    • [].sort() 默认生序
  • [].concat 数组拼接,返回一个新数组
  • [].join() 把数组按照指定的key拼接成字符串,默认按逗号拼接
let arr = [1,2,3]
const str = arr.join(',')//按逗号拼接
// 数组遍历
for(let i = 0; i < arr.length; i++){}
// 数组取值并修改
arr[0] = 'a'
// 排序
arr.sort((a,b) => {
    return a - b// 返回值>=0不交换,小于0交换
})
arr.splice(1,1, 'a', 'b');//从1位置删除一个,并插入a和b两个字符
console.log(arr);//[1, 'a', 'b', 3]
  • 类数组
    • 一个拥有 length 属性和若干索引属性的对象就可以被称为类数组对象,类数组对象和数组类似,但是没有数组的api方法。
    • 常见的类数组对象有 arguments 和 DOM 方法的返回结果,还有一个函数也可以被看作是类数组对象,因为它含有length属性值,代表可接收的参数个数。
    • 常见的类数组转换为数组的方法有这样几种:
      • Array.prototype.slice.call(arrayLike);
      • Array.prototype.concat.apply([], arrayLike);
      • Array.from(arrayLike);

函数 function

  • 定义:把具有相同或相似逻辑的代码块封装起来,以便精简代码方便复用
  • 声明和定义:function 名称 (参数...) { 函数体 }
  • 调用:函数名()
  • 函数传参
    • 形参:函数声明时,写在()里的变量,多个参数用逗号隔开,默认值是undefined,es6以后可以设置自定义默认值
    • 实参:函数调用时,传入的变量
    • 实参和形参的个数可以不一致,函数调用时,实参会按顺序赋值给形参
  • 返回值:在函数结尾处用 return 返回给外部的数据
    • 函数中return表示立即结束函数调用,并返回结果,该关键字后面的代码不再执行
    • 无return返回值的函数,默认返回undefined
    • 可以返回任意类型的数据
function add(){}//普通具名函数
function add(num){}//带参函数
function add(num = 1){}//自定义参数默认值的函数
function add(num1,num2){}//多参数函数
function add(){ return 1; }//有返回值的函数
function (){}//匿名函数
(function (){})()//立即执行函数/自执行函数 - 匿名函数 (function (){}()) !function (){}()
let fn = function(){}//函数表达式声明函数 - 匿名函数
  • 环境对象
    • 函数内部特殊的变量this,它代表当前函数运行时所处的上下文环境
    • this指向
      • 函数调用方式不同,this指向不同
      • 谁调用就指向谁,是this指向的粗略判断
      • 直接调用函数,this指向window
      • 属于某个对象方法的函数,this指向该对象
      • 用以下方法可以改变this指向
        • fn.call(thisArg,arg1,arg2,...)
        • fn.apply(thisArg,[...])
        • fn.bind(thisArg,arg1,arg2,...) 不直接执行,返回一个改变this后的新函数
const arr = [1,2,3];
//求数组最大值的三种方式
const max = Math.max.apply(Math, arr);
const max1 = Math.max.apply(null, arr);//第一个参数传null时不改变this
const max2 = Math.max(...arr)
//求数组最小值
const min = Math.min.apply(Math, arr);
  • 回调函数
    • 当一个函数当作参数传递给另外一个函数时,这个函数被称作回调函数

作用域

  • 全局作用域:作用域整个代码执行的环境
  • 局部作用域:局限于部分代码的环境中,如:函数中,代码块中
  • 在局部作用域中可以访问全局和上级作用域中的变量,上级作用域中不可以访问下级作用域中的变量
  • 变量访问原则
    • 代码中至少有一个作用域就是全局作用域
    • 遵循就近原则,现在最近的作用域中查找,找不到就在上级作用域中找,一直找到全局作用域中,如果还找不到就报错

对象

  • 概念:一种无序的数据集合,用于描述某个事物
  • 组成
    • 属性(信息、特征),多个属性用逗号分隔
    • 方法(功能、动作、行为),一种特殊的属性
//对象的声明
let obj = {}//字面量声明
let obj2 = new Object();//构造函数声明

let obj3 = {
    name: 'xxx',//属性
    say(){}//方法
}

//增删改查
obj.name = 'aaa';//获取属性,并修改
obj['name'] = 'bbb';//获取属性,并修改
obj.age = 18;//如果obj中原本没有age属性,则新增
delete obj.name;//删除属性

//对象的遍历
for (let key in obj){
    console.log(key, '--', obj[key]);
}

js内置对象-Math

  • Math是javascript提供的数学对象,提供了一系列的数学运算方法
  • 方法
    • random 生成[0, 1)之间的随机数
    • ceil 向上取整
    • floor 向下取整
    • max 取最大值
    • min 取最小值
    • pow 次幂运算
    • abs 取绝对值
    • round 四舍五入
  • 属性
    • Math.PI 圆周率
// 生成指定区间的随机数
function getMyRandom(start, end){
    return Math.floor(Math.random() * (end - start + 1) + start)
}
console.log( getMyRandom(5, 10) )

定时器

  • 间歇定时器 setInterval
    • 每隔一段时间执行一次,单位是毫秒
    • 关闭使用 clearInterval
    • 返回值是类似id的一个数字
  • 超时定时器 setTimeout
    • 超出指定时间后,执行且仅执行一次
    • 关闭使用:clearTimeout
    • 返回值是类似id的一个数字
let st = setInterval(() => {
    console.log('一秒执行一次')
}, 1000)
// clearInterval(st)

let sto = setTimeout(() => {
    console.log('300毫秒后执行')
}, 300)
// clearTimeout(sto)

js内置对象-Date 日期

  • 用来表示时间的对象,可得到当前系统的时间
  • 方法
    • getFullYear 获取四位数的年份
    • getMonth 获取月份0~11
    • getDate 获取日期(月份中的几号),不同月份取值不尽相同
    • getDay 获取星期0~6
    • getHours 获取小时0~23
    • getMinutes 获取分钟0~59
    • getSeconds 获取秒0~59
  • 时间戳
    • 从1970年01月01日00时00分00秒至今的毫秒数
const d = new Date()//通过实例化创建日期对象
const d2 = new Date('2022-05-01')//指定日期

//获取毫秒数的方式
+new Date()
Date.now()
new Date().getTime()

js内置对象-JSON

  • JSON.parse json字符串转对象
  • JSON.stringify 对象转json字符串
  • 缺点
    • function、undefined 属性丢失
    • 正则表达式会变成普通对象
    • 会破坏原型链和继承关系
    • 如果对象中有循环引用,会报错

WEB API

  • 作用:用js操作html元素和浏览器
  • 分类:DOM文档对象模型、BOM浏览器对象模型

DOM

  • (Document Object Model)专门用于操作网页内容,用于与任意的html/xml文档交互的api
  • DOM树:以树状结构的方式,描述网页内容关系的一种形式
  • DOM对象:根据html标签生成的js对象,可用于对html标签的增删改查
  • 顶层对象:Document
  • 获取dom对象
    • 根据css选择器获取
    • 其他方式
  • 操作对象
    • innerText 将纯文本内容添加/更新到标签中
    • innerHTML
  • 操作dom对象样式
    • 可以通过js对标签元素的属性进行增删改查
    • 常用属性如:href、 title、 src等
    • 样式属性
      • 通过style属性操作css样式
      • 直接通过类名(className)操作css
      • 通过classList操作类名,以修改样式
        • add remove replace toggle
  • 操作表单组件的属性
    • 如:value、type、checked、disabled
  • 调用dom的方法
    • 如:focus、blur、click
  • 设置和获取dom属性
    • element.setAttribute('name', 'value');
    • element.getAttribute('name');
    • h5推出了专门自定义属性的语法:data-xxx
      • 使用dataset可以操作该类型的对象属性
  • 获取元素宽/高
    • clientWidth/clientHeight
      • 可见宽高(不含边框、margin、滚动条等)
      • 数值型
    • offsetWidth/offsetHeight
      • 包含padding、border的宽高
      • 数值型,如果元素是隐藏状态时得到的是0
  • 获取元素位置
    • offsetLeft/offsetTop
      • 元素距离自己定位祖先的左上角距离,如果没有定位则以body为准
      • 只读属性,若想修改元素的定位应修改其style.left/top的值
//获取dom对象
let dom = document.querySelector('.box')//返回匹配的第一个元素(HTMLElement类型的对象)
let doms = document.querySelectorAll('.box')//返回所有匹配的元素组成的类数组(伪数组)

//其他方式获取dom对象
let dom2 = document.getElementById('boxId')//获取id匹配的一个标签
let divs = document.getElementsByTagName('div')//获取所有的div标签
let boxs = document.getElementsByClassName('box')//获取所有class名为box的标签

//操作dom对象内容
dom.innerText = 'a';//将文本内容添加/更新到标签中,不解析文本中可能遇到的标签
dom.innerHTML = '<div style="color:red">aa</div>';//将文本内容添加/更新到标签中,并解析文本中可能遇到的所有标签及其样式

//操作dom标签样式
dom.style.width = '100px';//注意加单位
dom.style.backgroundColor = 'pink';//注意css中短横线连接的属性,在这里要转成小驼峰方式
dom.className = 'box2';//直接替换旧的类名
dom.classList.add('box3');//新增类名

//造成表单属性
let inputDom = document.querySelector('input[class=i_name]')
inputDom.value = 'vvv';//修改值
inputDom.type = 'password'//修改类型

事件监听

  • 语法:
    1. 元素对象.on事件 = function(){}
      • 只有事件冒泡,没有事件捕获
      • 只能绑定一次,如果多次绑定会把之前的函数覆盖
      • 移除事件:元素对象.on事件 = null
    2. 元素对象.addEventListener(事件类型, 函数, useCapture)
      • 有时间捕获和冒泡
      • 可以多次绑定,监听多个函数
      • 移除事件:
        • 元素对象.removeEventListener(事件类型, listener[,options])
        • 元素对象.removeEventListener(事件类型, listener[,useCapture])
      • useCapture默认是false表示冒泡阶段触发,传true时表示捕获阶段出发
  • 事件监听三要素
    • 事件源、事件类型、回调函数
  • 事件类型
    • 鼠标事件
      • click
      • mousenenter和mouseleave 有事件冒泡
      • mouseover和mouseout 没有事件冒泡
    • 焦点事件
      • focus blur
    • 键盘事件
      • keydown keyup
    • 文本事件
      • input 输入事件
    • 页面加载事件
      • load
        • 常在window上监听,表示整个页面资源加载完成
        • 加载外部资源如:img css js时,也会有相应的事件
      • DOMContentLoaded 当初始的html文档加载解析完成后该事件触发,不等待css或图像资源的加载。
        • 在document上监听
    • 页面滚动事件 scroll
      • 常加在window或document上,也可以加在某个dom元素上
      • scrollLeft/scrollTop 元素的滚动位置属性,可读可写
      • window.scrollTo(x坐标,y坐标)方法,可以将页面滚动到指定位置
    • 页面尺寸事件
      • resize 常用在window上
  • 事件对象
    • 事件绑定函数的第一默认参数,用于描述事件触发时的相关信息的js对象
    • 常用属性
      • type 事件类型
      • target 真正触发事件的dom元素
      • clientX/clientY 鼠标光标相对于浏览器可见窗口左上角的位置
      • offsetX/offsetY 鼠标光标相对于当前dom左上角的位置
      • key/keyCode 键盘事件中,用户按下的键盘键对应的标识值
    • ev.stopPropagation() 阻止事件流传递
    • ev.preventDefault() 阻止事件的默认行为,如:链接跳转、表单提交
  • 事件流
    • 当事件触发时,会经历多个阶段,事件捕获 -> 绑定的事件执行 -> 事件冒泡
    • 事件捕获:事件从父元素传递到子元素,在事件触发前,会先触发其所有祖先元素中绑定的相同类型的事件
    • 事件冒泡:事件从子元素传递到父元素,当一个事件被触发后,会依次执行其所有祖先元素中绑定的相同类型的事件
    • 阻止事件传递(冒泡/捕获):事件对象.stopPropagation()
  • 事件委托
    • 给父元素绑定事件,利用事件冒泡的特点以监听子元素的相关事件
    • 减少事件注册,提供性能
    • 新增的子元素也可以响应相关事件
const fn = function(ev){
    conosle.log(ev.target.tagName)
    ev.stopPropagation()
}
document.body.addEventListener('click', fn)
document.body.removeEventListener('click', fn)

//监听滚动事件
window.addEventListener('scroll',function() {
    console.log('滚动距离', document.documentElement.scrollTop)
})
  • 移动端事件
    • touchstart 手指触摸到一个元素时触发
    • touchmove 手指在元素上滑动时触发
    • touchend 手指从元素上离开时触发

DOM节点操作

  • DOM树中的每一个内容都称之为节点
  • 节点类型
    • 元素节点,如:div
      • html是根节点
    • 属性节点,如:href
    • 文本节点:纯文本
    • 其他
  • 节点关系
    • 父节点、子节点、兄弟节点
  • 父节点查找
    • parentNode 属性
  • 子节点查找
    • childNodes 属性:获得所有子节点
    • children 属性:仅获得元素节点,返回的是类数组
  • 兄弟节点查找
    • nextElementSibling 属性:下一个节点
    • previousElementSibling 属性:上一个节点
  • 增加节点
    • document.createElement('标签名') 创建新节点
    • 父节元素.appendChild(要插入的元素) 向后追加节点
    • 父节元素.insertBefore(要插入的元素, 在哪个元素前面) 在指定节点前面插入一个节点
  • 克隆节点
    • 元素.cloneNode(boolean) false浅克隆-只克隆标签,true深克隆-包括标签上的所有属性和方法
  • 删除节点
    • 父元素.removeChild(子元素) 删除子元素
    • 元素.remove() 删除当前元素

BOM 浏览器对象模型

  • Browser Object Model
  • window对象是全局对象/顶级对象,所有通过var定义在全局作用域中的变量/函数都会变成window对象的属性和方法
  • js执行机制
    • js是单线程语言,同一个时间只能做一件事
    • 单线程就意味着,所有任务需要排队,如果js执行的时间过长会导致页面渲染不连贯,渲染加载阻塞
    • 为了解决这个问题,利用多核cpu的能力,html5提出了wev worker标准,允许js脚本创建多个线程,于是就有了同步任务和异步任务,js本身没有多线程,它是依靠宿主环境(浏览器/node)来处理多线程任务的
    • 同步任务
      • 都在主线程上执行,形成一个执行栈
    • 异步任务
      • js的异步是通过回调函数实现的,常见的有三种类型:普通事件,资源加载,定时器
      • 异步任务添加到任务队列中,也称消息队列
    • 任务执行顺序/事件循环机制 event loop
      1. 先执行主线程中的同步任务
      2. 异步任务放入任务队列
      3. 主线程所有同步任务执行完毕后,系统就会检查异步任务队列中是否有可执行的异步任务,如果有则按次序读取任务队列中的异步任务,调入执行栈开始执行
    • 异步任务分为宏任务和微任务
      • 宏任务:setTimeout、setInter、requestAnimationFrame、事件回调函数,如 clickloadajax
      • 微任务: Promise、MutationObserver
  • window.location
    • 它拆分并包含了URL地址的各个组成部分
    • 常见属性:href search hash
    • 常见方法:
      • reload(),reload(true)强制刷新
  • window.navigator
    • 记录了浏览器自身的相关信息
    • 属性
      • userAgent 浏览器版本及平台
  • window.history
    • 管理和操作浏览器路由的历史记录信息
    • 方法
      • back 后退
      • forward 前进
      • go 前进或后退 go(-1)后退一步
  • window.requestAnimationFrame()
    • 按帧定时循环函数,常用来执行动画效果,每一帧必定会执行不同
    • 在浏览器下一次重新渲染之前执行requestAnimationFrame中的回调函数
  • window.requestIdleCallback(fn,timeout)
    • 在浏览器空闲时执行
    • 假如浏览器一直处于非常忙碌的状态,回调函数可能永远不会执行,可通过设置timeout指定超出一定时间后强制执行
requestIdleCallback((deadline) => {
    console.log(deadline.timeRemaining())//表示当前帧剩余的时间,也可理解为留给任务的时间还有多少
    console.log(deadline.didTimeout)//布尔值,表示任务是否超时
})
  • window.MutationObserver
    • 用来监视DOM变动。DOM的任何变动,比如节点增减、属性的变动、文本内容的变动都会触发MutationObserver事件,它与事件有一个本质不同:事件是同步触发,MutationObserver是异步触发
var observer = new MutationObserver(function(mutations) {
  console.log(mutations)
});
observer.observe(document, { 
    childList: true//是否监听子节点的变动
});//配置 MutationObserver 在 DOM 更改匹配给定选项时,通过其回调函数开始接收通知
  • 本地存储
    • localStorage
      • 永久存储,大小5M
      • 多窗口共享数据,存储的数据都会转成字符串
      • 方法:setItem(key, value)、getItem(key)、removeItem(key)
    • sessionStorage
      • 临时存储,大小5M
      • 方法:setItem(key, value)、getItem(key)、removeItem(key)
      • sessionStorage不能在多个窗口或选项卡之间共享数据,但是,当通过window.open或链接打开新页面时,新页面会复制上一个页面的sessionStorage

正则表达式

  • Regular Expression 是用于匹配字符串中字符组合的模式。在js中挣扎表达式也是对象
  • 语法格式
    • /表达式/
    • new RegExp(表达式)
  • 方法
    • 正则变量.test(内容)
      • 检测表达式于字符串是否匹配,返回boolean值
    • 正则变量.exec(内容)
      • 在指定的字符串中执行一个搜索匹配
      • 成功返回一个数组,失败返回null
  • 元字符
    • 边界符(以什么开头/以什么结尾)
      • ^ 匹配行首的位置,以什么开始
        • 写在[]内则表示排除的意思
      • $ 匹配行尾的位置,以什么结尾
    • 量词(重复次数)
      • * 零次或多次
      • + 一次或多次
      • ? 零次或一次
      • {n} n次
      • {n,} n次或更多次
      • {n,m} n到m次
    • 字符类
      • [] 匹配字符集合,如:[abc] 匹配abc中任何一个字符
      • 用连字符表示一个范围,如:[a-z] 匹配a到z到字符
      • \d 表示0-9之间的数字。\D取反
      • \w 表示任意的字符、数字、下划线。\W取反
      • \s 表示空白符。\S取反
    • 修饰符:/表达式/修饰符
      • i 是ignore的缩写,表示不区分大小写
      • g 是global的缩写,匹配所有满足表达式的结果

字符串详解

  • 属性
    • ''.length
  • 方法
    • ''.replace 字符替换
    • ''.split 字符切割
    • ''.charAt() 根据索引返回对应字符
    • ''.charCodeAt 根据索引返回对应字符的编码
    • ''.concat() 字符串拼接返回新字符串
    • ''.endsWith
    • ''.startsWith
    • ''.includes
    • ''.indexOf
    • ''.lastIndexOf
    • ''.match
    • ''.matchAll
    • ''.repeat 返回新字符串
    • ''.search
    • ''.slice(start, end?)
      • 字符串截取,返回新字符串,当end为负数时,从尾部反向计算end的位置
    • ''.substr(start, length?)
    • ''.substring(start, end?)
      • 字符串截取,返回新字符串,当end为负数时,从start位置反向查找
    • ''.toLowerCase()
      • 结果可能会因不同语言之间的冲突而有所不同
    • ''.toLocaleLowerCase()
      • 根据主机系统的当前语言环境将字符串转换为小写字母。推荐使用
    • ''.toUpperCase
    • ''.toLocaleUpperCase
    • ''.trim
'a-b-c'.slice(-,-1) //-b- 从尾部反向计算end的位置
'a-b-c'.substring(-,-1) //a 从start位置反向查找

作用域

  • 局部作用域
    • 函数作用域
      • 在函数内部声明的变量只能在函数内部使用,外部无法访问
      • 包括内部变量、形参等
      • 函数执行完毕后,内部变量被销毁
    • 块级作用域
      • 使用{}包裹的代码称为代码块
      • let和const声明的变量属于块级作用域,var声明的变量不受块级作用域限制
  • 全局作用域
    • 全局作用域中的变量实际上就是window的属性或方法
    • 全局作用域中的变量可以被局部作用域访问
    • 未使用关键字声明的变量属于全局变量
  • 作用域连
    • 实际上就是js的变量查找机制
    • 一个函数执行时,会先在当前作用域中查找变量
    • 当前作用域找不到时,会依次逐级在其父级作用域中查找,直到全局作用域
  • js垃圾回收机制
    • Garbage Collection 简称GC
    • js中分配的内存,一般有如下生命周期
      • 内存分配:声明变量时
      • 内存使用:使用变量
      • 内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存
    • 全局变量在页面关闭时回收
    • 局部变量,不再使用时被自动回收
    • 内存泄露:程序中分配的内存由于某种原因导致未释放或无法释放时,就造成了内存泄露
    • 堆栈空间分配区别:
      • 栈:由操作系统自动分配释放;基本数据类型
      • 堆:一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收;复杂数据类型
    • 回收算法-引用计数法
      • IE采用的是引用计数法,定义内存不再使用,就是看一个对象是否有指向它的引用,没有了就回收对象
      • 跟踪记录被引用次数,被引用一次加1,多次引用累加,减少一个引用减1
      • 如果引用次数是0,则在检测时就被释放掉内存
      • 引用计数存在一个问题:嵌套引用,即如果两个对象相互引用,它们的记录数永远不会是0,尽管它们不再使用时,垃圾回收器也无法进行回收,会导致内存泄露
    • 回收算法-标记清楚法
      • 现在浏览器通用的大多数是基于标记清楚算法的某些改进算法,总体思想都是一致的
      • 标记清楚算法将 '不再使用的对象'定义为 '无法达到的对象'
      • 就是根部触发定时扫描内存中的对象,凡是能从根部到达的对象都是还需要使用的
      • 那些无法由根部触达达对象被标记为不再使用,稍后进行回收
  • 闭包
    • 函数内部声明一个子函数,子函数访问父作用域中的变量,最后返回子函数,在外部用变量接受返回的函数
    • 这时就可以调用返回的函数,操作或使用局部作用域中的变量
    • 作用:实现数据私有化
    • 问题:会导致变量/对象无法被垃圾回收,造成内存泄露
  • 变量提升
    • var声明的变量,在编译时会提升到当前作用域的最前面,在声明之前可以被访问,值为undefined
    • 变量提升只在相同作用域中有效

函数进阶

  • 函数提升
    • 和变量提升类似,即在声明之前可以被使用
    • 函数表达式不存在提升的现象
  • 函数参数
    • 动态参数/形参列表 arguments
      • arguments是类数组
    • 剩余参数
      • function(p1,p2,...others){}
  • 箭头函数
    • 更简短的函数写法,并且不绑定this
    • 箭头函数属于匿名函数,所以也没有声明提升
    • this指向其所定义时的最近的作用域上下文环境中的this值
    • 不使用于构造函数、原型中的函数、字面量对象中的函数、dom事件函数

构造函数

  • 创建对象的三种方式
    • 字面量或new Object()或Object.create()
    • 工厂模式:定义一个函数,在函数内部声明一个对象并赋予属性,最后返回这个对象
    • 构造函数,批量生成内容相同的对象
  • 构造函数命名以大写字母开头
  • 用new操作符创建实例化对象
  • 构造函数将变量和内部函数组合到一起,并通过this实现数据共享,体现了面向对象的封装特性
  • 通过原型上绑定公共属性和方便
  • 实例化过程
    1. 在内部隐式地创建一个对象,并将对象的原型指向构造函数的 prototype 属性
    2. 把上下文this指向这个对象
    3. 执行函数内部代码,赋予对象属性
    4. 如果没有显示地返回值或显示返回值不是一个对象,则创建的隐式对象
  • 实例成员
    • 实例对象中的成员称为实例成员
  • 静态成员
    • 构造函数的属性和方法称为静态成员
    • 静态成员只能由构造函数访问
    • 静态方法中的this指向构造函数
Student.eyes = 2;//静态属性
Student.move = function(){}//静态方法
Student.prototype.aaa = 'aa'//通过原型绑定公共属性
Student.prototype.fn = function(){}//通过原型绑定公共方法,在内部使用私有化方法或属性比较浪费内存,推荐使用原型绑定公共方法
function Student(){
    // new.target 代表当前正在被实例化的构造函数,Student当作普通函数调用时为undefined
    this.name = 'a';
    this.age = 18;
    this.say = function(){}
}
const xiaoming = new Student();
const xiaozhang = new Student();
  • js内置的构造函数
    • Object
      • 静态方法:
        • Object.keys 获取属性名
        • Object.values 获取属性值
        • Object.assign 属性拷贝
        • Object.is 在===判断上做了优化Objext.is(NaN,NaN)为true
        • Object.getPrototypeOf 获取指定对象的原型
        • Object.setPrototypeOf 为现有对象设置原型,第一个是现有对象,第二是原型对象
    • Array
      • 静态方法
        • Array.isArray
        • Array.from
    • RegExp
    • Date
    • String
    • Number
      • toFixed
    • Boolean

包装类

  • 字符串、数字、布尔等基本数据类型都有其对应的构造函数,称为包装类
  • 当访问基本数据类型属性,或调用基本数据类型方法时,js内部会把其包装成复杂类型
let str = "aa";
console.log(str.length)//new String(str).length
let num = 1.123
num.toFixed(2)//new Number(num).toFixed(2) = '1.12'

原型

  • 编程思想
    • 面向过程:就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了
      • 性能比面向对象高,适合跟硬件联系很紧密的开发,如单片机就采用面向过程编程
    • 面向对象:把事务分解成一个一个对象模块,然后右对象分工合作解决问题
      • 在面向对象程序开发思想中,每一个对象都是功能中心,具有明确的分工。
      • 优点:具有灵活代码可复用,容易维护,适合多人协作开发
      • 特性:封装性、继承性、多态性
    • js的面向对象是通过构造函数实现的
  • 构造函数通过原型分配的属性或方法是其所有实例化对象所共享的
  • js规定每个构造函数都有一个prototype属性,指向一个对象,称为原型对象
  • 对象实例化不会多次创建原型,相对节约内存
  • 构造函数和原型对象中的this都是指向实例化的对象
  • constructor 属性
    • 每个原型对象里面都有一个constructor属性
    • 该属性指向该原型对象的构造函数
  • __proto__属性
    • 每个对象都会有一个__proto__属性,指向构造函数的prototype原型对象,实例化对象之所以能够使用构造函数的原型属性,就是因为其有__proto__原型的存在
    • 只读属性,只能读不能改
    • __proto__不是js标准属性,有的浏览器用[[prototype]]
    • [[prototype]](和__proto__意义相同)属性只能在debug中看到,无法读取
    • 用来表示单曲实例对象指向哪个原型对象prototype
    • __proto__中也有一个constructor属性,指向创建该实例对象的构造函数
  • 原型继承:继承是面向对象编程的另一个特征,通过继承进一步提升代码封装的程度,js中大多是借助原型对象来实现继承的特性
  • 原型链:基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联关系是一种链状的结构,称为原型链
  • 原型链-查找规则
    • 当访问一个对象的属性/方法时,首先在自身查找
    • 自身没有,就在其原型上查找
    • 原型没有,就在原型的原型上查找,依次类推知道找到Object的原型(Object.prototype._proto_)null为止
  • 可以使用instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
//给数组原型添加自定义方法
Array.prototype.my_maxFn = function(){}

function Student(){
    this.name = 'a';
    this.age = 18;
    this.say = function(){}
}
Student.prototype = {//当给原型采用对象形式赋值时,就会丢失构造函数原型对象中原来的默认值(如constructor)
    constructor: Student//可以再主动添加上constructor
    aa: 'a'
}

//原型继承的简单实现
const Person = function(){
    this.eyes = 2
    this.head = 1
}
function Woman(){}
Woman.prototype = new Person()
Woman.prototype.constructor = Woman
function Man(){}
Man.prototype = new Person()//使用构造函数,生成原型对象和Woman的原型有相同的初始属性,并且防止了和Woman的原型冲突,修改Man的原型属性不会影响Woman的原型属性
Man.prototype.constructor = Man
const woman1 = new Woman()
const woman2 = new Woman()
const man1 = new Man()
const man2 = new Man()
man1 instanceof Person//true

进阶

浅拷贝和深拷贝

  • 浅拷贝常见方法
    • Object.assgin
    • 展开运算符{...obj}或[...arr]
    • Array.prototype.concat
  • 深拷贝常见方法
    1. 通过递归实现
    2. 使用插件lodash里面的cloneDeep方法
    3. 使用JSON.stringify

异常处理

  • throw 抛出异常
    • throw new Error('xxx')
  • try{} catch(){} finally{} 捕获异常
  • debugger 错误调试

性能优化

  • 防抖 debounce
    • 单位时间内频繁触发事件,只执行最后一次
    • 使用场景:输入框搜索事件,表单验证检测事件
  • 节流 throttle
    • 单位时间内频繁触发事件,只执行一次
    • 使用场景:鼠标移动事件、窗口缩放事件、页面滚动事件

解析字符串脚本

const str = "var age = 18;"
eval(str);//eval中不支持es6语法
console.log(age)

const fn = new Function("num", "return num + 1");
console.log( fn(18) )

推荐文章