原始值(直接表示在语言底层的不可变数据)
- 布尔类型
- Null 类型
- Undefined 类型
- 数字类型
- BigInt 类型
- 字符串类型
- 符号类型
对象(一组属性的集合)(引用类型)
- “标准的”对象 一个 JavaScript 对象就是键和值之间的映射。键是一个字符串(或者 Symbol),值可以是任意类型的。这使得对象非常符合哈希表。
- 函数是一个附带可被调用功能的常规对象。
- 日期
- 有序集:数组和类型数组
- 带键的集合:Maps, Sets, WeakMaps, WeakSets
- 结构化数据:JSON
- 基本包装类型(Boolean、Number 和String)
- 单体内置对象(Global、Math) JavaScript 标准内置对象 错误对象 控制抽象对象(Promise/Generator/GeneratorFunction/AsyncFunction) 反射 国际化 WebAssembly 其他(arguments)
Boolean包装对象
var test=new Boolean();
console.log(test);
var test=new Boolean(0);
console.log(test);
var test=new Boolean(null);
console.log(test);
var test=new Boolean("");
console.log(test);
var test=new Boolean(NaN);
console.log(test);
- 没有内容就是undefined,这个就是false
- 0就是false,1是true
- null跟undefined一样,都是false
- 字符串里面有内容的话才是true,没有内容就是false
- NaN是一种数值类型,已经是false了,只是为了让程序继续往下面走
- 其他解析: 数值只要不是0,都是true 对象object永远都是true
typeof null // "object"而不是"null" 这个bug是第一版Javascript留下来的。 在这个版本,数值是以32字节存储的,由标志位(1~3个字节)和数值组成。 标志位存储的是低位的数据。这里有五种标志位: 000:对象,数据是对象的应用。 1:整型,数据是31位带符号整数。 010:双精度类型,数据是双精度数字。 100:字符串,数据是字符串。 110:布尔类型,数据是布尔值。
Math.ceil 天花板向上取整 Math.floor 地板向下取整 Math.round 附近四舍五入取整
介绍
- 字符串(string)是一组由16位值组成的不可变的有序序列, 每个字符通常来自于Unicode字符集,JavaScript字符串的索引从零开始。 在JavaScript程序中的字符串直接量,是由单引号或双引号包括起来的字符序列。 在ECMAScript3中,字符串直接量必须写在一行中, 而在ECMAScript5中,字符串直接量可以拆分成数行, 但每行必须以反斜线结束,反斜线和行结束符都不算是字符串直接量的内容。
- 在ES5中,字符串可以当做只读数组,除了使用charAt()方法, 也可以使用方括号来访问字符串中的单个字符
js中字符串连接方式较为高效的方法 +的处理机制是: 一个临时字符串, 将新字符串赋值为a+b, 然后返回这个临新字符串并同时销毁原始字符串, 所以字符串连接效率较低。 所以用Array.join()不会新建临时字符串效率更高。 (当然以上效率问题仅存在于低版本浏览器ie7-及以下, 现在的新浏览器基本上都解决了这个问题,效率差不多)
判断字符串中是否包含某个字符串 String对象的方法
- indexOf
- includes
- search。search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。如果没有找到任何匹配的子串,则返回 -1。
- match。match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。 RegExp 对象方法
- test。test() 方法用于检索字符串中指定的值。返回 true 或 false。
- exec() 方法用于检索字符串中的正则表达式的匹配。返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回值为 null。
介绍 Symbol是ES6新增的一种数据类型,表示独一无二的值,Symbol最大的用途是用来定义对象的唯一属性名。ES5的对象属性名都是字符串,容易造成属性名的冲突。如果使用了一个他人提供的对象,但又想为期添加新的方法,那么新方法的名字有可能与已有方法产生冲突。因此,需要保证每个属性的名字都是独一无二的,以防止属性名的冲突。这就是ES6引入Symbol的原因。
介绍 原始类型存储的是值, 对象类型存储的是地址(指针) 他们都是栈内存 指针指向的是堆内存
一般来说 栈和堆的分配是指 C 或 C++ 编译的程序 通常有这几部分组成: 1、栈区(stack) 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等 2、堆区(heap)一般由程序员分配释放,使用 malloc 或 new 等 3、全局区(静态区)(static) 4、常量区 5、程序代码区
但是由于JS脚本引擎是一种由 C 或 C++ 开发的“应用” 而且这种脚本“应用”并不再经过 C/C++ 编译器编译 所以这种“应用”内变量所处位置并不好说
因为这些变量可能只是 C 或 C++ 内结构体或者某种Script类型实例后结果 那么就可能是指的存放在堆区的
但是呢,具体怎么做取决与不同引擎的实现方式 当然,如果有 JIT 的 可推导出某Script内局部变量\参数为 C/C++内某种具体值类型的话 可能还是会放置在栈区的吧 其实写JS的应该压根不关心这个(这种层面上的栈/堆)
作者:貘吃馍香 链接:https://www.zhihu.com/question/42231657/answer/102552732
介绍 数组最多可以包含 4 294 967 295 个项(2的32次方 无符号整形最大值)
原生具备 Iterator 接口的数据结构
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
循环数组中的空位 ES5forEach(), filter(), reduce(), every() 和some()都会跳过空位。 map()会跳过空位,但会保留这个值 join()和toString()会将空位视为undefined,而undefined和null会被处理成空字符串。
创建数组 1.使用 Array 构造函数。
var colors = new Array(20); // 创建 length 值为 20 的数组
var colors = new Array("red", "blue", "green"); // 创建了一个包含 3 个字符串值的数组
在使用 Array 构造函数时也可以省略 new 操作符
2.使用数组字面量表示法
var values = [1,2,]; // 不要这样!这样会创建一个包含 2 或 3 项的数组
在 IE 中,values 会成为一个包含 3 个项且每项的值分别为 1、2 和 undefined 的数组; 在其他浏览器中,values 会成为一个包含 2 项且值分别为1 和 2 的数组。 原因是 IE8 及之前版本中的 ECMAScript 实现在数组字面量方面存在 bug。
3.将集合A转化为数组
Array.from
Array.from(arr, mapfn,thisArg)方法,
用于将两类可以把对象转换为真正的数组:
类似数组的对象
可遍历的对象(部署了Iterator接口的,String,ES6新增的Map和Set)。
可以传3个参数,
其中第一个是数组,必传;
第二个是一个函数(类似map函数),对数组元素进行操作后再返回数组,可选;
第三个是对于this关键字的指向,可选。
[].slice.apply(A)
slice() 方法可从已有的数组中返回选定的元素(新数组)
[…A]
[].map.call(A, o => o)
遍历 forEach、every、some、filter、map、reduce、reduceRight 以及ES6新增的方法entries、find、findIndex、keys、values
操作 改变自身值的方法 pop、push、reverse、shift、sort、splice、unshift,以及两个ES6新增的方法copyWithin 和 fill
push
、pop
和unshift
、shift
。改变原数组,push
、pop
是从数组的尾部进行增减,unshift
、shift
是从数组的头部进行增减,push
和unshift
向数组的尾部/头部添加若干元素,并返回数组的新长度。pop
和shift
从数组的尾部/头部删除1个元素(删且只删除1个),并返回被删除的元素;空数组是继续删除,不报错,但返回undefined。splice
。绞接,改变原数组,如果需要删除数组中一个已存在的元素,可参考如下array.splice(array.indexOf('b'),1)
slice
。切, 不改变原数组,返回选定数组(新的数组对象)。concat
。将数组和(或)值连接成新数组,不改变原数组,返回新数组。join
。将数组变成字符串,不改变原数组,返回字符串。sort
。对数组进行排序,改变原数组,返回排序后的新数组。升序arr.sort((a, b) => { return a - b })
。v8引擎为了高效排序(采用了不稳定排序)。即数组长度超过10条时,会调用另一种排序方法(快速排序);而10条及以下采用的是插入排序,此时结果将是稳定的。https://juejin.cn/post/6844903476216987655toString
。将数组中的元素用逗号拼接成字符串,不改变原数组,返回拼接后的字符串reverse
。反转数组,改变原数组,返回反转后的新数组
不会改变自身的方法 concat、join、slice、toString、toLocateString、indexOf、lastIndexOf、未标准的toSource以及ES7新增的方法includes
indexOf
。 从索引为0开始,检查数组中是否包含有value,有则返回匹配到的第一个索引,没有则返回-1lastIndexOf
。从最后的索引开始,检查数组找那个是否包含value,有则返回匹配到的第一个索引,没有返回-1includes
。包含则返回 true,否则返回false
Array.prototype Array.prototype的所有方法 由于 Array.prototype 的某些属性被设置为[[DontEnum]],因此不能用一般的方法进行遍历 我们可以通过如下方式获取 Array.prototype 的所有方法
Object.getOwnPropertyNames(Array.prototype); // ['length', 'constructor', 'concat', 'copyWithin', 'fill', 'find', 'findIndex', 'lastIndexOf', 'pop', 'push', 'reverse', 'shift', 'unshift', 'slice', 'sort', 'splice', 'includes', 'indexOf', 'join', 'keys', 'entries', 'values', 'forEach', 'filter', 'flat', 'flatMap', 'map', 'every', 'some', 'reduce', 'reduceRight', 'toLocaleString', 'toString', 'at', 'findLast', 'findLastIndex'] // Edge 102
Array
Array.isArray
。判断一个变量是否数组类型。es5可用Object.prototype.toString.call(arg) === '[object Array]'
。Array.of
。基本上与Array构造器功能一致, 唯一的区别就在单个数字参数的处理上Array.from
。一个对象有迭代器,Array.from就能把它变成一个数组(返回新的数组,不改变原对象)
克隆数组 es6扩展运算符
const _arr = [0, 1, 2];
const arr = [..._arr];
合并数组 es6扩展运算符
const arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];
const arr = [...arr1, ...arr2];
去重数组 es6 set
const arr = [...new Set([0, 1, 1, null, null])];
// arr => [0, 1, null]
清空数组
arr.length = 0
过滤空值
const arr = [undefined, null, "", 0, false, NaN, 1, 2].filter(Boolean);
数组首部插入成员
arr.unshift(0);
arr = [0].concat(arr);
arr = [0, ...arr];
数组尾部插入成员
arr.push(2);
arr.concat(2);
arr[arr.length] = 2;
arr = [...arr, 2];
统计数组成员个数
const arr = [0, 1, 1, 2, 2, 2];
const count = arr.reduce((t, c) => {
t[c] = t[c] ? ++ t[c] : 1;
return t;
}, {});
// count => { 0: 1, 1: 2, 2: 3 }
解构数组成员别名
const arr = [0, 1, 2];
const { 0: a, 1: b, 2: c } = arr;
// a b c => 0 1 2
解构数组成员默认值
const arr = [0, 1, 2];
const [a, b, c = 3, d = 4] = arr;
// a b c d => 0 1 2 4
并集,交集和差集 ES7 includes
// 并集
let union = a.concat(b.filter(v => !a.includes(v))) // [1,2,3,4,5]
// 交集
let intersection = a.filter(v => b.includes(v)) // [2]
// 差集
let difference = a.concat(b).filter(v => a.includes(v) && !b.includes(v))
ES6 Array.from Set
let aSet = new Set(a)
let bSet = new Set(b)
// 并集
let union = Array.from(new Set(a.concat(b))) // [1,2,3,4,5]
// 交集
let intersection = Array.from(new Set(a.filter(v => bSet.has(v)))// [2]
// 差集
let differenceNew = Array.from(new Set(a.concat(b).filter(v => aSet.has(v) && !bSet.has(v))) [1,3]
ES5 filter indexOf(indexOf方法中NaN永远返回-1) 不考虑NaN
// 并集
var union = a.concat(b.filter(function(v) {
return a.indexOf(v) === -1})) // [1,2,3,4,5]
// 交集
var intersection = a.filter(function(v){ return b.indexOf(v) > -1 }) // [2]
// 差集
var difference = a.filter(function(v){ return b.indexOf(v) === -1 })// [1,3]
考虑NaN
var a = [1, 2, 3, NaN];
var b = [2, 4, 5];
var aHasNaN = a.some(function (v) {
return isNaN(v)
})
var bHasNaN = b.some(function (v) {
return isNaN(v)
})
// 并集
var union = a.concat(b.filter(function (v) {
return a.indexOf(v) === -1 && !isNaN(v)
})).concat(!aHasNaN & bHasNaN ? [NaN] : []) // [1,2,3,4,5,NaN]
// 交集
var intersection = a.filter(function (v) {
return b.indexOf(v) > -1
}).concat(aHasNaN & bHasNaN ? [NaN] : []) // [2]
// 差集
var difference = a.filter(function (v) {
return b.indexOf(v) === -1 && !isNaN(v)
}).concat(aHasNaN && !bHasNaN ? [NaN] : [])//1,3,NaN
console.log(union)
console.log(intersection)
console.log(difference
介绍 ECMAScript 中的 Date 类型是在早期 Java 中的 java.util.Date 类基础上构建的。为此,Date 类型使用自 UTC(Coordinated Universal Time,国际协调时间)1970 年 1 月 1 日午夜(零时)开始经过 的毫秒数来保存日期。在使用这种数据存储格式的条件下,Date 类型保存的日期能够精确到 1970 年 1 月 1 日之前或之后的 285 616 年。
介绍 ECMAScript 通过 RegExp 类型来支持正则表达式。使用下面类似 Perl 的语法,就可以创建一个正则表达式。
var expression = / pattern / flags ;
其中的模式(pattern)部分可以是任何简单或复杂的正则表达式,可以包含字符类、限定符、分组、
向前查找以及反向引用。每个正则表达式都可带有一或多个标志(flags),用以标明正则表达式的行为。
正则表达式的匹配模式支持下列 3 个标志。
g
:表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即
停止;
i
:表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写;
m
:表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模
式匹配的项。
Object()
Object.prototype.valueOf.call()
可以把一个原始值转换成对象,但是这个方法名太长了。
Object()
当Object被作为一个普通函数(而非构造函数)调用时,它的作用是 类型转换 转换成对象
。
在Object的所有子类型中,valueOf()
方法是将包装对象转换为原始值(正好和上述描述相反),
例 String.prototype.valueOf.call("abc")
对象添加getter与setter 1.字面值创建对象时声明get和set
var o = {
a : 7,
get b(){return this.a +1;},
set c(x){this.a = x/2}
};
2.Object.create() 方法创建一个拥有指定原型和若干个指定属性的对象,指定属性中加get和set 3.Object.defineProperty 4.Object.defineProperties 5.Object.prototype.defineGetter 以及 Object.prototype.defineSetter , 非标准方法。
对象属性遍历
1.for (let i in obj)
自身和原型
可以枚举属性
for循环出key
2.Object.keys()
自身
可枚举属性
返回key数组
Object.values()
返回value数组
Object.entries()
返回下标0是key、下标1是value的数组的数组
3.Object.getOwnPropertyNames
自身
所有属性 不包括Symbol
返回key数组
4.反射 Reflect.ownKeys
获取自身所有属性名称,包括不可枚举属性,Symbol
其实就是 Object.getOwnPropertyNames
与 Object.getOwnPropertySymbols
之和
对象属性的顺序 在ES5和早期标准中,没有指定属性的顺序 从ES6开始(Object.getOwnPropertyNames,Reflect.ownKeys),属性的顺序是基于一个特殊的规则的 数字:当属性的类型时数字类型时, 会按照数字的从大到小的顺序进行排序; 字符串:当属性的类型是字符串时, 会按照时间的先后顺序进行排序; Symbol:当属性的类型是Symbol时, 会按照时间的先后顺序进行排序。
深浅拷贝
浅拷贝: 只对第一层键值对进行独立的复制
for in
/ Object.keys
/ 展开运算符 ...
/ Object.assign
深拷贝
对于 == 来说,如果对比双方的类型不一样的话,就会进行类型转换
判断流程 首先会判断两者类型是否相同。相同的话就是比大小了 类型不相同的话,那么就会进行类型转换
- 会先判断是否在对比 null 和 undefined,是的话就会返回 true
- 判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。1 == '1' -> 1 == 1
- 判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。'1' == true -> '1' == 1 -> 1 == 1
- 判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。'1' == { name: 'yck' } -> '1' == '[object Object]'
对于 === 来说就简单多了,就是判断两者类型和值是否相同
NaN和任何比都是false
Object.is(valueA,valueB)
以与严格相等运算符相同的方式检查相等性的参数,但有两个区别。
首先,NaN
等于另一个 NaN
值:
Object.is(NaN, NaN); // => true
Object.is(NaN, 1); // => false
其次,Object.is()
区分 -0
和 +0
:
Object.is(-0, +0); // => false
typeof 对于原始类型来说,除了 null 都可以显示正确的类型 typeof 对于对象来说,除了函数都会显示 object
instanceof内部机制是通过原型链来判断的 instanceof不能判断原始类型
Object.prototype.toString.call() Array 、Function等类型作为Object的实例,都重写了toString方法,不能直接用
在 JS 中类型转换只有三种情况
- 转换为布尔值
- 转换为数字
- 转换为字符串
转Boolean 在条件判断时,除了 undefined,null, false, NaN, '', 0, -0,其他所有值都转为 true,包括所有对象
四则运算符 运算中,+号,数字隐式转换成字符串。其余的运算符号是字符串隐式转换成数字。
4 * '3' // 12
4 * [] // 0
4 * [1, 2] // NaN
以下分析+号
运算中其中一方为字符串,那么就会把另一方也转换为字符串 如果有一个操作数是对象、数值或布尔值,则调用它们的 toString()方法取得相应的字符串值, 然后再应用前面关于字符串的规则。对于 undefined 和 null,则分别调用 String()函数并取得字符串"undefined"和"null"
[] + {} // "[object Object]"
{} + {} // "[object Object][object Object]"
当[]遇上加号时有点古怪(加号会把空字符串转为0)
{} + [] // 0
[] + [] // ""
String([]) // ""
+String([]) // 0
另外对于加法还需要注意这个表达式 'a' + + 'b' // -> "aNaN"
比较运算符 如果是对象,对象可以用toPrimitive转换成原始类型 Symbol.toPrimitive 如果是字符串,就通过 unicode 字符索引来比较