基础
- 变量定义是绑定在所在的作用域对象下(?)
- 在 ECMAScript 中,变量可以存在两种类型的值,即原始值和引用值。原始值存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。引用值存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。
- 在许多语言中,字符串都被看作引用类型,而非原始类型,因为字符串的长度是可变的。ECMAScript 打破了这一传统。
- 引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。
- 内置类型
- JS 中分为七种内置类型,七种内置类型又分为两大类型:基本类型和对象(Object)。
- 基本类型有六种: null,undefined,boolean,number,string,symbol。
- JS 的数字类型是浮点类型的,没有整型。并且浮点类型基于 IEEE 754标准实现,在使用中会遇到某些 Bug。
- 对于基本类型来说,如果使用字面量的方式,那么这个变量只是个字面量,只有在必要的时候才会转换为对应的对象类型。
- 对象转基本类型
- 对象在转换基本类型时,首先会调用Symbol.toPrimitive(返回原始值的专用key)对应的函数,如果没有才会选择调用 valueOf 对应的函数,最后视强制转换类型决定是否调用toString。(这2个方法是可以重写的)。
- 当使用Symbol.toPrimitive对应的函数返回原始值时,
a + ''
这样的转换类型时Symbol.toPrimitive(hint){ hint !== 'string'}
(详情见Symbol.toPrimitive)
let a = {
valueOf() {
return 0;
},
[Symbol.toPrimitive]() {
return 2;
}
}
1 + a // => 3
'1' + a // => '12' // 先执行了对象转基本类型的Symbol.toPrimitive()方法。然后调用了数值2的toString方法转换为字符串
- 作用域链:包含自身变量对象和上级变量对象的列表
- 函数和变量提升:在生成执行上下文时,会有两个阶段。第一个阶段是创建的阶段(具体步骤是创建 VO),JS 解释器会找出需要提升的变量和函数,并且给他们提前在内存中开辟好空间,函数的话会将整个函数存入内存中,变量只声明并且赋值为 undefined,所以在第二个阶段,也就是代码执行阶段,我们可以直接提前使用。在提升的过程中,相同的函数会覆盖上一个函数,并且函数优先于变量提升
b() // call b second
function b() {
console.log('call b fist')
}
function b() {
console.log('call b second')
}
var b = 'Hello world'
- JS 解释器在遇到非匿名的立即执行函数时,会在函数内部创建一个辅助的作用域对象,然后将函数名称作为这个对象的属性指向该函数,因此函数内部才可以访问到 foo。但是这个值又是只读的,所以函数内对它的赋值并不生效,所以打印的结果还是这个函数,并且外部的值也没有发生更改。
var foo = 1
(function foo() {
foo = 10
console.log(foo)
}()) // -> ƒ foo() { foo = 10 ; console.log(foo) }
- 函数 A 返回了一个函数 B,并且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。
- 可以通过3种方式深度复制OBJ,依据适用对象从高到低排序 lodash函数,MessageChannel对象,JSON对象
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
标准对象
值属性:这些全局属性返回一个简单值,这些值没有自己的属性和方法。
Infinity
- 1/0
NaN
- NaN 不等于自身
- typeof NaN => "number"
undefined
- 除了null,undefined其他类型下标都有返回(可能是null或undefined),不会报错
- undefined 和 undefined 比较大小永远为false
- null或undefine时toString()会抛错
- undefined不是保留字,可以在一个函数上下文内以undefined做为变量名
let undefined = 1
,在低版本浏览器中甚至可以直接给winodw.undefined赋值
。使用void返回undefined字面量void 0 => undefined
null
- 除了null,undefined其他类型下标都有返回(可能是null或undefined),不会报错
- null或undefine时toString()会抛错
- typeof null => Object
函数属性:全局函数可以直接调用,不需要在调用时指定所属对象,执行结束后会将结果直接返回给调用者。
eval()
uneval()
isFinite()
isNaN()
parseFloat()
parseInt()
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
unescape()
基本对象
Object
- Object.keys(object)参数object可以为空对象,返回空数组
- 可以通过 Object.prototype.toString.call(xx)来判断类型。这样我们就可以获得类似 [object Type] 的字符串。
Function
Boolean
- 除了 undefined, null, false, NaN, '', 0, -0,其他所有值都转为 true,包括所有对象。
Symbol
- Symbol.toPrimitive对象的特定key,用来指向一个函数,这个函数用来定义如何返回这个对象的原始值。该函数接受一个参数表明需要转换成的数据类型,一共有以下2种可转换类型"number"、"string"。
var obj2 = {
[Symbol.toPrimitive](hint) {
if (hint == "number") {
return 10;
}
if (hint == "string") {
return "hello";
}
return true;
}
};
console.log(+obj2); // 10 -- hint is "number"
console.log(`${obj2}`); // "hello" -- hint is "string"
console.log(obj2 + ""); // "true" -- hint is "default"(缺省值)
Error
EvalError
InternalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
数字和日期对象
Number
- 期望值最好不要是数值型,数值型唯一的好处是可以直接进行计算。但是却有许多处理难点,例如‘0’的有值判断,浮点型的计算精度容易忘记转换,空值null后续操作抛错。建议用字符串代替
Math
Date
- 在ie9中
new Date(2018-09-01 00:00:00)
不能够被正确识别,需要改为new Date(2018,8,1,0,0,0);
date.setMonth(12)
会自动变为下一年1月date.setDate(0)
会变为上个月的最后一天
字符串
String
RegExp
可索引的集合对象
Array
- filter只会过滤数组组成新的数组,不会复制数组的内容。例如
let a=[{a:1},{a:2},{a:3}]
let b=a.filter(item=>{return item.a===1})
a[0]===b[0] // =>true
- arr.map(item=>{ })当arr为空数组时map不会被执行
- arr.sort((a,b)=>{ })中undefined 和 undefined 比较大小永远为false
- arr.sort((a,b)=>{ })当arr为空数组时不会执行
- arr.forEach(...)当arr为空数组时不会执行
- sort 在ie9中不支持
a>b
可写为a-b
Int8Array
Uint8Array
Uint8ClampedArray
Int16Array
Uint16Array
Int32Array
Uint32Array
Float32Array
Float64Array
使用键的集合对象:支持按照插入顺序来迭代元素
Map
Set
WeakMap
WeakSet
矢量集合:SIMD 矢量集合中的数据会被组织为一个数据序列(暂不整理)
结构化数据:这些对象用来表示和操作结构化的缓冲区数据,或使用 JSON 编码的数据。
ArrayBuffer
- 用来表示通用的、固定长度的原始二进制数据缓冲区
- ArrayBuffer 不能直接操作,而是要通过类型数组对象或 DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。
- 类型数组对象是web Api定义的对象(ArrayBufferView),包括下列构造函数生成的对象
- Int8Array();8位二进制带符号整数 -27~(27) - 1
- Uint8Array(); 8位无符号整数 0~(2^8) - 1
- Uint8ClampedArray();8位无符号整型固定数组
- Int16Array(); 16位二进制带符号整数 -215~(215)-1
- Uint16Array(); 16位无符号整数 0~(2^16) - 1
- Int32Array(); 32位二进制带符号整数 -231~(231)-1
- Uint32Array(); 32位无符号整数 0~(2^32) - 1
- Float32Array(); 32位IEEE浮点数
- Float64Array();64位IEEE浮点数
SharedArrayBuffer
Atomics
DataView
- DataView 视图是一个可以从 ArrayBuffer 对象中读写多种数值类型的底层接口,在读写时不用考虑平台字节序问题。(平台指操作系统,每个类型的操作系统对字节在保存时得处理不同,主要分为大端和小端)
var buffer = new ArrayBuffer(16);
var view1 = new DataView(buffer);
JSON
- JSON.parse(JSON.stringify(object))
- 会忽略 undefined
- 会忽略 symbol
- 不能序列化函数
- 不能解决循环引用的对象
let a = {
age: undefined,
sex: Symbol('male'),
jobs: function() {},
name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}
// 不能解决循环引用
let obj = {
a: 1,
b: {
c: 2
},
}
obj.c = obj.b
obj.b.c = obj.c
let newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj)
控制抽象对象
Promise
- promise的状态改变后,实际并不是固定的。当在then中运行的代码出错,抛出的错误,首先被catch捕获。
Generator
GeneratorFunction
AsyncFunction
反射?
Reflect
Proxy
国际化:为了支持多语言处理而加入ECMAScript的对象
Intl
Intl.Collator
Intl.DateTimeFormat
Intl.NumberFormat
WebAssembly ?
IWebAssembly
IWebAssembly.Module
IWebAssembly.Instance
IWebAssembly.Memory
IWebAssembly.Table
IWebAssembly.CompileError
IWebAssembly.LinkError
IWebAssembly.RuntimeError
其他
arguments
- arguments 是函数独有的对象(箭头函数没有)
- 该对象是一个伪数组,有
length
属性且可以通过下标访问元素 - 该对象中的
callee
属性代表函数本身 caller
属性代表函数的调用者
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
表达式和运算符
this
- 对象内的方法this指向对象本身,所以全局中this指向window
- 一个方法可以通过call,apply,bind方法改变执行它的对象,既改变this的值
- JavaScript 1.8.5 引入了 Function.prototype.bind() 方法,该方法允许显式地指定函数调用时 this 所指向的值 。该方法可以帮助你解决 this 指向不确定的问题。
let myArray = ['zero', 'one', 'two'];
myBoundMethod = (function (sProperty) {
console.log(arguments.length > 0 ? this[sProperty] : this);
}).bind(myArray);
function
- function 就是个语法糖,内部等同于 new Function()
new
- 对于创建一个对象来说,更推荐使用字面量的方式创建对象(无论性能上还是可读性)。因为你使用 new Object() 的方式创建对象需要通过作用域链一层层找到 Object,但是你使用字面量的方式就没这个问题。
let a = { b: 1 } // 这个字面量内部使用了 new Object()
-
生成对象的步骤
- 新生成了一个对象
- 链接到原型
- 绑定 this
- 返回新对象
-
new 表达式的优先级高于函数调用,但是低于对象方法访问
function Foo() {
return this;
}
Foo.getName = function () {
console.log('1');
};
Foo.prototype.getName = function () {
console.log('2');
};
new Foo.getName(); // -> 1 先执行了Foo.getName返回一个函数,然后执行new依据这个函数生成对象
new Foo().getName(); // -> 2 先执行了new Foo()生成一个对象,然后执行这个对象的getName方法
比较运算符
- == 比较逻辑有缺陷会出现
[] == ![] // -> true
和预期不符的情况,只使用===代替 - 如果是对象,先转换对象,然后再比较(转换对象参考对象转换为基本类型)
- 如果是字符串,就通过 unicode 字符索引来比较
- undefined 参与的比较永远为false
let a = {}
let b={}
a>b // false
a<b // false
a===b // false
四则运算符
- 只有当加法运算时,其中一方是字符串类型,就会把另一个也转为字符串类型。其他运算只要其中一方是数字,那么另一方就转为数字。加法运算会触发三种类型转换:将值转换为原始值,转换为数字,转换为字符串。
- 特殊
+ ‘1’ -> 1
引申出+ 'b' -> NaN
及'a' + + 'b' // -> "aNaN"
instanceof
- 用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置,可用于判定是否数组。所有都继承与Object
let a =[]
a instanceof Array // true
a instanceof Object // true
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
语句和声明
let
- let 不能在声明前使用
- let会为每次循环创建作用域变量,既每次循环中let的值是相互独立的
for ( let i=1; i<=5; i++) { // 这里的i在每次循环时都是独立的,所以可以实现打印,1,2,3,4,5如果使用var则会互相影响打印5个5
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
typeof
- typeof undefined // 'undefined'
- typeof b // b 没有声明,但是还会显示 undefined
- typeof 对于对象,除了函数都会显示 object
typeof console.log // 'function'
- 对于 null 来说,虽然它是基本类型,但是会显示 object,这是一个存在很久了的 Bug
typeof null // 'object'
// 在 JS 的最初版本中,使用的是 32 位系统,为了性能考虑使用低位存储了变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。虽然现在的内部类型判断代码已经改变了,但是对于这个 Bug 却是一直流传下来。 - 可以通过 Object.prototype.toString.call(xx)来判断类型。这样我们就可以获得类似 [object Type] 的字符串。
Object.prototype.toString.call([]) => "[object Array]"
void
- 无论void后的表达式是什么,void操作符都会返回undefined
void 0 => undefined
- 填充href、src使链接和图片无效
href="javascript:void(0)
。把a标签的href设为空字符串会导致点击时刷新整个页面,设置成javascript:void(0)则不会;把img的src设为空字符串可能会向服务器发起无效的get请求,而使用javascript:void(0)则不会 - 无论void右边的表达式是什么,都要对其求值。就是说可以用来运行一个表达式,但是表达式的结果不会影响返回,返回永远是undefined