JS执行机制
1 预编译 -- 把当前作用域内的, var变量声明和函数声明, 提升到作用域的最前面
2 执行列队
1 先执行执栈中的同步任务 -- 把遇到的异步任务交给异步处理进程 -- 然后由异步处理进程决定放入任务队列的时间 -- 触发时才会放入
2 等执行栈中的同步任务执行完毕 -- 再依次读取任务列队中等待的异步任务 -- 放入执行栈中开始执行
3 主线程 -- 执行栈 -- 不断重复获取任务列队的任务并执行, 这种循环的机制被称为 --> 事件循环 (event loop)
3 知识点
1 对于定时器, 只有等待时间过了, 才会被异步进程写到任务列队里面
2 对于事件, 只有触发了, 才会被异步进程写到任务列队里面
3 在事件列队中优先执行微任务, 然后执行宏任务, ajax只要请求到数据就放在第一位执行 (ajax不是微任务, 也不是宏任务)
同步 / 异步
1 了解 -- JS 是单线程 -- 同一时间只能做一件事 -- 上一个任务结束, 下一个任务才可以开始
2 了解 -- 如果某段代码执行时间太长 -- 会导致后面的代码无法执行, 也就是加载阻塞
3 解决 -- 把我们的任务分为了俩大类 -- 同 步和异步
4 同步任务 -- 都放在主线程上按照单线程的方式执行的, 形成一个执行栈
5 异步任务 -- 通过回调函数实现的, 放在异步队列里面等待执行的任务
6 常见的异步任务 -- 事件监听 -- 定时器 -- Promise -- ajax -- async ..
作用域
1 一块区域空间, 存在作用域的地方 -- js文件 -- script标签 -- 函数内部 -- ES6的大括号
2 一个作用域内的代码和变量, 对该作用域外部的环境, 毫无影响
3 全局作用域的生命周期 --> 进入页面创建 关闭页面销毁
4 函数作用域的生命周期 --> 函数执行的时候创建 执行完毕销毁
5 作用域链:
1 内部作用域可以访问外部作用域, 且遵守就近原则
2 作用域 a内部创建作用域b, b可以访问a中的变量, a不可访问b中的变量
堆和栈
1 栈 --> 存放简单数据指向变量, 重新赋值会覆盖原有值, 原有数据不会销毁, 只是没有指向了
2 堆 --> 存放复杂数据 -- 生成索引放在栈中指向变量 -- 改变复杂数据的值会影响所有指向它的变量
闭包
1 产生
1 俩个相互嵌套的函数 -- 内部函数作用域访问了外部函数作用域中的变量
2 当内部函数被return到外部 -- 声明变量接收且执行的时候 -- 这个函数会在执行体处访问它所在环境的外部函数的变量
3 这个访问的过程就是闭包, 或者指被访问的函数是闭包
2 作用: 延申了变量的作用范围, 实现封装, 属性私有化 -- 模块化开发, 防止污染全局变量
3 危害: 闭包会导致原有作用域链不释放, 造成内存泄漏 (即使内存占用过多)
4 简单实现闭包的代码
function a() {
var x = 9
function b() {
console.log(x);
}
return b
}
var hh = a()
hh()
原型
1 概念
-------------------------------------------------------------------------------------
1 我们把 JS中的对象分为 普通对象 和 函数对象
2 函数对象都有 prototype 原型属性 – Function.prototype 除外 – 普通对象没有该属性
3 所有函数都是 Function() 构造函数的实例 – Function.prototype == fn / Function.prototype.prototype == ubdefined
4 prototype 的主要作用 – 所有添加到原型对象上的属性方法, 都将被所有实例对象共享 – 就是继承
5 对象都有 proto 隐藏属性 – 主流浏览器自带的, 不是给开发者用的
6 对象都有 constructor 属性 – 属性值为该对象的构造函数或类
7 根构造器 Object – Object.prototype.hh = 777 --> 所有对象都可以访问 hh了
8 原型链 – 就是多个原型之间的特殊的访问关系
9 prototype==JS的原型对象 / proto 浏览器自带的原型对象
-------------------------------------------------------------------------------------
2 原型之间的关系
-------------------------------------------------------------------------------------
1 理解
1 obj.__proto__ == obj构造器的 prototype -- 一个对象可访问它原型链上的所有属性和方法
2 构造器的 __proto__ == ƒ () {
[native code] }
3 Object == 根构造器
4 Object.prototype == 原型链的末端
5 Object.prototype.__proto__ == null
2 常见场景
1 创建字符串 -- var str = "zhang"
2 原型指向 --> str.__proto__ == String.prototype
3 原型指向 --> String.prototype.__proto__ === Object.prototype
4 原型指向 --> Object.prototype.__proto__ === null
4 案例解析
1 Object.prototype.hh = 77 --> var str = "zhang" --> console.log(str.hh)
2 浏览器通过原型链查找 hh 属性过程
1 str.hasOwnProperty('abc') false
2 str.__proto__.hasOwnProperty('abc') false
3 str.__proto__.__proto__.hasOwnProperty('abc') true -> 返回 hh 的属性值 66
4 str.__proto__.__proto__ == String.prototype.__proto__ == Object.prototype
-------------------------------------------------------------------------------------
3 继承
-------------------------------------------------------------------------------------
1 继承的方式
1 构造函数继承 有局限性…
2 原型继承 不合常理…
3 拷贝继承 父子对象都会受到影响…
4 混合继承 常用的实现继承方式
5 class类继承 常用的实现继承方式
-------------------------------------------------------------------------------------