# 2021-02
# 数组栈方法
栈是一种后进先出(LIFO, Last-In-First-Out)的结构。
- push()方法接受任意数量的参数,并将他们添加在数组末尾,返回数组的最新长度
- pop()方法则是用删除数组的最后一项,同时减少数组的length值,返回被删除的项
let colors = new Array();
let count = colors.push("red", "green") //这里返回数组的最新长度
console.log(count)//2
count = colors.push("black");
console.log(count)//3
//
let item = colors.pop();
console.log(item) // black
console.log(colors.length) // 2
# 数组队列方法
队列以先进先出(FIFO, First-In-First-Out)形式限制访问。
- shift()方法删除数组的第一项并返回它,然后数组长度减1。
- unshift()方法在数组开头添加任意多个值,然后返回新的数组长度。
# 数组排序
- reverse()方法将数组反向排列
- sort()方法会按照升序重新排列数组元素。(会把数组元素转换为字符串在比较)。sort()方法接受一个比较函数用于判断哪个值应该排在前面。
- reserve()和sort()都返回调用它们数组的引用
# 数组操作方法
- concat()方法可以在现有数组全部元素的基础上创建一个新的数组。
- slice()方法创建一个包含原有数组一个和多个元素的新数组。
- splice()方法可以操作删除、插入、替换。返回一个数组,它包含从数组中被删除的元素(如果没有删除,则返回空数组)。
# 数组搜索和位置方法
- 严格相等
indexOf()、lastIndexOf()和includes()(ES7)方法接受两个参数:要查找的元素和一个可选的其实搜索位置。
indexOf()和includes()方法从数组前头开始向后搜索,而lastIndexOf()从数组末尾开始向前搜索。
indexOf()和lastIndexOf()都返回要茶轴的元素在数组的位置,如果没有查到则返回-1。includes()返回布尔值。表示至少找到一个与指定元素匹配的项。
let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
console.log(numbers.indexOf(2)) //2
console.log(numbers.lastIndexOf(2)) //7
console.log(numbers.includes(2)) // true
- 断言函数(ES6)
ECMAScript 也许按照定义的断言函数搜索数组,每个索引都会调用这个函数。断言函数的返回值决定了响应索引的元素是否被认为匹配。
const people = [
{
name: "Matt",
age: 27
},
{
name: "Nicholas",
age: 29
}
];
let aa = people.find((element, index, array) => element.age < 28)
let bb = people.findIndex((element, index, array) => element.age < 28)
console.log(aa) // { name: 'Matt', age: 27 }
console.log(bb) //0
# 归并方法
reduce()和reduceRight()
# bind理解和手写原生实现
Function.prototype.bind()
bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()中的第一个参数的值,例如:f.bind(obj),实际上可以理解为obj.f(),这时f函数体内的this自然指向的是obj。
//例子 1:
var a = {
b: function () {
var func = function () {
console.log(this.c);
}
func();
},
c: 'hello'
}
a.b(); //undefined
console.log(a.c); // hello
因为fun()这个函数执行的时候他的函数上下文为window,而a.b()的这个函数的执行的时候函数上下文this为a对象。
//改变this的值
var a = {
b: function () {
var that = this; // 通过赋值的方式将this赋值给that
var func = function () {
console.log(that.c);
}
func();
},
c: 'hello'
}
a.b(); // hello
// 使用bind方法一
var a = {
b: function () {
var func = function () {
console.log(this.c);
}.bind(this);
func();
},
c: 'hello'
}
a.b(); // hello
console.log(a.c); // hello
// 使用bind方法二
var a = {
b: function () {
var func = function () {
console.log(this.c);
}
func.bind(this)();
},
c: 'hello'
}
a.b(); // hello
console.log(a.c); // hello
这里我们以a.b()的形式去执行a对象中的b这个函数,是经过对象a的所以当我们来执行a对象中b函数的时候找this就会先找到a对象所以在a对象中的b这个函数中的this为a对象,所以这个时候bind,绑定的this也就是为a对象了。
# bind()的原生实现分步解析
- 通过call把arguments生成一个真正的数组
Array.prototype.slice.call(arguments) //是用来将参数由数组转换为真正的数组
[].slice.call(arguments) //是用来将参数由数组转换为真正的数组
上面两种方法的结果一样
解析:arguments是一个类数组(对象)它没有slice的方法,通过上面的Array.prototype.slice写法可以它添加slice的方法
slice()没参数默认从0到最后一项,浅拷贝,不影响原数组
因为arguments也是一个对象,就相当于在arguments中执行了slice()函数,name不要参数的情况下是根据key下标会返回一个完整的数组从而达到生成了一个新的数组效果,arguments对象中是有length属性和0,1,2这样的属性,而slice会根据key(属性值)生成一个数组
# RegExp
- 使用RegExp可以基于已有的正则表达式实例,并可选择性的修改它们的标记。
const re1 = /cat/g;
console.log(re1); // "/cat/g"
const re2 = new RegExp(re1);
console.log(re2); // "/cat/g"
const re3 = new RegExp(re1, "i");
console.log(re3); // "/cat/i"
# [].slice与Array.prototype.slice区别
- [].slice实际上是先创建一个Array的实例[],然后调用这个实例[]上的slice方法,而这个方法是Array的prototype上的,也就是Array.prototype.slice
- 这两种调用的不同之处,就是this的指向不同。在[].slice()中,this指向的是改实例[],而在Array.prototype.slice中,this指向的是Array.prototype
# object
- 在对象字面量表示法中,属性名可以是字符串或数值比如:
let person = {
"name": "nichelol",
"age": 29,
5: true
}
//{ '5': true, name: 'nichelol', age: 29 }
注意,数值属性会自动转换为字符串
- 在使用数组字面量表示法创建数组不会调用Array构造函数,与对象一样。
- Array.of()可以把一组参数转换为数组。这个方法用于代替ES6之前常用的Array.prototype.slice.call(arguments),一种异常笨拙的将arguments对象转换为数组的写法
# Event loop(浏览器)
- HTML5标准规定setTimeout的第二个参数不得小于4毫秒,不足自动增加。
- ES6规定中,microtask称为jobs,macrotask称为task。
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
new Promise((resolve) => {
console.log('Promise')
resolve()
}).then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
// script start => Promise => script end => promise1 => promise2 => setTimeout
微任务包括:process.nextTick,promise,Object.observe,MutationObserver
宏认为包括:script,setTimeout,setInterval,setImmediate,I/O,UI rendering
很对人有个误区,认为微任务快于宏任务,其实是错误的。因为宏任务中包含了script,浏览器会先执行一个宏任务,接下来有异步的话就先执行微任务。
所以正确的一次Event loop顺序是这样的
1、执行同步代码,这属于宏任务
2、执行栈为空,查询是否有微任务需要执行
3、执行所有微任务
4、必要的话渲染UI
5、然后开始下一轮Event loop,执行宏任务中的异步代码