# JS基础
写在前面
尽信书则不如无书,红宝书第第三版有很多翻译的有歧义,而且很多话说的很绕,第四版有很大改进,但也并非完美无缺,下面笔记也会有很多变更的地方,希望自己一个月之内通读完,然后进入下一本
javascript包含,ECMAScript,DOM,BOM。支持uinicode字符标准。
DOM(Documennt Object Model)
- 针对于XML创建扩展用于HTML的API(Application Programming Interface)接口
- DOM视图 View
- DOM事件 Events
- DOM样式 Style
- DOM遍历和范围 Traversal and Range
- DOM加载和保存 Load and Save
- DOM验证 Validation
BOM(Browser Object Model)
- 操作浏览器的接口 不同浏览器实现不同
- 弹出新窗口
- 提供浏览器详细信息 navigator
- 提供页面加载页面信息 Location
- 提供分辨率信息 screen
- Cookie
- XMLHttpRequest
- ie ActiveXObject
- window
xhtml中引入script标签:
<script type="text/jacascript">
//<![CDATA[
xhtml内需要cData,面对不支持的xhtml的加注释hack
//]]>
</script>
2
3
4
5
# 基础的基础概述
# 数据类型(5简单(原始类型(primitive type))+1复杂)
- undefined: [变量初始化]
- null: [空对象指针,对象初始化最好指定]
- boolean(true,false): [false:"",0,NaN,null,undefined]
- number: [IEEE754格式规范:浮点数值有问题],[0:八进制,0x:16进制]
- string
- symbol*新类型
- object详细
因为js变量是松散的,不需要太多的类型,变量仅是占位符。
# Nuamber
number数值转换[Number(),parseInt(),parseFlot()]
- null:0
- undefined:NaN
- obj:先valueOf(),后toString()
# String
- 创建后不可改变,只能销毁在新建
- toString():null,undefined没有toString方法TypeError。
- String():存在toString方法调用,null,undefined 返回字面量。
- 字面量模板(ES6):
${}
# Symbol(ES6)
- 原始值唯一不可改变。typeof 会返回symbol
- Symbol()初始化,可以传参,仅起到描述作用,不影响唯一性
# 操作符
相等与全等
相等先转换在比较,全等不转换仅比较
相等转换规则:
- null和undefined不转换,他俩却相等
- 先转数字,对象调valueOf方法。
null == undefined //true
null === undefined //false
null == false // false
2
3
# 位操作符
- 按位非(~):0变1
- 按位与(&):同1得1
- 按位或(|):有1得1
- 安位异或(^):不同得1
# 布尔作符(逻辑)
- 逻辑非(!):真变假,假变真
- 逻辑与(&&):一假则假,真真得真
- 第一个是false 这直接返回
- 第一个是对象返回第二个
- 都是对象 返回第二个
- 存在null,NaN,undefined 返回 null.NaN,undefined
- 按位或(||):一真则真,假假得假
- 第一个是ture直接返回
- 第一个是对象,直接返回
- 都是null,NaN,undefined,返回null,NaN,undefined,否则返回第二个
# 语句
- if
- do—while
- while
- for
- for-in 都会被遍历,但是没有顺序。
- for-of新:用于遍历可迭代的对象 //TODO:补全
- for-await-of:支持生成promise的可迭代异步对象。
- switch():case[使用的是全等操作,不会触发类型转换]
- with
大量使用with性能会下降,此法欺骗
// with 例
var qs=location.search.substring(1)
var hostName=location.hostname
var url=location.href
with(location){
var qs=search.substring(1)
var hostName=hostname
var url=href
}
2
3
4
5
6
7
8
9
10
# 标签语句
// TODO 标签语句
# 变量作用域和内存问题
原始值(primitive value)基本类型值:按值引用,基本类型不能添加属性(undefiend,Null,boolean,number,string,symbol)别着急
引用值(reference value)引用类型值:是引用类型的实例 引用类型是数据结构
- 不能直接操作内存,所以安引用访问的(不严谨,复制是)
- 复制引用类型,复制的是堆内存指针,复制的是引用。
意淫
👆boolen,number,string是特殊引用类型,但是他们的实例是基本类型值
👇参数只能按值传递,书上说的,下面的例子是证明,但是我觉得是new的问题(nwe 开辟了新的内存地址,切断了)
function setName(obj){
obj.name="along"
obj = new Object()
obj.name = "song"
}
var person = new Object()
setName(person) // 传入对象
console.log(person.name) // along
2
3
4
5
6
7
8
9
**typeof 检测原始值非objct,null还是好用的**numuer,undefined,boolean,string
instanceof根据原型链识别
variable instanceof constructor
person instanceof Object
person instanceof Array
person instanceof RegExp
2
3
4
# 首次谈及执行环境和作用域
- 执行环境(execution context):定义了『变量或函数有权访问的数据』决定了『』的行为,有一个关联的VO
- 变量对象(variable object):『变量和函数』都在这个里面,无法访问,解析器可以
- 活动对象(activation Object):ac最开始只包含arguments对象,这里我理解为:执行到这里,这里的作用域链就变成了ac,ac=作用域链
意淫
- 说说自己的理解,老外的东西说的是贼绕,"代码在一个环境执行时,会创建VO的一个作用于链",作用域链是VO组成的(VO=作用域?),那VO就是作用域!另一本书说 作用域是存储变量的规则
不同时期的产物,可能是同一个东西,不必太过纠结。
# 变量声明
- var
- 提升(hoisting)
- let
- 块级作用域,重复声明报错syntaxError
- 也会提升,因为‘暂时性死区’导致不能用(temporal dead zone)
- const
- 一经声明不可改变,对象的键除外
- 同样块级作用域
- 如果非要对象不变使用Object.freeze(obj)
- 会暗示为单一类型,编译器会将实例替换成实际值,减少查找,增加速度
const a ={}
a.b = 3 //不会报错
a = {} // TypeError
2
3
# 首次谈及垃圾清除
node垃圾清除
垃圾回收时周期性的,每隔一段时间自动运行 函数中局部变量的正常生命周期,变量会在函数执行时存在。此时,栈(或堆)内存会分配空间以保存相应的值。函数在内部使用了变量,然后退出。此时,就不再需要那个局部变量了,它占用的内存可以释放,供后面使用。有时候并不是这么明显。垃圾回收程序必须跟踪记录哪个变量还会使用,以及哪个变量不会再使用,以便回收 内存。如何标记未使用的变量有许多不同的实现方式。在浏览器的发展史上,用到过两种主要的标记策略:标记清理和引用计数。
- 标记清除 当变量进入上下文时会被标记,当变量离开上下文时会被添加离开的标记,具体的实现方式有多种,每个浏览器的周期不同
- 引用计数 主要是解决循环引用的问题,当声明变量并给它赋一个引用值时,这个值的引用数为 1。如果同一个值又被赋给另一个变量,那么引用数加1,如果这个值被覆盖则减1,减到0则可以清理。
- const 和 let 会更早的让垃圾回收程序介入 优化性能,因为用的是块级作用域。
- 最好不要动态的删除或创建对象属性,会改变隐藏的对象,合理的设置null
- 频繁的垃圾回收会影响性能,IE7以后的回收机制是,当回收内存小于已分配内存的15%则分配空间翻倍,如果回收超过85%则分配空间恢复默认值。
# 管理内存
因为出于安全,浏览器分配的内存比(桌面应用)的少,『chrome牛逼』。
- 解除引用:将不用的对象设置null,不挂在根节点的对象会被回收
- 内存泄漏
- 意外全局声明,函数内声明变量千万记得加let const或var
- 定时器setTimeout回到函数引用了外部变量
- 闭包
// 来个泄露的例子吧
(function(){
var a = b = 7
})()
console.log(b) // 7
console.log(a) // 报错
2
3
4
5
6
# 基本引用类型
漂亮文章结构北改了大Function和Object都被提升到新的章节了,原来这张叫基本引用类型,现在一分为三,后续还有集合引用类型,函数
- DateMDN
- RegRxp // TODO:正则小本本要写笔记
# 基本包装类型(Boolean,Number,String)
- 执行机制:
- 创建String类的实例,隐式调用new String()
- 在实例上调用指定方法
- 销毁实例
- 引用值和基本包装类型的区别是:生命周期不一样,只存在代码执行的瞬间,执行后立即销毁
- 不能为基本类型添加属性和方法
- 可以显式声明
var s1 = "sdadf"
s1.color = "red" // undefiend
// 来了
console.log(typeof s1) // string
s1 = new String("sdfasf")
console.log(typeof s1) // object
2
3
4
5
6
# 单体内置对象
另外两个内置对象
- Global 不存在的,兜底对象,
- Math 随机值:num = Math.floor(Math.random()*可能值的总数+第一个肯能值)
- Date
# RegRxp
- g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。
- i:不区分大小写,表示在查找匹配时忽略 pattern 和字符串的大小写。
- m:多行模式,表示查找到一行文本末尾时会继续查找。
- y:粘附模式,表示只查找从 lastIndex 开始及之后的字符串。
- u:Unicode 模式,启用 Unicode 匹配。
- s:dotAll 模式,表示元字符.匹配任何字符(包括\n 或\r)。
# Object对象
- 数据和功能的集合
- Object详细文档
Object()每个实力都具有的方法:
方法 | 描述 |
---|---|
constructor | 保存创建当前对象的函数 |
hasOwnProperty(propertyName) | 检查给定的属性(propertyName)在当前实例中是否存在,不算原型。 |
isPertotypeOf(object) | 检测传入的对象(object),是否是当前对象的原型。 |
propertyIsEnumberable(propertyName) | 检测给定的属性(propertyName)能否for in。 |
toLocaleString() | 返回对象的字符串表示,与执行环境相关。 |
toString() | 返回对象的字符串表示 |
toValueOf() | 通常和toString()相同,字符串,数值或布尔值。 |
Object 构造函数的方法:
方法 | 描述 |
---|---|
Object.assign() | 通过复制一个或多个对象来创建一个新的对象。 |
Object.create() | 使用指定的原型对象和属性创建一个新对象。 |
Object.defineProperty() | 给对象添加一个属性并指定该属性的配置。 |
Object.defineProperties() | 给对象添加多个属性并分别指定它们的配置。 |
Object.entries() | 返回给定对象自身可枚举属性的 [key, value] 数组。 |
Object.freeze() | 冻结对象:其他代码不能删除或更改任何属性。 |
Object.getOwnPropertyDescriptor() | 返回对象指定的属性配置。 |
Object.getOwnPropertyNames() | 返回一个数组,它包含了指定对象所有的可枚举或不可枚举的属性名。 |
Object.getOwnPropertySymbols() | 返回一个数组,它包含了指定对象自身所有的符号属性。 |
Object.getPrototypeOf() | 返回指定对象的原型对象。 |
Object.is() | 比较两个值是否相同。所有 NaN 值都相等(这与==和===不同)。 |
Object.isExtensible() | 判断对象是否可扩展。 |
Object.isFrozen() | 判断对象是否已经冻结。 |
Object.isSealed() | 判断对象是否已经密封。 |
Object.keys() | 返回一个包含所有给定对象自身可枚举属性名称的数组。 |
Object.preventExtensions() | 防止对象的任何扩展。 |
Object.seal() | 防止其他代码删除对象的属性。 |
Object.setPrototypeOf() | 设置对象的原型(即内部 [[Prototype]] 属性)。 |
Object.values() | 返回给定对象自身可枚举值的数组。 |
# 2.Array
# 3.Date类型
# 4.RegExp正则匹配
// TODO 小书
# 5.Function
# 请求响应
# 事件
# xml
# promise
new 立即执行,then
Class myp{
This.val 初始结果空间
resolve(XE)
resolve(val){
This.val=val 保存结果
}
Then(full(val))(
Full(Val)结果传个then执行
)
}
2
3
4
5
6
7
8
9
10
11
# 动画与canvas图型
# requestAnimationFrame
- 参数:下次重绘执行的函数
- return:请求ID
- cancelAnimationFrame(id) 取消
# 节流
浏览器会暴露hook的回调队列在重绘前,队列没有限制
- requestAnimationFrame
- 标志变量
- 计时器
var enabled = true
function a(){
console.log(Date.now())
}
window.addEventListener('scroll',()=>{
if(enabled){
enabled=false
window.requestAnimataionFrame(a)
setTimeout(()=>enabled=true,50)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 2D绘图
- 获取上下文
canvas.getContext("2d")
- 导出canvas图像toDataURL传入MIME类型
canvas.toDataURL("image/png")
- 左下角为(0,0)
- 填充
fileStyle
与描边strokeStyle
- 绘制矩形
fillRect()
,strokeRect()
,clearRect()
分别是实心、描边、橡皮矩形,4个参数(x,y,宽,高) - 绘制路径 arc(x, y, radius, startAngle, endAngle, counterclockwise):以坐标(x, y)为圆 心,以 radius 为半径绘制一条弧线,起始角度为 startAngle,结束角度为 endAngle(都是 弧度)。最后一个参数 counterclockwise 表示是否逆时针计算起始角度和结束角度(默认为 顺时针)。 arcTo(x1, y1, x2, y2, radius):以给定半径 radius,经由(x1, y1)绘制一条从上一点 到(x2, y2)的弧线。 bezierCurveTo(c1x, c1y, c2x, c2y, x, y):以(c1x, c1y)和(c2x, c2y)为控制点, 绘制一条从上一点到(x, y)的弧线(三次贝塞尔曲线)。 lineTo(x, y):绘制一条从上一点到(x, y)的直线。 moveTo(x, y):不绘制线条,只把绘制光标移动到(x, y)。 quadraticCurveTo(cx, cy, x, y):以(cx, cy)为控制点,绘制一条从上一点到(x, y) 的弧线(二次贝塞尔曲线)。 rect(x, y, width, height):以给定宽度和高度在坐标点(x, y)绘制一个矩形。这个方法 与 strokeRect()和 fillRect()的区别在于,它创建的是一条路径,而不是独立的图形。
# 你不知道的js(上)
# 作用域
# 编译原理
js “动态或解释性语言,实际上编译行语言”
大部分编译语言代码执行前(编译)三步:
- 分词/词法分析
- 解析/语法分析(抽象语法树AST)
- 代码生成(根据AST生成指令)
js会比这复杂,
# 理解作用域
引擎:从头到尾负责【编译】及【执行】过程
编译器:语法分析及代码生成
作用域:负责收集维护 所有声明变量 组成的一系列查询,确定当前执行的代码对 变量的访问权限。
- 编译器(左右查找右查找)-->>作用域(var a 将填入作用域)
- 引擎-->>(询问当前【作用域】)
- 无:作用域向上查找
- 有:直接执行
LHS(左查找):赋值
RHS(非左查找): 查找
function foo(a){
var b = a //b=[LHS],a[RHS]
return a + b //a,b[RHS]
}
var c = foo(2) // c=[LHS],foo()[RHS],a=2[LHS]
2
3
4
5
# 作用域嵌套
逐级向上查找,
# 异常
RHS:(未声明)ReferenceError
LHS:
非严格模式:帮你声明
严格模式:ReferenceError
作用域存在:typeError,undefined
# 词法作用域
气泡
# 词法欺骗(不推荐,会降低性能)
eval(修改词法作用域,严格模式被限制)
function foo(str){
eval(str)
console.log(b)
}
var b = 3
foo("var b = 4")//4
2
3
4
5
6
with(创建新的词法作用域,严格模式完全不能用)
//test_1
var obj = {
a:1,
b:2,
c:3
}
//正常
obj.a = 3
...
//with
with(obj){
a = 3;
b = 4;
c = 5;
}
//test_2
function foo(obj){
with(obj){
a = 2;
}
}
var o1 = {
a:3
}
var o2 = {
b:3
}
foo(o1) // o1.a=2
foo(o2) // o2.a undefined, a = 2 会被泄露到全局作用域
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 函数作用域和块作用域
# 函数中的作用域
外部不能访问函数内作用域
# 隐藏内部实现
任意代码片段,函数声明对其进行包装,将其隐藏
最小特权原则(最小暴露原则)
规避冲突
# 函数作用域
问题
首先要生声明一个【具名】函数foo()(污染全局作用域)
必须调用函数foo()
# IIFE(立即执行函数)【immediately invoked function expression】
(function(@param){
。。。
})(@param)
看个人喜好
(function(){
}())
2
3
4
5
6
7
undefined保存
(function(undefined){
a === undefined
})()
2
3
匿名函数的问题
- 不方便调试
- 递归的时候只能使用过期的argument.callee
- 降低可读性
# 块作用域
- let 不会提升,运行前声明不“存在”
if(foo){
let a = 2
console.log(a)
}
//显式
if(foo){
{
let a = 2
console.log(a)
}
}
2
3
4
5
6
7
8
9
10
11
for(i = 0;i<3;i++){
setTimeout(function(){
console.log(i)
},10000)
} // 333
//
for(let i = 0;i<3;i++){
setTimeout(function(){
console.log(i)
},10000)
} // 012
2
3
4
5
6
7
8
9
10
11
- const
# 提升
a = 2
var a
console.log(a)//2
==========
var a
a = 2
console.log(a)
2
3
4
5
6
7
函数优先
foo() //typeError
bar() //ReferenceError
var foo = function bar(){
var a = 2
}
=====
var foo
foo()
bar()
foo = function{
var bar = ...self...
}
2
3
4
5
6
7
8
9
10
11
12
# 作用域闭包
# webpack 前端模块化打包工具
1
npm install webpack --dev
# 模块化
- 全局变量泛滥
- 命名冲突
- 依赖关系管理
初期
//立即执行函数
(function(window){
window.jQurey = window.$ = jQurey
})(window)
2
3
4
现代化(高内聚,低耦合)
- commonJS
- RequireJS(AMD)/SeaJS(CMD)
require(['math'],function(math){
math.add(2,3)
})
2
3
- ES6 module
import math from 'math'
# webpack
npm->loader->source map(排错)->plagin
webpack常用配置包括:
- devtool、
- entry、
- output、
- module、
- resolve、
- plugins、
- externals等
# loader
https://zhuanlan.zhihu.com/p/28245984
loader是一个导出为function的node模块。可以将匹配到的文件进行一次转换,同时loader可以链式传递。
# 梳理
dev 开发环境
devServer
sourceMap
接口代理,proxy
pro 生产环境
treeShaking(清除未用模块)
代码压缩
提取公共代码
共同点
同样的入口,
部分代码相同的
方案
- webpack.prod.js
- webpack.dev.js
- webpack.base.js
webpack-merge
打包优化
- 入口配置,entry多入口(jqurey全局使用)
- 提取公共代码,splithunks
- 动态加载,按需加载
代码包分析工具 webpack-bundle-analyzer
# vue
# 声明式渲染
{{ }}
v-if = "ture|flase"
v-for = "item in items"
v-model
2
3
4
# vue-cli
npm install -g @vue/cli
vue create my-project
2
# vue目录结构
# public
模板文件 单页面文件
# src目录
- assets/ 静态文件
- components/ 组件模块
- router/ 路由
- store/ 状态管理、数据仓库
- views/ 视图
- App.vue Vue跟组件
- main.js 入口文件
- .gitignone git忽略文件
# vue.config.js文件
自己生成,调整vue webpakg 配置
module.exports = {
configureWebpack:{
plugins:[new htmlWebpackPlugin()]
}
}
2
3
4
5
# readme.md与常用命令
npm install 使用
npm run serve 启动hot-reloads
npm run build 项目打包
npm run lint lint代码检测
输出webpack相关配置
npx vue-cli-service inspack --mode production(or development) >> webpack.production.js
# vue-vuex
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
// 状态数据
count:10
},
getters:{
// 计算属性
},
mutations: {
// 唯一改变state 得方式
},
actions: {
//进行异步处理
},
modules: {
// 模块化
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# koa
# koa-static 静态文件
const statics = requeire('koa-stacit')
const staicsPath = './static'
app.use(statics(
path.join(__dirname,staicsPath)
))
2
3
4
5
# 闭包(closure)
闭包是函数和声明该函数的词法环境的组合 闭包就是能够读取其他函数内部变量的函数。 闭包
# 闭包的作用
- 实现共有变量 累加器
- 可以做缓存
- 可以是实现封装,属性私有化
- 模块开发防止污染全局变量
# 立即执行函数
执行后立即销毁 实际上表达式都可以被执行 eater Person
(function(){}()); //W3c
(function(){})();
2
# 函数声明转表达式
+ function text() {};
- function tect() {};
! function tect() {};
2
3