数据类型
- 基本类型:Number Undefined Null Boolean String Symbol BigInt
- 引用类型:Object RegExp Date Function Array
- 基本类型按值访问,其值不可变,比较是值的比较,存放在栈
- 引用类型按引用访问,值可变,可以用于属性和方法,存放在栈和堆,栈保存变量标识符和指向堆的指针,比较是引用的比较
.
运算符提供了装箱操作,它会根据基本类型构造一个临时对象,使得能在基础类型上调用对应对象的方法。
null与undefined
null
是空指针,undefined
是变量未被初始化所赋予的值。没必要把变量赋值为undefined
但null
就可以。但null==undefined
总是返回true
。null
和undefined
没有toString
方法undefined
是一个变量而不是关键字,为了避免无意中被篡改,有的编程规范会要求用void 0
代替undefined
。现代浏览器中undefined
被设置成configurable
和writable
为false
。
String
String有最大长度253-1,对字符串的操作charAt
、charCodeAt
、length
等方法针对的都是UTF16编码,所以字符串的最大长度实际上是受字符串的编码长度影响的。0~65536(U+0000-U+FFFF)的码点被称为基本字符区域(BMP)。
Number
NaN占用了
9007199254740990
个数,这些原本是符合IEEE规则的数字。JavaScript中有
+0
和-0
,可以用1/x
是Infinity
还是-Infinity
来区分非整数的Number类型正确的比较方法是使用JavaScript提供的最小精度值
Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON();
Number整数类型的范围在-253-1~253-1之间,不含两个端点。
Number.MAX_SAFE_INTEGER
和Number.MIN_SAFE_INTEGER分别表示JavaScript中最大和最小的的安全整数:-253-1和253-1
类型转换
原值 |
Boolean |
Number |
String |
Object |
|
---|---|---|---|---|---|
Undefined |
undefined |
false |
NaN |
"undefined" |
|
Null |
null |
false |
0 |
"null" |
|
Boolean |
true |
1 |
"true" |
new Boolean(true) |
|
false |
0 |
"false" |
new Boolean(false) |
||
String |
"" |
false |
0 |
new String("") |
|
"123" |
true |
123 |
new String("123") |
||
"1a" |
treu |
NaN |
new String("1a") |
||
Number |
0 |
false |
"0" |
new Number(0) |
|
1 |
true |
"1" |
new Number(1) |
- 字符串到数字的类型转换支持十进制、二进制、八进制、十六进制以及正负号科学计数法:
- 30
- 0b111
- 0o13
- 0xFF
- 1e3
- -1e-2
- Number较大或较小时字符串会用科学计数法表示
ToPrimitive
函数式对象类型到基本类型的拆箱转换,对象到String
和Number
的转换会先将对象变成基本类型,再从基本类型转换为对应的String
和Number
。拆箱转换会尝试调用valueOf
和toString
来获得拆箱后的基本类型,没有这两个函数或者没有返回基本类型会产生TypeError
。Symbol.toPrimitive
可以覆盖原有的行为。一般情况下没有指定转换类型时,都会优先调用valueOf
,若返回的不是基本类型,则调用toString
。
数据类型判断
typeof
一元运算符,放在一个运算符之前,返回为一个字符串,其中基本类型的null
返回为object
对象,其他都返回基本类型,函数返回function
。缺点:不能检测数组和对象instanceof
可以判断一个变量是否是某个对象的实例,用来测试一个对象在其原型链中是否存在一个构造函数的prototype
属性。a instanceof Array
。
缺点:- 对基本数据类型,字面量方式创建出来的结果和实例方式创建有一定区别
console.log(1 instanceof Number)//false
console.log(new Number(1) instanceof Number)//true - 只要在当前实例的原型链上,用其检测出来的结果都是true。在类的原型继承中,检测出的结果未必准确
- 不能检测
null
和undefined
- 对基本数据类型,字面量方式创建出来的结果和实例方式创建有一定区别
constructor
返回对创建此对象的数组函数的引用,与instanceof
相似,还可以处理基本数据类型的检测。a.constructor == Array
缺点:- 不能检测
null
和undefined
- 函数的
constructor
是不稳定的,类的原型重写时可能会把之前的constructor
覆盖function Fn(){}
Fn.prototype = new Array()
var f = new Fn
console.log(f.constructor)//Array
- 不能检测
Object.prototype.toString.call
function isArray(o) {
return Object.prototype.toString.call(o) === '[object Array]';
}Object.prototype.toString()
获取对象的类名然后将[object 类名]
组合并返回,既解决了instanceof
存在的跨页面问题,也解决了属性检测方式所存在的问题ES6新增Array.isArray()
特性判断
function isArray(object){
return object && typeof object==='object' &&
typeof object.length==='number' &&
typeof object.splice==='function' &&
//判断length属性是否是可枚举的 对于数组 将得到false
!(object.propertyIsEnumerable('length'));
}有
length
和splice
不一定是数组,但是length
不能枚举便可以判断其不是对象的属性
object.propertyIsEnumerable(proName)
判断指定的属性是否可列举
数据类型相等判断
var toString = Object.prototype.toString; |
数组方法
map:将调用的数组的每个元素传递给指定的函数,并返回一个数组。
const arr = [1, 2, 3, 4, 5, 6];
const mapped = arr.map(el => el + 20);
console.log(mapped);// [21, 22, 23, 24, 25, 26]filter:返回的数组元素是函数逻辑为真的一个子集。
const arr = [1, 2, 3, 4, 5, 6];
const filtered = arr.filter(el => el === 2 || el === 4);
console.log(filtered);// [2, 4]reduce:按函数方法计算值。
const arr = [1, 2, 3, 4, 5, 6];
const reduced = arr.reduce((total, current) => total + current);
console.log(reduced);// 21find, findIndex, indexOf, push, pop
shift:从数组头部删除一个元素,它改变了原数组。函数本身返回被删除元素的值。
let arr = [1, 2, 3, 4];
const shifted = arr.shift();
console.log(arr);// [2, 3, 4]
console.log(shifted);// 1unshift:在数组头≠部添加一个或多个元素,它改变了原数组。与其他很多方法不同的是,函数本身返回数组新的长度。
let arr = [1, 2, 3, 4];
const unshifted = arr.unshift(5, 6, 7);
console.log(arr);// [5, 6, 7, 1, 2, 3, 4]
console.log(unshifted);// 7
call和apply
相同点:作用相同,第一个参数都为执行时的上下文对象
不同点:接收参数的方式不同,对于
call
,传递给函数的参数必须逐个列举出来;对于apply
时,传递给函数的是参数数组。例子如下:function add(c, d){
return this.a + this.b + c + d;
}
var o = {a:1, b:3};
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34深拷贝和浅拷贝
JSON.stringifyJSON.parse
可以实现,但是会丢失undefinedfunction
和symbol
类型的属性数组的
slice
和concat
可以实现一级属性的拷贝,但是二级及以上的属性不能深拷贝递归函数实现
多个节点插入DOM
多个节点插入DOM时,由于渲染回流,在for循环内部多次appendChild
会造成多次渲染,从而出现卡、闪屏的现象。javascript提供了一个文档片段DocumentFragment
的机制。如果将文档中的节点添加到文档片段中,就会从文档树中移除该节点。把所有要构造的节点都放在文档片段中执行,这样可以不影响文档树,也就不会造成页面渲染。当节点都构造完成后,再将文档片段对象添加到页面中,这时所有的节点都会一次性渲染出来,这样就能减少浏览器负担,提高页面渲染速度。
var fragment = document.createDocumentFragment(); |
参考文章