第一章 什么是JavaScript
完整的js包含以下几个部分
ECMAScript(核心)
DOM(文档对象模型)
BOM(浏览器对象模型)
web浏览器只是ECMAScript实现可能存在的一种宿主环境。
DOM 文档对象模型 (DOM,Document Object Model)是一个应用编程接口(API),用于在HTML中使用扩展的XML。
BOM 浏览器对象模型,主要针对浏览器窗口和子窗口。
第二章 HTML中的JavaScript
标签 < script >
async: 立即下载脚本,但不阻止其他页面动作,异步
defer: 同步,立即下载,延迟执行,可以延迟到文档完全被解析和显示之后再执行
代码中不可以出现< script />否则会报错
第三章 语言基础
var
在全局声明会变成windox的属性,具有变量提升,函数作用域,无块级作用域的概念,可重复声明
//变量提升
function test(s){
console.log(s)
var s = 2
function s(){}
console.log(s)
}
test(1)
//ƒ s(){}
// 2
相当于
var s = 1
(function(){
console.log(s)
var s = 2
function s(){}
console.log(s)
})
// 函数提升的优先级高于var 变量提升 ,优先提升函数,所以先输出function (){},随后,输出s=2
console.log(a)
var a = 5
//等于
// var a
// console.log(a)
// a = 5
function test(){
message = "ok" //全局对象
}
test()
console.log(message) // ok
let
块级作用域( 看 {} ) 块级作用域小于或等于函数作用域,不可重复声明
暂时性死区:使用未声明的let/const变量时,js引擎也会注意到后面的let变量,但是在这个变量声明之前,不能够使用,这段时间就叫做,暂时性死区
for循环的时候
for( var i = 0; i<5 ; i++){
}
console.log(i)// 5
//let 报错
const
和let类似,但是声明时必须要赋值,而且不能够重新赋值和重复声明。
优先用const,其次let
数据类型
undefined 未定义
null 对空对象的引用,逻辑上是表示一个空对象指针。
NaN not a number 表示本来要返回数值的操作,但失败了 ,such as (0/0,5/0)
isNaN('red') // true
isNaN(true) //false 可以转为1
//判断是否 “不是数值”
Symbol
符号是原始值,且符号实例是唯一,不可变的,符号的用途是确保对象属性使用唯一标识,防止冲突。
操作符
3 ** 2 = 9
4 ** 2 = 16
2 + ‘2’ = 22
“a” > "A" //true 比的是字符编号
“23” < 2 //false 23 > 2
只要和NaN 比较都为false
NaN < 3 false
NaN >= 3 false
NaN != NaN true
语法
for in 枚举对象中非符号键的属性
for(let key in obj){} //key obj属性名
for of 遍历可迭代对象
for(let el of [1,2,4]){console.log(el)} // 1 2 4
第四章 作用域与内存
原始值(undefined null boolean number string symbol)大小固定,保持在栈内存
对象存储在堆内存
任何变量都存在于某个执行上下文中(也称作用域),这个上下文(作用域)决定了变量的生命周期,以及它们可以访问哪些代码部分。
执行上下文分全局上下文、函数上下文、块级上下文
代码执行流每流进入一个新上下文,都会创建一个作用域,用于搜素变量和函数
传递参数
所有函数的参数都是按值来传递的。就算是传引用形数据类型(对象)也是按值来传
function test(a){
console.log(a) //Identifier 'a' has already been declared
let a = 5
console.log(a) //Identifier 'a' has already been declared
}
test(1)
function test(a){
console.log(a) //1
var a = 5
console.log(a) //5
}
test(1)
执行上下文与作用域
在v8环境下,函数会被提升,会被先解析
每一个执行上下文会关联一个vo对象(variable Object)变量对象
全局代码被执行,关联的就是GO(gobal Object)
函数被执行,关联的就是AO(activation Object)
执行上下文栈,底层一般是全局上下文
vo会有一个 作用域链对象 scope chain对象,决定各级上下文中代码在访问变量和函数时的顺序是
函数优先访问自己的AO,找不到变量就通过作用域链,向上查找,最后是向GO查找,作用域链仅仅和函数定义的位置有关,和调用无关
function(){ a = 5 } 未定义直接赋值会变成全局变量
垃圾回收
js通过自动内存管理实现内存分配和闲置资源回收,哪个变量不用了就会释放它的内存,这个过程是周期性。垃圾回收程序需要跟踪记录哪个变量不使用,标记策略一般有两种(标记清理和引用计数)
垃圾回收是周期性运行,时间调度很重要,在移动设备上,垃圾回收有可能明显拖慢渲染速度和帧速率。
一般基本都是根据已分配对象的大小和数量来判断何时运行,可手动触发回收但不推荐。
标记清理(最常见)
当变量进入上下文,比如在函数内部声明一个变量时,这个变量会被加上存在于上下文的标记。而在上下文的变量,只要不离开上下文就永远不会被释放内存,因为有可能用到。离开时也会被加上离开的上下文的标记。
加标记的方式:例如当变量进入上下文,反转某一位
垃圾回收程序运行:标记内存中存储的所有变量,然后去掉所有上下文变量的标记(包括引用的变量),最后剩下的,再被加上标记的变量就是等待删除的。随后垃圾回收程序做一次内存清理。
引用计数
记录每个值的引用次数,声明并赋值变量+1,引用被覆盖-1,0的时候被回收
缺点:对象相互引用,不能释放内存
let obj1 = {}
let obj2 = {}
obj1.a = obj2
obj2.a = obj1
内存管理
优化内存的最好方法,只保存需要用的数据,不用的就设为空
1 多用let、const ,不用var
2 隐藏类和删除操作(极致性能)
//创建好后又补充新属性,导致两个不是共用一个隐藏类
function test(){this.name="zhangshan"}
let a1 = new test()
let a2 = new test()
//a1 a2 共享相同隐藏类,如果补充a1.age = 18,a1 a2将对应两个不同隐藏类
//解决方案
function test(age){this.name="zhangshan",this.age = age}
let a1 = new test()
let a2 = new test(18)
//删除一个属性,保持同一个隐藏类,用null
function test(){this.name="zhangshan" this.age =18}
let a1 = new test()
let a2 = new test()
delete a1.author //不在用同一个隐藏类
a1.author = null //还是同一个隐藏类
内存泄漏问题
意外全局变量
function(){ age =18 }
定时器
let name = "a"
setInterval(()=>{
console.log(name)
},1000)
//一直使用name,无法释放name内存
闭包
// 调用outer 会使name内存泄漏
//创建一个内部闭包,返回函数占用name,导致内存无法释放,如果name占的空间很大就有大问题了
let outer = function(){
let name = "a"
return function(){
return name
}
}
静态分配与对象池
减少浏览器垃圾回收的次数,不能直接控制什么时候开始收集垃圾,但是可以间接控制触发垃圾回收条件。(合理分配内存)
对象池 解决对象更替速度过快导致频繁垃圾回收
在初始化的某一时刻,创建一个对象池,统一管理一组可回收的对象,应用程序可以向这个对象池请求一个对象,设置其属性,使用它,然后操作完成后再把它还给对象池,由于没发生对象初始化,垃圾回收探测就不会发现有对象更替,垃圾回收就不会那么频繁的运行。
第五章 基本引用类型
Data
RegExp
Boolean
Number
String
Global
Math
具体用到,忘记api看红宝书
第六章 集合引用类型
API
map set
第七章 迭代器和生成器
第八章 对象与面向对象编程
属性类型 vue2
属性:分为数据属性和访问器属性
数据属性
- Configurable 是否可以被修改特性,是否可以被delete删除并重新定义 默认true
- Enumerable 是否可以通过for-in循环返回 默认true
- Writable 属性值是否可以被修改 默认true
- Value 包含属性实际值 默认undefined
要修改属性默认特性,必须使用Obecgt.defineProperty(要给其添加属性的对象,属性名称和一个描述对象,描述对象上的属性可以包含)
let person = {}
Object.defineProperty(person,"name",{
writable:false,
value:"zhangshan"
})
console.log(person.name) //zhangshan
访问器属性 vue2双向绑定核心
它包含一个获取(get)函数和一个设置(setter)函数
- Configurable 是否可以被修改特性,是否可以被delete删除并重新定义 默认true
- Enumerable 是否可以通过for-in循环返回 默认true
- Get 获取函数,读取属性时调用,默认值为undefined
- Set 设置函数,在写入属性时调用,默认值为undefined
let person ={age:18}
Object.defineProperty(person,"age",{
get(){
return this.age
},
set(newValue){
if(newValue>20)
return "超过20岁"
else{
return newValue
}
}
})
//定义多个属性
let person = {age:18,name:zhangsan}
Object.defineProperties(person,{
sex:{
value:"男"
}
age:{
get(){
return this.age
}
}
})
Object.getOwnPropertyDescriptor()获取指定属性和属性描述词 Object.assign() 合并对象,接收一个或多个源对象作为参数
判断NaN
Object.is(NaN,NaN) true
创建对象
工厂模式
函数内直接创建一个新对象,并设置好属性,最后返回出去
构造函数模式
和工厂模式类似,但是没有new新对象,用this赋值属性和方法,没有return
new的过程
- 内存中创建一个新对象
- 绑定prototype原型链
- 把构造函数内部的this被赋值为这个新对象(this指向新对象)
- 执行构造函数内部代码(给新对象添加属性)
- 如果构造函数返回非空对象,则返回该对象,否则返回刚创建的新对象
构造函数也是函数,可以直接执行,但是此时this为Global对象(浏览器为window)
问题:分别创建两个实例,方法名相同但是不是同一个方法,每次都new一个新的函数
this.say = new Function(“console.log()”)
不同实例上的函数同名但不相等(person1.sayName == person2.sayName) false
原型模式
解决上面的构造函数问题,属性和方法可以被对象实例共享。直接在prototype上绑定属性方法
盗用构造函数
解决原型包含引用值导致的继承问题,并且可以在子类构造函数向父类构造函数传参,在子类调用父类构造函数,使用apply() call()
区别开属性共享问题,每个实例有自己的属性
缺点:必须在构造函数中定义方法,因此函数不能重用
组合继承
综合原型链和盗用函数,集中两者优点,使用原型链继承原型的属性和方法,盗用构造函数继承实例属性,让方法定义在原型上实现重用,又可以让每个实例都有自己的属性。
使用最多的方法
原型继承
适合不需要单独构建构造函数,但仍然需要在对象间共享信息的场合。本质上给定对象执行浅复制
寄生式继承
和原型式比较接近。先基于一个对象创建一个新对象,然后再增强这个新对象,最后返回新对象。
寄生式组合继承
存在效率问题,父类构造函数始终被调用两次。被认为是基于类型继承的最有效方式
类
类和函数相似,但是类不能提升
和构造函数的区别,类必须new
继承
class Bus extends Vehicle{}
访问父类静态方法super.xxxx()
第九章 代理与反射
代理:作为目标对象的替身,但又完全独立于目标对象,目标对象可以直接被操作,也可以代理操作 用处:重新定义对象基本操作跟踪
proxy(目标对象,处理程序对象)
核心-定义捕获器 :拦截自定义目标对象操作(访问属性,调用方法)
//手动写代码
const target = {age:18}
const handler = {
get(trapTarget,property,receiver){
return trapTarget[property]
}
}
const proxy = new Proxy(target,handler)
//借助Reflect
const target = {age:18}
const handler = {
get(){
return Reflect.get(...arguments)
}
}
//
revocable()可以撤销代理对象和目标对象的关联
可以多层代理
//set(target,property,value,receiver)
const person = {age:10}
const proxy =new Proxy(person,{
set(target,property,value,receiver){
if(value <18){
return false
}else{
return Reflect.set(...arguments)
}
}
})
proxy.age = 12 // 10
proxy.age = 20 // 20
第十章 函数
箭头函数
不能使用arguments、super、new.target,也不能作构函数,此外,箭头函数也没有protorype属性。
理解参数
调用函数可以传任意个参数都不会报错,原因是函数参数在内部表现为一个数组,非箭头函数可以用arguments查看参数。
闭包
函数访问函数外的变量,一般是嵌套函数,闭包存在内存泄漏问题。
立即调用函数
(function(){
var i = 5
})()
console.log(i) //报错,访问不到i
私有变量
静态私有变量
模块模式、模块增强模式
第十一章 期约与异步函数
Promise.all()和Promise.race()
第十二章 BOM
window
BOM核心,windox对象,两个身份Global对象和浏览器窗口的js接口。
系统对话aler(),confirm(),prompt()