词法结构
字符集
使用 Unicode 编写
ES3 Unicode2.1+
ES5 Unicode3+
区分大小写
注释
// 注释
/*
注释
*/
标识符和保留字
必须以字母、下划线、美元符开始,后续字符可以是字母、数字、下划线、美元符,即数字不能作为首字符
保留字
可选的分号
Javascript 只有在缺少了分号就无法正确解析代码的时候才会填补分号。
一般,一条语句以(、[、/、+、- 开始,它极有可能和前一条语句一起解析。return、break、continue 除外
类型、值和变量
数据类型:在编程语言中、能够表示并操作的值的类型
变量:一个值的符号名称,可以通过该名称获得值的引用。
数据类型
一般分类
原始类型:数字、字符串、布尔值、null、undefined
对象(属性的键值对集合)类型:数组、普通对象、函数类、日期类、正则类、错误类
其他分类
可以拥有方法的类型和不能拥有方法的类型
可变类型(数字、布尔值、null、undifined、字符串)和不可变类型(对象、数组)
数字
javascript 采用 IEEE 754 标准定义的 64 位浮点格式表示数字,最大值±1.7976931348623157E+308,最小值±5E-324
能够表示的整数范围为 -2E+53~2E+53。实际操作(如数组索引)是基于 32 位整数。
注意:小数精度问题,如 0.1+0.2 != 0.3,需要转成整数计算,计算完成再转回小数。产生原因是 Number 采用的时 IEEE 754 64 位双精度浮点数编码,浮点数无法精确表示其值范围内的所有数值,导致十进制转换成二进制时有舍入模式,产生了误差
格式
整形直接量
浮点直接量
算术运算
上溢出(正负无穷)使用±Infinity 表示,下溢出(无限接近于 0)则返回 0(±0)。
NaN 和任何值都不相等,包括自身。
二进制浮点数和四舍五入错误
在 javascript 使用实数时,常常只是真实值的一个近似表示。
let x=0.3-0.2
let y=0.2-0.1
x==y // false
x==0.1 // false
y==0.1 // true
// 由于舍入误差,0.3 和 0.2 之间的近似差值实际上不等于 0.2 和 0.1 之间的近似差值
文本
字符串是一组由 16 位值组成的不可变的有序序列。字符串长度是其所含的 16 位值的个数。
转义字符
布尔值
true 或者 false 可转换为 false 的值:undefined、null、0、-0、NaN、”。
null 和 undifined
typeof null 为 object,含义为非对象
undifined 未定义值
全局对象
全局属性、全局函数、构造函数、全局对象
包装对象
存取字符串、数字或布尔值的属性时创建的临时对象叫包装对象。
不可变的原始值和可变的对象引用
可变类型(数字、布尔值、null、undifined、字符串)和不可变类型(对象 / 引用类型、数组)。
类型转换
转换和相等性
显式类型转换
变量声明
如果给一个未声明的变量赋值(不可配置),实际上会给全局对象创建一个同名属性(可配置),不建议这样用。
创建一个全局变量实际上是给全局对象创建了一个属性。
变量作用域
一个变量的作用域是程序源代码中定义这个变量的区域。
函数作用域、块级作用域。
声明提前
类型检测
typeof 用于基础类型和函数判断
instanceof 用于对象类型判断
Object.prototype.toString.apply([])==='[object Array]’ null、undifined 失效
表达式和运算符
表达式
表达式分为简单表达式(常量、变量名)和复杂表达式(由简单表达式组成)。
原始表达:
表达式的最小单位,
直接量(包括:数字、字符串、布尔,不包括数组、对象)
关键字
变量
由简单表达式可以组合成复合表达式
复杂表达式
对象和数组的初始化表达式
函数定义表达式
属性访问表达式
调用表达式
对象创建表达式
运算符
说明:
下图按照优先级高到低排序,水平线分割的具有不同的优先级
A 列表示运算符结核性,L(左到右)R(右至左)
N 列表示操作数的个数
类型列表示期望的操作数类型以及运算符的结果类型
分类
按照操作数个数分:一元(+1)、二元(1+2)、三元(?:)
左值
表达式只能出现在赋值运算符的左侧。变量、对象属性、数组元素均是左值。
算术表达式
一元算术运算符
作用于一个单独的操作数,并产生一个新值,具有很高的优先级,且均为右结合。
+:转换为数字或者 NaN,并返回转换后的值
-:和 + 一样,但是会改变结果的符号。
++ 和 –: 运算符在操作数前,操作数±1 并返回计算后的值;运算符在操作数之后,操作数±1,并返回计算前的值。
, 逗号运算符,从左到右一次执行,返回最右边的值
关系表达式
in
instanceof
逻辑表达式
赋值表达式
其他运算符
?:
typeof
delete
viod
, 逗号运算符,从左到右计算,最后返回最右边的值
语句
声明语句
变量 var let
函数 function
条件语句
switch
switch(expression){
statements
}
// expression 中计算是使用 ===
循环
do/while
do{
statements
} while(expression)
// 至少执行一次
for/in
// 将对象中的所有属性复制到一个数组中
var o = {x:1,y:2,z:3};
var a = [], i = 0;
for(a[i++] in o) /* empty */;
跳转
标签语句
mainloop: while(token I= null) {
// 忽略这里的代码...
continue mainloop; // 跳转到下一次循环
// 忽略这里的代码...
}
// 从标签名开始,以便在报错时退出程序
compute_sum: if (matrix) {
for(var x = o; x < matrix.length; x++) {
var row= matrix[x];
if (!row) break compute_sum;
for(var y = o; y < row.length; y++) {
var cell= row[y];
if (isNaN(cell)) break compute_sum; sum+= cell;
}
}
success= true;
}
// break 语句跳转至此 II 如果在 success== false 的条件下到达这里,说明我们给出的矩阵中有错误//否则将矩阵中所有的元素进行求和
其他语句类型
width
// 临时扩展作用域链
with(document.form[0]){
name.value=””
}
try/catch
try{
xxxx
}catch(e){
xxx
}finally{
xxx
}
对象
创建对象
对象直接量创建的对象原型为 Object.prototype
通过 new 创建的对象原型为使用的原构造函数的 prototype
Object.create()创建的对象原型为第一个参数,也可设置为 null
属性的查询和设置
属性访问错误
查询属性和原型有关,设置与原型无关(如果设置属性为继承属性,且具有 setter 方法时,将执行 setter,而不是给当前对象创建新的属性)
下列情况给对象 O 设置属性 P 会失败
O 中属性 P 是只读的(defineProperty()方法中有例外)
O 中的 P 是继承的,且是只读的
O 中不存在属性 P,O 中没有使用 setter 方法继承属性 P,并且 O 的可扩展性()是 false
检测属性
in:x in o
hasOwnProperty: O.hasOwnProperty(x)
propertyIsEnumerable: o.propertyIsEnumerable(x),hasOwnProperty 的增强版,自身属性且可枚举
o.x!==undefined x 的值为 undefined 则需要使用 in
属性的特性
值 value
可写性 writable
可枚举性 enumerable
可配置性 configurable
获取自身属性的特性
Object.getOwnPropertyDescriptor({x:1},’x’)
// 返回{value:1,writable:true,enumerable:true,configurable:true}
设置属性的特性
// 单个
Object.definePeoperty(o,’x’,{
value:1, // 值
writable:true, // 可读
enumerable:true, // 可遍历
configurable:true // 可改变配置
})
// 批量
Object.definePeoperties(o,{
x:{
value:1,
writable:true,
enumerable:true,
configurable:true
},
y:{
value:1,
writable:true,
enumerable:true,
configurable:true
}
})
对象的三个属性
原型
查询原型 Object.getPrototypeOf()
检测是否包含某个原型 p.isPrototypeOf(o),p 是否是 o 的原型
类属性
可以通过 toString 获取对象的类属性
function classof(o){
if(o===null) return ‘Null’;
if(o===undefined) return ‘Undefined’;
return Object.prototype.toString.call(o).slice(8,-1);
}
classof({}) // => ‘Object’
可扩展性
查询可扩展性 Object.isExtensible(o)
转换成不可扩展 Object.preventExtensions(o)
封闭:转换为不可扩展且所有属性不可配置 Object.seal(), 可使用 Object.isSealed()来检测是否封闭
冻结:转换为不可扩展且所有属性不可配置、所有属性只读 Object.freeze(), 可以使用 Object.isFrozen()来检测是否冻结
序列化
JSON.stringify(),JSON.parse()具可接受第二个参数,标识需要序列化或还原的属性列表
对象方法
toJSON()
valueOf()将对象转换成原始值
数组
创建数组
数组直接量 [],该语法有可选的结尾逗号,故[,,] 只有两个元素而非三个
new Array()
new Array() // 创建一个空数组
new Array(10) // 创建一个长度为 10 的数组
new Array(5,4,3) // 创建一个已包含数组元素数组
稀疏数组
稀疏数组并不是项的值为 undefined,而是不存在
// 三种方式创建
// 1
new Array(5)
// 2
a=[]
a[1000]=0
// 3
delete
数组方法
* 标识为变异方法
join
reverse *
sort *
concat
slice
splice *,返回删除元素组成的数组
push/unshift *,返回数组新的长度
pop/shift * 返回删除元素的值
toString/toLocalString 无方括号,逗号分隔
forEach
map
filter, 可以使用来压缩稀疏数组
every 所有元素调用判定函数,均返回 true 才返回 true
some 所有元素调用判定函数,有一个返回 true 就返回 true
reduce/reduceRight
// 求和、第二个参数为 temp 的初始值,不传默认使用数组中的第一个元素
arr.reduce((temp,value,index,arr)=>temp+value, 0)
indexOf/lastIndexOf
数组类型
判断使用 Array.isArray(arr)判断是否是数组
函数
构造函数:用于初始化一个新创建的对象的函数
函数定义
两种定义方式及区别:
函数声明语句,可以在定义前使用(函数声明前置);不能出现在循环、条件、try/catch/finally、with 中
函数定义表达式,不能在定义前使用(变量声明前置);可以出现在任何地方
函数构造器
函数调用
四种调用方式:
作为函数:this 在非严格模式为全局对象,严格模式为 undefined
作为方法:this 为方法所属对象
作为构造函数:this 为新构造的对象
call()或者 apply()间接调用:this 为指定的对象
函数的实参与形参
不定实参函数:可以接收任意个数的实参,通过 arguments(类数组对象)接收参数
作为命名空间的函数
立即调用函数
(function(){
}())
闭包
词法作用域,函数内变量作用域是在函数定义时创建的,而不是在调用时创建,且在函数执行时,定义时的作用域链依然有效。函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存咋子函数作用域内,这种特性叫闭包。
函数属性、方法和构造函数
length 形参个数
arguments 参数对象(类数组对象)
prototype 指向原型对象
apply、bind、call
apply 将函数作为指定对象 thisObj 的方法来调用,传递给它的是指定的参数数组 args
function.apply(thisObj,args)
call 将函数作为指定对象 thisObj 的方法来调用,传递给它的是指定的参数, 如果 thisObj 为 null,则为全局对象
function.call(thisObj,arg1,arg2,…)
bing 返回一个新函数,通过可选的指定参数,作为指定对象 obj 的方法调用该方法,传递给该函数的参数由两部分组成,一部分是传递给 bind()的 args 数组指定的参数,剩下的是传给这个新函数的所有值。
传入 bind()的实参都是放在传入原始函数的实参列表开始的位置。
function.call(obj,arg1,arg2,…)
// 示例:
let g=f.bind(obj,1,2)
g(3)
// 等价于
f.call(obj,1,2,3)
toString
Function()构造函数,最后一个实参为函数体
函数式编程
高阶函数
操作函数的函数,接收一个或者多个函数作为参数,并返回一个函数。
不完全函数
传入 bind()的实参都是放在传入原始函数的实参列表开始的位置。
作用域
分类
全局
函数,块级(ES6+)
eval
作用域链
变量对象
用于存储执行上下文中的:
变量
函数声明
函数参数
1. 变量初始化阶段
2. 代码执行阶段
类和模块
特性:封装、继承、多态、抽象
类名使用大驼峰命名。ES6 直接使用 class,下面是 ES6 之前的。
构造函数和类的标识
原型对象是类的唯一标识:当切仅当两个对象继承自同一个原型对象时,它们才属于同一个类的实例。
construsctor
构造函数是类的公共标识,construsctor 属性为对象提供了类。
let 0= new F()
0.construsctor===F // => true
javascript 中的 java 式的类继承
创建一个类分为三步:
定义一个构造函数,并设置初始化新对象的实例属性
给构造函数的 prototype 对象定义实例方法
给构造函数定义类字段和类属性
类的扩充
javascript 中基于原型的继承机制是动态的,如果创建对象之后原型的属性发生变化,也会影响到继承这个原型的所有实例,即我们可以通过给原型对象添加方法来扩充 Javascript 类。
类和类型
instanceof:
obj instanceof c
obj.isPrototypeOf(f)
constructor:
x.constructor===Number
构造函数的名称
Object.prototype.toString.call(o)
注意:
前两种方法在多个执行上下文无效
这三种方法都有一个问题,就是不是所有对象都有 constructor 属性
鸭式辩型
Javascript 中的面向对象技术
标准转换方法
toString()
toLocaleString()
valueOf()
toJSON()
方法借用
Object.prototype.xxx=xxx
子类
方法链
构造函数链
正则表达式的匹配模式
定义
直接量
构造器
内容
直接量字符
字符类
重复
非贪婪重复在匹配字符后加一个? 即可。
选择、分组、引用
指定匹配位置
修饰符
String 方法
search
replace
match
split
RegExp 对象
属性:
source
global
ignoreCase
multiline
lastIndex
方法:
exec
test
javascript 的子集和扩展
迭代
迭代器
Iterator(), 返回迭代器
for(let [k,v] in Iterator({a:1,b:2}))
console.log(k+”=”+v) // a=1,b=2
特性:
只针对自有属性进行遍历,忽略继承属性
第二个参数传 true,则只遍历属性名。忽略值
数组推导 *
[expression for (varuable in object) if(conditon)]
函数简写
表达式闭包: 如果函数只计算一个表达式并返回它的值,关键字 return 和花括号可以省略
let succ=function(x)x+1
多 catch 从句
E4X
jsx 语法