一. 作用域
作用域是什么?
- 作用域是存储变量的一套规则,比如函数作用域,块作用域,全局作用域
- 作用域组成: 引擎 编译器 作用域
举例: var a = 1 分为两个阶段: 1. 编译阶段声明变量 2. 执行阶段赋值
LHS: 变量赋值 RHS: 变量查找
- 编译的原理
js–(分词/词法分析(tokenizing/Lexing))–>有意义代码块–(解析/语法分析)–>AST–(代码生成)–> 执行代码
- js引擎: 先编译后执行
二. 词法作用域
作用域的两种工作模式: 词法作用域和动态作用域
1. 查找:作用域查找会在找到第一个匹配标识符停止
2. 欺骗词法eval:修改作用域 with:创建新的作用域
后果:导致js引擎在静态分析时停止优化,导致性能下降三. 函数作用域和块级作用域
遵循最小授权原则
1. 隐藏内部实现
2. 规避冲突
3. 立即执行函数(IIFE)四. 提升
- var a = 1 –> var a;(编译阶段) a=1; (执行阶段)
- 优先级: 函数提升> 变量提升
五. 作用域和闭包
闭包: 基于词法作用域书写代码产生,在词法作用域以外执行
1. 函数内定义,外部调用
2. 函数内定义匿名函数,并执行 如:定时器和事件绑定
循环和闭包:
var后面的i会覆盖前面的i,let每次创建是块作用域不会覆盖,也可以用户IIFE创建一个函数作用域防止覆盖
模块
模块模式的两个条件:
1. 必须有外部的封装的函数,并至少执行一次
2. 封装函数至少返回一个内部函数
基于函数的模块只有在运行时才能被考虑,无法静态分析 import不需要动态作用域: 运行时决定
静态作用域: 定时时确定第二部分 this和对象原型
一. 关于this
为什么使用?
- 可以隐式传递一个对象的引用,代码更加优雅
- 特点: 动态绑定,取决于调用的位置二. this全面解析
调用位置:
this所在函数被称为调用栈,调用栈在全局,this调用位置就是全局作用域
绑定规则:
1. 默认绑定 全局对象|undefined
2. 隐式绑定 函数调用 隐式丢失:var bar = obj.foo() bar()
3. 显示绑定 call apply 硬绑定: bind 软绑定 new 绑定
- 优先级: 硬绑定 > new 绑定 > 软绑定
- 绑定例外: 忽略this foo.call(null)
- ES6 无法绑定this, 继承外层作用域this三. 对象
- 创建: 字面量和构造函数
- 一个bug: null是值类型,typeof缺失object 原因是typeof会将二进制前三位为0的判断的为对象,null全都是0
- 内容: 属性访问和键访问(可以不是有效标识符)
- 数组: 本质也是对象,[][‘name’] = ‘iwen’ [][‘4’] = ‘bar’自动转化
- 复制对象:
- 浅拷贝: Object.assign()
- 深拷贝:JSON.parse( JSON.stringify( obj) )
- 属性描述: Object.defineProperty 密封:seal 冻结: freeze
- 获取设置:底层: [[get]] [[put]] 隐式: getter setter 显示:get set
四. 混合对象‘类’
类是一种设计模式
1. 多重继承
2. 混入 浅拷贝 Object.assign()
3. 显示伪多态: Obj.bar.call(this, …)
注意点: 显示混入只能复制对象的引用,无法复制对象和函数本身