文章目录
JS进阶
发展历程和语言特点
发展历程
- JavaScript组成(客户端)
- ECMAScript (ES)—— 核心规范,不可替代;JavaScript的语法标准
- BOM —— 宿主对象,可更换部分
- DOM —— 宿主对象
- 浏览器 —— 客户端JavaScript运行的宿主环境
- 目前 JavaScript 的运行环境有浏览器和 node.js 环境两种
- 浏览器下载 JavaScript 脚本文件后,由浏览器 JavaScript 引擎解释执行
- ES
- 最新:ES10
- ES5:ES2009
- ES6:ES2015
- ES5没有块作用域
- JavaScript,JScript和ActionScript 都遵从ES标准
语言特点
-
是一种直译式脚本语言
-
是一种弱类型、动态类型语言
数据类型
分类
- ES5数据类型(6种)及其划分(2类)
- 基本(原始)类型:Number、String、Boolean、Null、Undefined
- 引用(对象)类型:Object(Array、Function、Date等)
- typeof —— 判断数据类型
- 数据、变量和类型
- JavaScript 中的变量没有类型
- JavaScript 中的数据值有类型
- 变量可以随时持有任何类型的值
- 对变量执行 typeof 操作时,得到的结果并不是该变量的类型,而是该变量持有的值的类型
- 数据、变量和类型
存储
- 变量声明
- 变量赋值
- 内存空间
- 堆内存
- 存储的值大小不定,可动态调整
- 由程序员通过代码进行分配
- 空间大,运行效率相对较低
- 栈内存
- 存储的值大小固定
- 由系统自动分配内存空间
- 空间小,运行效率高
- 基本数据类型的临时变量分配在栈区
- 引用数据类型的变量的引用(地址)存储在栈区,被引用(指向)的对象存储在堆区
- 堆内存
区别
- 基本类型与引用类型的区别
- 访问机制不同
- 基本类型的值直接访问
- 引用类型的值通过引用访问,不能直接访问
- 先从栈中获取该对象的地址引用,再从堆内存中取得我们需要的数据
- 变量赋值不同
- 基本类型赋值 —— 相互独立互不影响
- 引用类型赋值
- 比较变量不同
- 值类型是判断变量的值是否相等(值比较)
- 引用类型是判断所指向的**内存空间(地址)**是否相同(引用比较)
- 参数传递不同
-
ECMAScript 中所有函数的参数都是按值来传递的
-
基本类型值:把变量里的数据值传递给参数,之后参数和变量互不影响
-
引用类型值:把对象的引用(地址)值传递给参数,参数和对象都指向同一个对象,相互影响
-
- 访问机制不同
包装对象和数据类型转换
包装对象
-
包装对象
- 数字、布尔、字符串等基本数据类型都有对应的包装对象类型
- 例:new Number(20); new String(‘SomeStr’); //装箱
- 存储或读取基本类型(字符串、数字、布尔)值的属性时,会创建临时包装对象
- 例: console.log(‘Hello,World’.length);
- 基本类型其属性不能被改变、添加或删除(原始值不可变性)
- 数字、布尔、字符串等基本数据类型都有对应的包装对象类型
-
临时包装对象 —— 使用后立即释放
-
存取字符串、数字或布尔值的属性时创建的临时对象称为包装对象
-
用来处理属性的引用,一旦属性引用结束,包装对象就会销毁
-
var str=”test”; str.p = 4;//设置临时对象属性 var t = str.p; // 临时对象已释放,再输出t时为undefined
-
数据类型转换
-
基本数据类型的值
- Number类型的值
- 整数与浮点数
- NaN、Infinity、-Infinity、+0、-0
- String类型的值
- 空字符、字符和字符串、转义字符
- Boolean类型的值
- true、false
- Null与Undefined
- null、undefined
- Number类型的值
-
NaN
-
表示一个没有意义、不正确的数值
-
console.log( typeof NaN);//Number
-
-
与自身不相等 —— NaN != NaN
-
isNaN()函数
- 用来检测参数是否为 NaN 值
- 参数是 “NaN” 时返回 true,否则返回 false
-
-
引用数据类型的值
- 简单对象
- 数组
- 函数对象
- 函数也是对象(可执行的对象),也有属性和方法
- 正则对象
-
类型转换
- 隐式类型转换
- 使用关系运算符时的转换(==、>、<、引用类型和基本类型比较时
- 使用算数运算符时的转换(‘img’+ 3 + ‘.jpg’; “25”-0;)
- 使用逻辑运算符时的转换( !!0; )
- 执行流程语句时的转换(if(obj){…})
- 显式类型转换(强制类型转换)
- Boolean()、Number()、String()、Object()
- 数转为字符串(toString()、toFixed()、toPrecision()、toExponential())
- 字符串转为数字(parseInt()、parseFloat())
- 对象转换为原始值(toString()、valueOf())
- 转换成Number类型
- undefined —— NaN
- null —— 0
- 布尔值 —— false转换成0;true转换成1
- 数字 —— 不变
- 字符串 —— 解析字符串中的数字,空字符转换为0
- 强制转换: parseInt()、parseFloat()、Number()
- Object:调用valueof().toString(),再转换为number类型
- 转换成String类型
- undefined —— ‘undefined’
- null —— ‘null’
- 布尔值 —— false—>‘false’ ; true—>‘true’
- 数字
- 字符串 —— 不变
- 强制转换:String()
- Object:调用toString()方法
- 转换成Boolean类型
- undefined —— false
- null —— false
- 布尔值
- 数字 —— 0、NaN —>false;其他数字—>true
- 字符串 —— "—>false;其他字符串—>true
- 强制转换:Boolean()
- Object:true(任意对象)
- 转换成Object
-
对象
-
undefined、null——空对象{}
-
string、number、Boolean —— 包装对象
- new Boolean(bool)、new Number(num)、new String(str)
-
强制转换:Object()
-
- 隐式类型转换
运算符和表达式
标识符与表达字
- 关键字,保留字不能作为标识符
- 访问属性的方式
- 通过点号(.)运算符
- 通过中括号([])运算符
- window对象属性
- 全局变量是 window 对象的属性
- 全局函数是 window 对象的方法
运算符与表达式
-
字面量
-
运算符
-
运算符优先级
-
逻辑运算符
-
两边的操作数都是布尔类型时
- 对于&&来说, 除了两侧都为真时为真,其他情况都为假
- 对于| |来说, 除了两侧都为假时为假,其他情况都为真
-
两侧的操作数不是布尔类型
- 首先将左操作数转换成布尔类型
- 对转换后的左操作数进行逻辑判断(true or false)
- 根据短路原则返回原始左操作数或原始右操作数
-
短路原则
-
console.log(2&&4); //4 console.log({x:2}&&{name:"Jack"}); //{name:Jack} console.log(2||4); //2 console.log({x:2}||{name:"Jack"}); //{x:2}
-
应用
- 使用||设置函数参数的默认值
- 使用&&提升程序的健壮性
- 使用||和&&实现条件语句(减少代码量,增加执行效率)
-
-
-
比较运算符(=、)
-
递增递减(++、–)
-
赋值运算符
-
多级赋值
-
var a = {n: 1}; var b = a;//b被赋值为a,因此b就是对象{n:1} a.x = a = {n: 2}; //a.x指的是给a添加一个x属性,在js的运算中“.”和"="运算符同时出现,会先执行"."运算 //因此先给a.x赋值,再给a赋值 //先执行:a.x={n:2},这里a并未改变,是给a的x属性赋值为{n:2},a还是{n:1} //给{n:1}这个对象增加了名为x的属性 //再执行a={n:2},变量a被重新赋值为一个新的对象{n:2}; console.log(a); //{n:2} console.log(b); //a的二次赋值,并没有影响b,b还是{n:1},但是{n:1}这个对象,增加了一个x属性 console.log(a.x);//{n:2}对象没有x属性,所以结果是undefined console.log(b.x);//综上所述,这个结果是{n:2}
-
var a = { n: 1 }; a.x = a = { n: 2 }; console.log(a.x); //undefined
-
-
表达式
- 函数表达式
- IIFE:立即执行的函数表达式
- 建立函数作用域限制变量的作用域
- 解决ES5作用域缺陷(没有块作用域)所带来的问题,如:变量污染、变量作用域等问题)
语句
对象的属性特性
对象与属性
- 对象是一种复合值,是若干无序属性的集合
- 函数作为某一个对象的属性时,称其为该对象的方法
- 操作数据就是操作对象的属性
- 对象的创建:
- 对象字面量方式
- Object的create静态方法
- 构造函数
- 对象分类:
- 内置对象(构造器函数对象、非构造器对象)
- 宿主对象
- 自定义对象
- 属性的种类
- 数据属性
- 访问器属性
- 内置属性
数据属性及其特性
- 数据属性的特性
- value:属性的值
- writable:可写性 —— 是否可以改写
- configurable:可配置特性 —— 是否能删除以及其他特性是否可配置
- enumerable:可枚举特性
- 属性描述符
- 设置 —— Object.defineProperty(obj, prop, descriptor)
- obj —— 要在其上定义属性的对象
- prop —— 要定义或修改的属性的名称
- descriptor —— 将被定义或修改的属性描述符
- 查询 —— Object.getOwnPropertyDescriptor(obj,prop)
- 设置 —— Object.defineProperty(obj, prop, descriptor)
- 枚举性 ——是否能枚举: obj.propertyIsEnumerable(prop)
- 定义属性
- 属性不存在 —— 创建新属性,由描述符指定特性,未指定使用默认值
- 属性存在 —— 更新描述符指定的属性特性,没有对应的特性保持不变
访问器属性及其特性
- 间接访问属性的方法(访问和设置时都不加括号,没有function关键字)
- 属性特性
-
get(读取):读取属性时调用的函数,该函数计算读取的结果,默认是 undefined
-
set(设置) :设置属性值时调用的函数,该函数接受设置的值作为参数,默认是undefined
-
configurable
-
enumerable
-
函数定义和调用形式
函数定义形式
-
函数定义方式
- 通过函数声明的形式来定义
- 通过函数表达式的形式来定义
- 通过 Function 构造函数实例化的形式来定义
-
Function构造函数
-
可以传入任意数量的实参(string类型)
-
最后一个实参为函数体
-
eg: var max = new Function("a","b","return a>b?a:b;"
-
-
函数定义三要素
- 函数名,函数的参数,函数的返回值
-
具名/匿名函数
- 匿名函数
- 单独的匿名函数无法运行,可以赋值给变量或立即执行
- 具名函数优势
- 当遇到错误时,堆栈跟踪会显示函数名,容易寻找错误
- 匿名函数
-
name属性:返回函数实例的名称
-
length属性:函数的形参个数
-
函数的参数:调用时,传递的实参数量可以与形参数量不一致
arguments对象
- arguments对象
- 代表传入函数的实参
- 是函数中的局部变量
- 不能显式创建,只有函数调用时才可用
- 它是一个类数组对象
- 类数组对象
- 与数组一样具有 length 与 index 属性;本质是 Object,length代表实参数量
- arguments与形参的“双向绑定”特性
- 在函数调用时 arguments 对象与实际传递了值的形参变量发生双向绑定,arguments 对象中的对应单元会和命名参数建立关联
call/apply/bind方法
-
函数对象
- 每个函数都是作为对象来运行和维护的
- 对象是一系列属性和方法的集合 ,所以函数也有对应的 属性和方法
- 可以将**函数(函数对象)**赋值给一个变量,或将函数作为参数进行传递
- 属性:name,length,prototype
- 方法:call,apply,bind,toString,valueOf
- 每个函数都是作为对象来运行和维护的
-
this关键字
- 在 function 内部被创建
- 指向调用时所在函数所绑定的对象
- this 不能被赋值,this 的值取决于函数被调用的方式
-
call()方法
-
语法:fn.call(thisObj,arg1,arg2,…)
-
参数:arg1,arg2,…:调用的实参(参数序列)
thisObj:this指向的对象
-
返回值:与fn普通调用相同
-
作用:调用函数,改变函数执行的this指向
-
-
apply()方法
- 语法:fn.apply(thisObj,[arg1,arg2,…])
- 被调用的参数是参数数组
- 返回值:与fn普通调用相同
- 作用:调用函数,改变函数执行的this指向
-
bind()方法
- 语法:fn.bind(thisObj,arg1,arg2,…)
- 参数:调用的是参数序列
- 返回值:返回一个原函数的拷贝(绑定函数),并拥有指定的 this 值和初始参数
- apply,call 都会立即调用函数执行,bind 不会立即调用函数
函数调用形式
- 作为函数直接调用(非严格模式下this为全局对象,严格模式下为undefined)
- 作为方法调用(this指向调用此方法的对象)
- 通过call( )和apply( )间接调用(this为函数对象的call/apply方法的首个参数 )
- 作为构造函数调用(this指向实例化出来的对象)
预解析
- JavaScript代码运行机制
- 执行分两个阶段
- 代码解析阶段:将代码翻译成可执行代码 (预解析:声明提升)
- 代码执行阶段:执行可执行代码
- 编译和执行过程
- 全局解析阶段(全局预解析)
- 全局顺序执行阶段(变量赋值、函数调用等操作)
- 当遇到函数调用时,进行函数范围内的预解析,再执行函数内代码
- 当存在函数嵌套时,以此类推,会进行多次函数解析与执行
- 注意:解析和执行是不断交替的过程
- 执行分两个阶段
- 声明提升
- 所有的变量声明和函数声明提升到当前作用域的最前面
- 声明提升规则:
- 函数声明整体提前
- 变量声明提前,赋值留在原地
- 函数会优先被提升,然后才是变量
- 函数声明有冲突,会覆盖;变量声明有冲突,会忽略
函数的作用域和执行上下文
执行上下文
- 执行上下文
- 当前代码的运行环境
- 作用:保存当前代码运行时所需要的数据
- 在全局环境、函数环境中会创建执行上下文
- 函数执行时创建;当一个函数调用时,一个新的执行上下文就会被创建
- 执行上下文栈
- 按照函数的调用顺序来管理执行上下文
- 栈底永远是全局上下文,栈顶是当前正在执行的函数
- 特点:先进后出
- 生命周期
- 执行上下文的生命周期
- 创建(解析)阶段:–作用域链确定 创建变量对象(声明提升规则)
- 执行阶段:修改变量对象
- 等待回收阶段
- 执行上下文的生命周期
- 每个执行上下文都有一个与之关联的变量对象(VO)和一个作用域链(scopechain)
- return语句
- 返回值
- 终止函数执行(销毁当前执行上下文,弹出执行上下文栈 )
变量对象
- 定义
- 与执行上下文相关的数据作用域
- 与上下文关联的特殊对象,用于存储被定义在上下文中的变量和函数声明
- 创建过程
- 建立 arguments 对象
- 检查当前上下文的函数声明
- 检查当前上下文中的变量声明
- 浏览器中全局上下文的变量对象
- 变量对象就是 window 对象
- 在页面关闭前一直存在
作用域链
-
作用域
- 作用域是一套关于如何存储变量当中的值,并且能在之后对这个值进行访问和修改的规则
-
作用域的作用
- 指定变量与函数的可访问范围
- 控制着变量与函数的可见性
-
作用域类型
-
全局作用域
-
在全局作用域下声明的变量叫做全局变量
-
全局作用域中无法访问到局部作用域中的变量
-
全局变量创建方式
- 在全局作用域下 var 声明的变量
- 在函数内部,没有使用 var关键字声明直接赋值的变量
- 使用 window 全局对象创建的属性和方法
-
-
函数作用域
- 在函数作用域下声明的变量叫做局部变量
- 局部变量只在当前函数内部中使用
- 局部作用域中可以访问到全局作用域中的变量
- 局部变量创建方式
- 在函数内部通过 var 声明的变量
- 函数的形参
-
块作用域
- { } 中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,称为块级作用域
- ES5 没有块作用域,在 ES6 中添加了块作用域
-
-
作用域模型
- 词法作用域(静态性) —— JavaScript 作用域
- 由函数定义的书写位置决定的,与调用位置无关
- 静态性,静态结构决定了一个变量的作用域
- 动态作用域(动态性) —— 仅由调用位置决定
- 词法作用域(静态性) —— JavaScript 作用域
-
[[scope]]属性
- 虚拟属性,无法问问和修改
- 函数创建(定义)时生成的属性,保存着这个函数所有父级执行上下文环境中的变量对象的集合
-
作用域链(scopechain)
-
由当前执行环境与所有父级执行环境的一系列变量对象组成
-
ScopeChain = VO + [[scope]]
-
-
提供对变量和函数访问的权限和顺序的规则
-
-
变量函数访问规则
- 沿着作用域链从里向外查找
- 查找会在找到第一个匹配的标识符时停止
内存空间管理
- 内存空间管理
- 分配内存
- 使用分配到的内存
- 不需要时释放内存
- 垃圾回收机制
- 当一个值失去引用之后就会回收
闭包
- 定义
- 闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所需访问的所有局部变量。
- 作用
- 访问函数作用域内的局部变量
- 使函数中的变量被保存在内存中不被释放
- 缺点
- 内存消耗大
- 闭包会在父函数外部,改变父函数内部变量的值
- 常见形式
- 以普通函数返回
- 作为对象的方法返回
- IIFE、闭包综合应用
- 解决变量共享、变量污染问题
- function(i){ ……}(i)
- 通过IIFE对变量存储的改变(避免变量共享错误) (JS(ES5)没有块作用域,变量可能会共享)
- 避免非期望的变量共享
this绑定
this绑定
- this
- 被自动定义在所有函数的作用域中的一个关键字
- 在函数运行期间绑定,与函数定义无关
- this作用
- 复用代码,为函数自动引用合适的上下文对象
- 提供了一个更加优雅而简便的方式来隐式传递一个对象引用
- 绑定规则
- 作为函数直接调用 —— 默认绑定
- 作为对象方法调用 —— 隐式绑定
- 作为构造函数调用 —— new绑定
- 通过 call/apply 间接调用 —— 显式绑定
- 变量 _this、that、self 锁定 this(软绑定)
- 通过函数对象的bind方法来锁定(硬绑定)
- 绑定优先级:**new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定 **
严格模式
- 开启方式:某个函数开启严格模式,得把 “use strict”; 声明放在函数体所有语句之前
- 可以应用到整个脚本或个别函数中
- 相对JavaScript语法和行为的不同
- 变量必须先声明再使用
- 全局作用域中函数中的 this 是 undefined不是window对象
- 构造函数不加 new 调用,this 报错 ,不会指向全局对象
- 函数参数不允许重名
高阶函数
- 高阶函数:对其他函数进行操作的函数,函数的参数和返回值均为函数
- 满足条件(至少一个满足)
- 函数作为参数被传递(常见的形式:回调函数)
- 函数作为返回值输出(常见的形式:闭包)
- 对待不确定的变量或过程
构造函数与原型
构造函数三要素
- 构造函数定义与调用
- 首字母大写
- 内部使用this对象指向需要生成的实例对象
- 使用new字符调用
- 实例化与内存
- 实例化:创建一个实例对象,分配内存
- 执行构造函数:对分配的内存空间进行实例化
prototype/____proto
- prototype属性
- 使用者:函数(构造函数指向实例化对象的原型对象)
- 创建者:创建一个函数Fun,则内部包含有prototype属性(指向实例化对象的原型对象),并初始化constructor 属性引用该函数
- 作用:通过原型对象添加属性和方法,实现属性和方法的共享
- ______proto_____属性
- 每个实例对象(Object)都有该属性(指向实例化的原型对象)
- 实例对象可以访问这个原型对象中的属性,就像本身拥有该属性一样
- 原型对象
- 看做公共容器
- 定义在原型对象上的属性会让其所有实例对象都共享这个属性,但是不会在实例内部重新定义这个方法,内存占用较小
- Fun.prototype === fun.proto
- Fun.prototype.constructor === Fun
静态/实例/原型属性
- 实例对象可以访问本身对象上的实例属性,也可以访问原型对象上的原型属性,但是不能访问构造函数上的静态属性。静态属性只能通过构造函数来访问。
new运算符
- 构造函数返回值
- 没有return,返回this,即实例对象
- 有return,且返回值为基本数据类型,构造函数忽略return,返回this对象;返回值为引用数据类型,构造函数返回return值。
- new运算符作用
- 创建空对象,即{}
- 执行[[prototype]]连接
- 将该对象作为this的上下文,并执行构造函数
原型链及JS的继承方式
属性访问机制
- 属性访问机制
- 实例对象继承原型对象的属性,即可以访问原型对象上的属性
- 构造函数与原型对象方法中的this,指向调用该方法的对象
- 通过对象访问属性时,先从本对象查找,接着是原型以及原型的原型。即按照原型链查找。
- 属性屏蔽
- 本对象和原型对象具有相同属性时,不再去原型对象上访问
- 覆写
- 一个对象的属性可以覆写原型对象相同键的属性,此时,前者的属性先被找到,隐藏原型对象的属性,使得原型对象不能被访问。
- JS对象的属性访问链(自有属性和继承属性)
- JS对象的原型链——自有属性和继承属性的操作
- 基于构造函数实现的原型继承——原型链、属性操作
- 可通过实例化出来的对象**proto**属性来确认原型
属性分类
- 属性分类
- 自有属性
- 直接赋予该对象的属性,不需要从原型链上进行查找
- 继承属性
- 从原型链上查找的属性
- 自有属性
- 属性操作
- 添加、修改、删除(自有属性)
- 遍历、访问、检测(自有属性、继承属性)
- 检测属性
- obj.hasOwnProperty(prop)
- 返回布尔值,判断对象自身属性中是否有指定属性
- Object.getOwnPropertyNames(obj)
- 返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性)组成的数组
- prop in obj
- 返回布尔值,检查是否有指定属性名称的属性的对象(包括它的原型链)
- obj.hasOwnProperty(prop)
- 遍历属性
- for in遍历:遍历所有可枚举属性键(包括自有和继承)
原型链
- js基于原型的语言
- 原型链
- 每个对象有一个原型对象(proto),对象从中继承属性和方法,原型对象也可能拥有原型对象,层层类推。这种关系叫原型链。
- 层层向上直到一个对象的原型对象为null。null没有原型,并作为这个原型链的最后一个环节
- **instance.proto === Constructor.prototype **
- 所有非函数对象具有____proto____属性和 prototype 属性
- Function create by Function
- Function.proto==Function.prototype
- Object created by Function
- Object.proto==Function.prototype
- Function.prototype.proto == Object.prototype
- 给 Object.prototype 添加方法和属性,Function.prototype 也会拥有相同的方法和属性,相反则不具有
- Function.prototype 是函数的起源,Object.prototype 是对象的起源
- 获取/设置/判断原型对象
- Object.getPrototypeOf(obj)
- 返回指定对象的原型,如果没有继承属性,则返回 null
- Object.create(proto) :创建对象
- prototypeObj.isPrototypeOf(object)
- 测试prototypeObj对象是否在object对象的原型链上
- Object.getPrototypeOf(obj)
数据类型检测
-
constructor属性
- 用于返回创建该对象的构造函数(eg:Array、Boolean、Date、Function、Number、Object )
- 通过构造函数创建的实例对象可以访问原型对象的constructor属性
- 通过改变原型对象,可以破坏constructor的指向
-
obj instanceof constructor
- 返回布尔值,构造函数的prototype属性值是否出现在某个实例对象的原型链上
-
toString
-
定义在 Object.prototype 对象上的方法,返回一个表示该对象的字符串。因为大部分对象都实现了方法覆写,所以需要通过call/apply来借用Object.prototype 上的 toString 方法 。
-
call调用返回调用者的类型字符串,格式为 [object xxx],xxx 是调用者的数据类型。
-
eg: Object.prototype.toString.call('');//[Object String] Object.prototype.toString.call(1);//[Object Number]
-
-
JS对象—对象原型继承
- 继承方式:对象——对象继承
- 缺点:构造函数实现的对象——对象的原型继承的原型共享问题
通过构造函数模拟类—类继承
JS继承补充部分
- 静态方法与原型方法的区别
- 静态方法是构造器函数对象(类)的方法,原型方法是实例化对象(对象)的原型的方法 。
递归与深浅拷贝
递归
- 一个方法重复调用自身的情况叫做递归
- 注意,一定要有一个条件来结束递归,否则将会陷入无限的循环
深浅拷贝
- 浅拷贝
- 拷贝基本类型的值
- 拷贝引用类型的引用(地址)
- 浅拷贝不是直接赋值,而是新建一个对象,将源对象的属性都一一复制过来。
- 深拷贝
- 深拷贝 = 浅拷贝 + 递归
- 拷贝基本类型的值
- 拷贝引用类型时(eg:数组、对象),使用递归,把父对象中所有属于引用类型的对象都遍历赋给子对象即可
- 缺点:带来性能问题,如果一个对象十分复杂或数据庞大,性能消耗会增加。
- 深拷贝和浅拷贝最根本的区别在于是否是真正获取了一个对象的复制实体,而不是引用
- 使用拷贝的原因:改变新数组(或对象)时,不改变原数组(对象)
标准内置对象
构造器
- 包装对象
- 当访问基本数据类型属性或方法时创建临时包装对象,访问的都是对象中的属性或方法
- 访问对象属性时,首先访问自身属性,访问不到时,则会在原型链上寻找对应的属性和方法
Number
- 原型方法
- Number.prototype.toFixed(…) *
- Number.prototype.toPrecision(…)
- Number.prototype.toString(…) *
- Number.prototype.toExponential(…)
- 静态属性
- Number.MAX_VALUE Number.MIN_VALUE
- Number.NaN
- Number.NEGATIVE_INFINITY
- Number.POSITIVE_INFINITY
Boolean
- 所有对象都是真值
String
- 字符串方法
- 使用
- length、indexOf(value)、charAt(i)、str[i]、slice(start,end)、split()、+、删除内容,遍历(for)、toUpperCase()、toLowerCase
- 规则
- 单 / 双引号声明
- 字符串不可更改,返回全新字符串
- 书写符合小驼峰命名法
- 使用
- 静态方法
- String.fromCharCode(97,98,99);
- 原型方法
- String.prototype.trim( );
- String.prototype.**concat(**str1,str2);
- String.prototype.toLowerCase( ); String.prototype.toLocaleLowerCase( );
- String.prototype.toUpperCase( ); String.prototype.toLocaleUpperCase( );
- String.prototype.indexOf(searchingString,position?);
- String.prototype.lastIndexOf(searchingString,position?);
- String.prototype.search(regexp); *
- String.prototype.match(regexp); *
- String.prototype.replace(regexp); *
Function
- 函数定义
- 函数声明
- 函数表达式
- Function构造函数实例化
- 函数调用
- 作为函数直接调用
- 对象方法
- 构造函数
- call / apply
- 静态属性
- Function.name
- 原型方法
- Function.prototype.apply()
- Function.prototype.bind()
- Function.prototype.call()
- Function.prototype.toString()
Object
- 静态方法
- Object.create() *
- Object.defineProperties()
- Object.defineProperty() *
- Object.getOwnPropertyDescriptor() *
- Object.getOwnPropertyDescriptors()
- Object.getOwnPropertyNames()
- Object.getPrototypeOf()
- Object.setPrototypeOf()
- 原型方法
- Object.prototype.hasOwnProperty() *
- Object.prototype.isPrototypeOf()
- Object.prototype.propertyIsEnumerable()
- Object.prototype.toString() *
- Object.prototype.valueOf()
Date
- Date 提供了解析、管理和展示时间的功能
- 对象基于1970年1月1日(世界标准时间)起的毫秒数
- 以常规函数调用时返回一个字符串,通过new调用,返回的是Date对象
- 没有字面量格式
- Date时间戳
- 北京时间1970年01月01日08时00分00秒)起至现在的总毫秒数
- 时间转换成时间戳
- Date.now()
- (new Date()).getTime()
- 时间戳转换成时间
- new Date(timestamp)
- 创建Date对象及其日期的格式
- new Date(year,month,date,hours,minutes,seconds,milliseconds) //注意起始索引 ,若years为2位的话自动加1900
- new Date(dateTimeStr) //参数为字符串类型,注意格式,参见日期格式
- new Date(timeValue) //参数为数字类型,以毫秒为单位的时间戳
- new Date( ) //返回当前时间
- 静态方法
- Date.now()
- Date.parse() //转成毫秒,从1970年1月1日 00:00:00开始
- 原型方法
- Date.prototype.get( )
- Date.prototype.set( )
- Date.prototype.toLocalTimeString( )
- Date.prototype.toString( )
- Date.prototype.toLocalString( )
- 日期和时间格式
- 日期
- YYYY-MM-DD 、 YYYY-MM 、 YY
- 时间
- THH:mm:ss.sss、THH:mm:ss.sssZ 、THH:mm:ss、THH:mm:ssZ、THH:mm、THH:mmZ
- (T代表时间、Z代表时区信息)
- 日期时间
- YYYY-MM-DDTHH:mm:ss.sssZ
- 时间比较时转换为毫秒比较
- 日期
Array
- 静态方法(ES6)
- Array.from(…) 、Array.isArray(…) 、Array.of(…)等 *
- 原型方法
- 添加和删除元素 —— 破坏性
- Array.prototype.shift() Array.prototype.unshift(elem1,elem2,…)
- Array.prototype.pop() Array.prototype.push(elem1,elem2?,…)
- Array.prototype.splice(start,deleteCount,elem1,elem2)
- 排序和颠倒元素顺序 —— 破坏性
- Array.prototype.reverse()
- Array.prototype.sort(compareFunction)
- 合并、切分和连接 —— 非破坏性
- Array.prototype.concat(arr1,arr2,…)
- Array.prototype.slice(begin,end)
- Array.prototype.join(separator)
- 值的查找 —— 非破坏性
- Array.prototype.indexOf(searchValue,startIndex)
- Array.prototype.lastIndexOf(searchElement,startIndex)
- 迭代 —— 非破坏性
- Array.prototype.forEach(callback,thisValue) *//遍历所有元素
- Array.prototype.every(callback,thisValue) *//判断所有元素是否都符合条件
- Array.prototype.some(callback,thisValue) *//判断是否至少有一个元素符合条件
- 迭代-转换方法 —— 非破坏性
- Array.prototype.map(callback,thisValue) * //对元素重新组装,生成新的数组
- Array.prototype.filter(callback,thisValue) * //过滤符合条件的元素
- 迭代-归约方法 —— 非破坏性
- Array.prototype.reduce(element,initialValue) *
- Array.prototype.reduceRight(callback,initialValue)
- 添加和删除元素 —— 破坏性
Error
- 7种错误
- Error 基类型,其他错误类型都继承自该类型
- ReferenceError: 引用错误
- TypeError: 类型错误
- RangeError: 范围错误
- SyntaxError: 语法错误
- EvalError: Eval错误
- URIError: URI错误
- 异常捕获 —— try catch finally
- try 是必选的,catch 和 finally 两者至少要有其一, 没有 catch 块,程序会终止
- catch 块指定一个标识符(e),该标识符保存抛出异常信息,标识符仅在 catch 块执行时存在;catch 块执行完成后,标识符不再可用
- catch内的错误对象属性
- name :错误名称
- message :错误信息的文本描述
- **异常抛出 —— throw **
- 抛出一个用户自定义的异常
- expression 指定了异常的内容,可以为任何的 JavaScript 值
- Error构造器
- new Error( [message])
- 可以创建一个错误对象。当运行时错误产生时,Error 的实例对象会被抛出
JSON
-
数据传输格式概述(JSON作用:数据交换格式)
- XML:生成与解析麻烦
- JSON:简化格式
-
JSON
-
概述
- JavaScript对象表示法
- 轻量级文本数据交换格式
- 由JavaScript脚本语言演变而来
- 独立于语言和平台
- 文件扩展名.json
- 更小、更快、更易解析
- 是一种数据格式,不是编程语言
- 具有相同的语法形式,但 JSON 并不从属于 JavaScript
- 并不是只有 JavaScript 才使用 JSON
- 很多编程语言都有针对 JSON 的解析器和序列化器
- 是JavaScript 对象的字符串形式的表示法,使用文本表示 JavaScript 对象的信息,本质是一个字符串
-
语法
- 并列数据的集合(数组)用方括号(“[]”)表示
- 并列的数据之间用逗号(", ")分隔
- 映射的集合(对象)用大括号(“{}”)表示
- 映射用冒号(": ")表示
- 字符串必须加双引号
-
可以表示的类型
- 简单值
- 字符串、数值、布尔值和 null,不支持 undefined
- 对象 —— 一组无序的键值对
- 数组 —— 一组有序的值的列表
- 简单值
-
JSON方法
- JSON.stringify(object [,replacer [,space] ] )
- 把 JavaScript 对象格式转化为 JSON 字符串(序列化)
- undefined 值会被忽略
- object:指定要转换的对象
- replacer:参数过滤器为数组时,结果只包含数组中列出的属性 ;参数过滤器为函数时,需接受两个参数,属性键名和属性值
- space:参数为数值时,表示每个级别缩进的空格数;参数为字符串时,使用字符串作为缩进字符
- JSON.parse(json [,reviver])
- 把JSON字符串解析为原生JavaScript对象(反序列化)
- json:参数必须是有效的 JSON,否则会报错
- reviver:过滤器函数,需接受两个参数,属性键名和属性值
- JSON.stringify(object [,replacer [,space] ] )
-
-
应用
正则表达式(RegExp对象)
-
简介
- 对字符串操作的逻辑公式(过滤,替换,判定等)
- 匹配模式,包括字符匹配和位置匹配
-
创建正则表达式
-
创建方式
-
字面量方式
-
推荐优先使用,但是字面量不能够使用变量代替
-
var box = /box/; //直接用两个斜杠 var box = /box/ig; //在第二个斜杠后面加上模式修饰符
-
-
new运算符
-
涉及到转义字符时,需要多写一个 \
-
var box = new RegExp('box'); //第一个参数正则字符串或正则字面量 var box = new RegExp(/box/); var box = new RegExp('box','ig');//第二个参数可选模式修饰符字符串
-
-
修饰符
- i 忽略大小写
- g 全局匹配
- m 多行匹配
-
转义字符
- 具有特殊含义的字符,不能直接匹配使用的,必须使用反斜线(\) 作为前缀进行转义后才能使用。
- . \ / * ? + [ ] ( ) { } ^ | $ -
- 字符串、正则表达式构造函数都使用反斜线(\) 作为转义字符的前缀。
- 具有特殊含义的字符,不能直接匹配使用的,必须使用反斜线(\) 作为前缀进行转义后才能使用。
-
RegExp方法
- test():检索字符串中指定的值,返回true或false
- exec():检索字符串中指定的值,返回找到的值,并确定其位置
-
模式匹配的String方法
- replace():对字符串中特定格式的子串进行替换,返回替换后的结果
- match():一个或多个子串、正则表达式的匹配, 返回一个数组
- 原字符串中匹配到了正则表达式指代的子串,则返回一个数组,否则返回null。
- a*b:以a开始以b结束的字符串
- a.b:以a开始以b结束的最长字符串
- search():返回第一次出现匹配指定正则表达式子串的下标,若没有匹配则返回 -1
- indexOf() 不支持正则表达式
- split():用一个指定的字符串或正则表达式,对原字符串进行拆分,返回拆得的子串数组
- 若指定了 howmany 属性,则只返回拆得的前 howmany 个子串
-
-
-
正则表达式符号
-
元字符:具有特殊含义的字符
- . 匹配任意单个字符,换行符除外
- \w 匹配字母、数字、下换线(字符)
- \W 匹配非字母、数字、下换线(字符)
- \d 匹配数字
- \D 匹配非数字
- \s 匹配空格字符
- \S 匹配非空格字符
- \n 匹配换行符
-
锚字符 :用于查找某个位置
- ^ 匹配字符串的开头,从左向右匹配
- $ 匹配字符串的结尾,从右向左匹配
- \b 匹配字符串的边界,\w 和 \W之间的位置
- \B 匹配字符串的非边界
- 零宽断言
- (?=exp) 零宽度正预测先行断言
- 匹配其后紧接 exp 的字符串(exp表示任意表达式)
- (?!exp) 零宽度负预测先行断言
- 匹配其后没有紧接 exp 的字符串
- (?=exp) 零宽度正预测先行断言
-
方括号:用于查找某个范围内的单个字符
- [abc] 匹配方括号字符集中的任何字符
- [^abc] 匹配任何不在方括号字符集中的任意字符
- [0-9] 匹配任何从0到9的数字
- [a-z] 匹配任何从 a 到 z 的字符
- [A-Z] 匹配任何从 A 到 Z 的字符
- [A-z] 匹配任何从 A 到 z的字符
-
量词:定义字符出现频次的字符
- n+ 匹配任何包含至少一个 n 的字符串
- n* 匹配任何包零个或多个 n 的字符串
- n? 匹配任何包含零个或一个 n 的字符串
- n{x} 匹配包含 x 个 n 序列的字符串
- n{x,} 匹配包含至少 x 个 n 序列的字符串
- n{x,y} 匹配包含 x 至 y 个 n 序列的字符串
-
贪婪和惰性
贪婪匹配 惰性匹配
1、 + +?
*2、 * ?
3、 ? ??
4、 {x,} {x,}?
5、 {x,y} {x,y}?
-
选择和分组
- exp1|exp2|exp3 使用 | 进行条件选择,查找任何指定的选项
- (exp1) 括号中的表达式可以作为一个整体
-
-
正则静态属性
-
正则静态属性
RegExp.$1-$9 RegExp.input ($_) RegExp.lastMatch ($&) RegExp.lastParen ($+) RegExp.leftContext ($`)
-
正则实例属性
-
patten.flags patten.global patten.ignoreCase patten.multiline patten.lastIndex patten.source
-
-
事件与异步
事件绑定
-
分类
-
传统事件绑定
-
内联模型
-
<button onclick="tell();">弹出提示框</button>
-
违反内容与行为相分离的原则
-
-
脚本模型
-
document.getElementById('btn').onclick = function(){ }
-
实现分离,但元素只能绑定一个监听函数
-
-
-
现代时间绑定 —— DOM2级模型
- 实现分离,可以绑定多个监听函数
- **element.addEventListener(type, listener[, useCapture]) **
- type:监听事件类型的字符串
- listener:指定事件触发时执行的函数
- useCapture:布尔值,true指定事件是否在捕获阶段触发,false指定事件在冒泡阶段执行
-
EventTarget对象
- 继承于EventTarget的事件目标对象可以实现事件的分发,并可以为它们创建侦听器来捕获和响应事件
- addEventListener():注册待定事件类型的事件处理程序
- removeEventListener(type,listener):删除事件监听器,具名函数可删除,匿名函数不可删除
- dispatchEvent():向指定事件目标派发事件
-
事件流
- 事件流
- 描述从页面接收事件的顺序
- 模式:冒泡和捕获
- 冒泡
- JS中的事件冒泡:从目标元素到根元素的顺序
- event.stopPropagation():阻止事件冒泡
- event.bubbles : 返回布尔值,是否向上层冒泡
- onmouseover onmouseout —— 支持冒泡
- onmouseenter onmouseleave —— 不支持冒泡
- 应用 —— 事件委托
- 可以将事件监听器设置在其父节点上,并将事件监听器的影响设置为每个子节点
- 捕获设置
- element.addEventListener(type, listener[, useCapture])
- 事件处理周期 : 触发一个事件后,在HTML元素间传播的过程
- 事件捕获:事件对象沿DOM树向下传播
- 目标触发:执行监听函数
- 事件冒泡:事件对象沿DOM树向上传播
异步
-
进程和线程
-
浏览器是多进程的
- Browser进程(主进程,1个)(协调,主控)
- Plugin进程 —— 第三方插件进程
- GPU进程(最多一个,3D绘制)
- Renderer —— 浏览器渲染进程(浏览器内核) (内部多线程)
- GUI 渲染线程
- JS 引擎线程(单线程)
- 事件触发线程
- 定时触发器线程
- HTTP 请求线程
- GUI 渲染线程与 JS 引擎线程互斥
-
任务:同步任务,异步任务(注册回调函数行为)
-
事件轮询
- 消息队列、事件循环
-
定时器:主程序执行完毕后执行
-
setTimeout(function(){ …… …… },1000)
-
-
程序执行过程
- 执行同步任务—> 渲染 —> 任务队列取出一个任务 (重复该过程)
异步数据传输
HTTP协议
- 无状态协议
- 请求响应 : 客户端请求,服务端响应
- 请求报文:请求方法,请求URI,协议版本,可选的请求首部字段,内容实体构成
- 响应报文:协议版本,状态码,原因短句,可选的响应首部字段,实体主体
- URI:统一资源标识符(URL是URI的子集)
- URL转义
- 全局方法
- encodeURI —— 把字符串作为URI进行编码
- decodeURI —— 可对该函数编码过的URI进行解码
- 全局方法
- URL转义
- 方法(Method) —— 告知服务器意图的HTTP方法
- GET —— 获取资源
- POST —— 向服务器端发送数据
- PUT —— 向服务器发送数据,改变数据信息
- DELETE —— 删除文件
- HEAD —— 获取报文首部
- OPTIONS —— 询问支持的方法
- 状态码 —— (表示请求成功或失败的数字代码)
- 1XX:信息性
- 2XX:成功
- 3XX:重定向
- 4XX:客户端错误
- 5XX:服务器端错误
Ajax异步请求
- Ajax(专注于数据传输)
- 改善用户体验,使网页实现异步更新(不重加载进行更新)
- Ajax技术与数据格式无关
- 实质:使用XMLHttpRequest 对象异步的向服务器发送请求
- 最早设计使用XML格式传输数据,现在基本是用JSON(JS天然支持其解析和序列化)
- XMLHttpRequest
- 一般流程
- 创建对象实例
- 创建请求
- 设置事件回调函数
- 发送请求
- 一般流程
- 实例常用属性
- readyState —— 请求状态
- 0:尚未初始化
- 1:正在发送请求
- 2:请求完成
- 3:请求成功,正在接收数据
- 4:接收数据成功
- status
- responseText —— 服务器返回的文本数据
- 请求响应 json 数据时得到的结果为字符串类型
- **onreadystatechange **
- 求状态改变触发器(回调事件处理函数)
- readyState —— 请求状态
- 实例常用方法
- 创建请求 open(method,url,bool )
- method:请求类型get/post
- url:请求地址
- bool:异步/同步请求
- true发送异步请求(用户可以操作页面);false发送同步请求(浏览器锁定当前页面,用户不能操作页面)
- setRequestHeader() —— 指定请求的HTTP开头信息
- send() —— 发送请求
- 方法内传递提交参数(POST方法),没有则默认为 null
- 若是GET方法,可在 open 方法的 “URL” 后面追加参数
- 请求发送到服务器端,收到数据会自动填充实例对象的属性
- 创建请求 open(method,url,bool )
- 提交不同格式的数据
- FormData
- 表示表单数据的键值对的构造方式
- 可以使用 XMLHttpRequest.send() 方法送出
- Document
- Blob
- ……
- FormData
fetch
- 用于网络请求(现代浏览器均提供)
- 返回结果:Promise实例,用于接收请求数据
同源策略(了解)
- 保护某些用户数据的隐私与安全,会限制Ajax技术获取数据的范围和能力
- 有时也会绕过同源策略,实现跨域请求资源
- 跨域:请求能够发送,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了
- Ajax不可以发起跨域请求:跨域是为了阻止用户读取到另一个域下的内容 ,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应
- 一种约定,浏览器最核心最基本的功能
- 限制不同源之间执行特定操作
- 同源:域名,协议,端口均相同
- 特定操作:
- 读取 Cookie,LocalStorage 等中的数据
- 获取 DOM 元素
- 发送 Ajax 请求
Promise和async-await
Promise ——解决回调地狱,提供链式调用
-
回调函数
- 单个异步请求
- 多个异步请求相互依赖 —— 回调地狱
- 存在问题
- 不利于阅读维护
- 异步操作顺序变更时,需要大规模代码重构
- 回调函数大多是匿名函数,bug追踪困难
-
Promise含义 —— 用于异步操作,表示尚未完成且预计在未来完成的异步操作
-
优势
- 将异步操作以同步操作的流程表示,利于阅读维护
- 将数据请求和数据处理明确分开,掌握控制权
-
状态
- pending:初始值
- fulfilled:操作成功
- rejected:操作失败
- 状态转换:只有 等待—>完成,等待—>拒绝
-
Promise构造器
-
Promise是一个构造函数,new Promise 返回promise实例对象
-
接收executor函数作为参数,executor函数两个函数类型形参 resolve,reject
-
Promise构造函数执行时立即调用执行executor函数(同步任务)
-
new Promise(function(resolve,reject){ /*executor*/ })
-
调用resolve成功,pending—>resolve
-
调用失败,pending—>rejected
-
resolve 或 reject 只有第一次执行有效,多次调用没有任何作用
-
-
-
Promise封装异步操作
- 在回调函数中针对不同的返回结果,调用resolve或reject
- 异步操作成功调用resolve函数,将返回值作为参数传递到外部
- 操作失败调用reject函数,将错误信息作为参数传递到外部
-
Promise异步操作结果处理
-
then方法 —— 异步执行
- resolve(成功) onFulfilled 会被调用,onFulfilled 是用来接收 promise 成功的值
- reject(失败) onRejected 会被调用,onRejected 是用来接收 promise 失败的原因
- 调用返回的promise对象保持当前状态,除非新创建
- promise 状态一旦改变则不能再变
-
catch方法 —— 异步执行
-
在链式写法中可以捕获 then 中发送的异常
-
写法
-
promise.then(onFulfilled,onRrejected); promise.then(onFulfilled).catch(onRrejected);
-
-
-
finally方法
- finally()返回一个Promise
- 成功失败都会执行
-
-
任务队列分类
- 宏任务 —— ajax,setTimeout,setInterval,异步IO操作,…
- 微任务 —— Promise.then catch finally
- 宏/微任务执行顺序
- 执行一个宏任务,遇到微任务,添加到微任务队列,一个宏任务执行完毕后,立即执行当前微任务队列中所有微任务(循环该过程知道任务队列为空)
-
静态方法
- Promise.resolve() —— 返回一个状态为 resolved 的Promise对象
- Promise.reject() —— 返回一个状态为 reject 的Promise对象
- Promise.all()
- 将多个 Promise 对象组成的数组包装成一个 Promise 对象
- 数组中 Promise 的状态全部变为 resolved,all 方法返回状态为 resolved
- 数组中 Promise 的状态一个为 reject,all 方法返回状态为 reject
- Promise.race()
- 接收Promise数组,返回新的Promise
- 返回状态由率先完成的Promise的状态决定
async/await —— 包装Promise对象(语法糖)
- async —— 写在函数前面的关键字,表示内部有异步操作
- await —— 写在函数内部,后面是Promise对象,返回该对象结果,不是返回对应值,await返回后,async函数内后续代码才能执行
fetch —— 异步网络请求
- fetch
- 返回Promise实例
- 通过.then接收响应结果
- fetch发起GET请求
- fetch不传递选项时,默认发起GET请求
- 可以明确指定发送GET请求
- 调用形式 :fetch(url,options)
- url 是一个字符串,options是object类型
- fetch发起POST请求
- fetch发起非GET请求时,必须指明method
- fetch响应结果包含的数据(请求结果res包含的属性)
- headers 类型为object,包括响应的头信息
- ok 类型为boolean,请求是否成功
- status 类型为number,响应状态码
- statusText 类型为string,响应状态码对应的文本描述
- text 函数,返回数据的文本格式
- blob 函数,返回数据的原始二进制流
- json 函数,对数据进行JSON.parse后返回,若返回格式不是合法的JSON格式,会报错。