JavaScript
1. 数据类型
按存储类型分类:(基本类型)
number
,string
,boolean
,undefined
,null
;(引用类型, 对象)Object
,Array
,Function
;typeof:
number
,string
,boolean
,undefined
,null(object)
,function
,array(object)
instanceof:
A.__proto__ === B.prototype
; 注意都是true:Object instanceof Function; Function instanceof Object; Function instanceof Function
Object.prototype.toString.call
相对有效比较稳的方法:
let class2type = {} 'Array Date RegExp Object Error'.split(' ').forEach(e => class2type[ '[object ' + e + ']' ] = e.toLowerCase()) function type(obj) { if (obj == null) return String(obj) return typeof obj === 'object' ? class2type[ Object.prototype.toString.call(obj) ] || 'object' : typeof obj }
2. new运算符的执行过程
例如:var a = new A();
创建一个新对象:
var obj = new Object(); obj.__proto__ = A.prototype;
将构造函数的作用域赋给新对象(因此this就指向了这个对象):
A.bind(obj)
执行构造函数中的代码(为这个新对象添加属性):
A()
返回新对象(如果构造函数有自己 retrun 时,则返回该值)
polyfill:
function New (f) { var n = { '__proto__': f.prototype }; //步骤1 return function () { f.apply(n, arguments); //步骤2和3 return n; //步骤4 }; }
3. this 关键字
常见用法
- 对象的方法调用,this指向对象
- 函数调用中的 this,严格模式是 window,非严格模式是 undefined
- 构造函数中的this,指向构造函数的实例化对象
三种显式改变this绑定
call:
fn.call(target, 1, 2)
apply:
fn.apply(target, [1, 2])
配合 arguments 很好用,内部会转换成 call,所以效率上call更快bind:
fn.bind(target)(1,2)
一般不立即执行的时候使用,bind 里面的 this 指向,不会被重写a.bind(b).call(c)
最终的 this 是 b应用:
- 获取数组中的最大值和最小值:
Math.max.apply(Math, numbers);
- 判断类型:
Object.prototype.toString.call(target)
- 数组里面的使用需要注意:
arr[0]()
等效arr.0.call(arr)
- 获取数组中的最大值和最小值:
this的绑定原则
- 严格模式下默认绑定的是
undefined
, 非严格模式 this 指向了 window 和 global - setTimeOut 这样在函数中以函数作为参数的,非严格模式下this指向全局对象
- 优先级:new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
fn(...args)
等效fn.call(window [ES5-strict: undefined], ...args)
箭头函数
箭头函数表达式的语法比函数表达式更短,并且不绑定自己的this,arguments,super或 new.target。这些函数表达式最适合用于非方法函数(non-method functions),并且它们不能用作构造函数。
没有
arguments
,使用rest
参数的形式访问没有构造函数,所以不能使用
new
没有原型
箭头函数中this直接指向的是调用函数的上一层运行时
一个特殊的对比
function test () { setTimeout(function () { console.log(this); }, 0) } test.call({a: 'this is obj'}) // Window function test () { (() => { console.log(this); })() } test.call({a: 'this is thisArg'}) // Object {a: 'this is thisArg'}
例子
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
}
};
obj.method(fn, 1);//输出是什么?
4. 数组方法(es6方法斜体)
通过Object.getOwnPropertyNames(Array.prototype)
得到浏览器支持方法
9个会改变自身值的方法,使用需谨慎:
pop
,push
,reverse
,shift
,sort
,splice
,unshift
,copyWithin
,fill
sort
:各大浏览器的算法不是统一的splice
:三个参数(起始下标、删除个数、添加元素),返回删除的项目数组集合
8个不会改变自身的方法:
concat
,join
,slice
,toString
,toLocateString
,indexOf
,lastIndexOf
,includes
,flat
,flatMap
concat, slice
:一般的数组拷贝可以使用它们,但是他们的集合里面如果有引用类型的对象,是不会复制的,只会继续引用includes
:相比indexOf
多一个查找NaN
的能力[NaN, 1].includes(NaN); [NaN, 1].indexOf(NaN)>-1; // true; false
flat
:多维数组拍平一维数组12个遍历的方法:
forEach
,every
,some
,filter
,map
,reduce
,reduceRight
,find
,findIndex
,entries
,keys
,values
forEach
:将为数组中每一项执行一次函数,那些已删除,新增或者从未赋值的项将被跳过(但不包括值为 undefined 的项)
some
:接收的方法返回true,后面的立即停止reduce
:接收的参数第一个为累加器方法,这个方法有四个参数(accumulator,currentValue, currentIndex, array自身);第二个为初始值 initialValue,如果有初始值,作为第一个accumulator值,否则accumulator 的值为数组第一个,currentIndex 从1开始;在没有初始值的空数组上调用 reduce 将报错
map
相比forEach
多了个返回值,如果遍历对象不是引用类型就不会影响元素组的值entries
,keys
,values
:涉及到迭代器
伪数组转换
- var arr = Array.prototype.slice.call(aLi)
- Array.from(arguments)
5. 深拷贝和浅拷贝
比较前还需要弄清除赋值,赋值
- 基本数据类型:赋值,赋值之后两个变量互不影响
- 引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有影响
简单来说可以理解为浅拷贝只解决了第一层的问题,拷贝第一层的基本类型值,以及第一层的引用类型地址。
浅拷贝的方法:
obj2 = Object.assign({}, obj);
obj2 = {...obj};
arr2 = arr.slice(0);
arr2 = arr.concat([])
深拷贝的方法:
JSON.parse(JSON.stringify(obj))
- 缺陷:
undefined
、symbol
和函数这三种情况,会直接忽略。- 循环引用情况下,会报错。
- 正则直接转对象了
- 缺陷:
lodash.cloneDeep()
6. 字符串方法
所有字符串方法都不会改变自身
操作:
slice
,substr
,substring
,trim
,toLowerCase
,toUpperCase
,toLocaleLowerCase
,toLocaleUppercase
,replace
,split
,toString
,valueOf
;查找比较:
charAt
,charCodeAt
,indexOf
,lastIndexOf
,search
,match
,localeCompare
,includes
html相关:
anchor
,link
,big
,blink
,bold
等支持正则高阶用法:
match
,search
,replace
,split
7. 正则
元字符
- 基本 --->
.
\
|
- 字符组 --->
[]
[^]
[-]
- 数量 --->
{m,n}
{m,}
{m}
+
*
?
| - 位置 --->
^
$
\b
\B
(?=p)
(?!p)
- 特殊 --->
\d
\D
\s
\S
\w
\W
- 标志 --->
g
i
m
- 基本 --->
简写
\d
(\D
) digit --->[0-9]
\w
(\W
) word --->[0-9a-zA-Z_]
\s
\S
space --->[\t\v\n\r\f]
.
--->[^\n\r\u2028\u2029]
?
--->{0,1}
+
--->{1, }
*
--->{0,}
惰性:数量相关的概念
- 默认贪婪
'aaaa'.match(/\w{2,5}/) // 'aaaa'
- 加上
?
转为惰性'aaaa'.match(/\w{2,5}?/) // 'aa'
- 默认贪婪
8. 模块化
CommonJS:
require/module.exports
浏览器没有那两个关键字不支持,只能在 node 中使用从它分裂出 AMD
Asynchronous Module Definition
规范(requireJS),可以作用在浏览器上基于它,CMD规范(seaJS),和 AMD 主要差别:AMD是一个依赖提前加载的概念,而CMD是同步执行,遇到require之后再执行当前的一个模块。两个都是单例模式。
ECMAScript6:
import/export
相关:JS MODULE 大战