# 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,执行宏任务中的异步代码

Last Updated: 3/3/2021, 4:19:06 PM