算法以前

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战javascript

image.png

数据结构与算法的关系

  • 数据结构:计算机存储,组织数据的方式,就像锅碗瓢盆。
  • 算法:一系列解决问题的清晰指令,就像食谱。
  • 程序 = 数据结构 + 算法
  • 数据结构为算法提供服务,算法围绕数据结构操做。

数据结构分类

  • 有序:栈,队列,链表
  • 无序:集合,字典
  • 节点关联性:树,堆,图

时间 / 空间复杂度

image.png

数学知识

log2

在数学中,对数是对求幂的逆运算,正如除法是乘法的逆运算,反之亦然。 [6] 这意味着一个数字的对数是必须产生另外一个固定数字(基数)的指数。 在简单的状况下,乘数中的对数计数因子。更通常来讲,乘幂容许将任何正实数提升到任何实际功率,老是产生正的结果,所以能够对于b不等于1的任何两个正实数b和x计算对数。若是a的x次方等于N(a>0,且a≠1),那么数x叫作以a为底N的对数(logarithm),记做x=loga N。其中,a叫作对数的底数,N叫作真数。 [1]前端

矩阵

在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合 [1] ,最先来自于方程组的系数及常数所构成的方阵。这一律念由19世纪英国数学家凯利首先提出。java

对应在前端领域,是咱们的多维数组,和双重for循环node

时间复杂度

在计算机科学中,时间复杂性,又称时间复杂度,算法的时间复杂度是一个函数,它定性描述该算法的运行时间。这是一个表明算法输入值的字符串的长度的函数。时间复杂度经常使用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的状况。web

一个算法花费的时间与算法中语句的执行次数成正比例,哪一个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。正则表达式

function traverse(arr) {
    var n = arr.length;   		// 执行1次
    for(var i=0;i<n;i++) {		// var i = 0; 执行1次 | i < n 执行n次 | i++ 执行 n+1次
        console.log(arr[i])		// 执行n次
    }
}
复制代码

执行次数:1 + 1 + n + (n + 1) + n = 3n + 3算法

通常状况下,算法中基本操做重复执行的次数是问题规模n的某个函数,用T(n)表示,如有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f (n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记做T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。编程

时间复杂度计算:基于n趋向于无限大,3n + 3在n趋向于无限大的时候,3n + 3趋向于n。因此这里的时间复杂度为O(n)。数组

空间复杂度

空间复杂度(Space Complexity)是对一个算法在运行过程当中临时占用存储空间大小的量度,记作S(n)=O(f(n))。好比直接插入排序的时间复杂度是O(n^2),空间复杂度是O(1) 。而通常的递归算法就要有O(n)的空间复杂度了,由于每次递归都要存储返回信息。一个算法的优劣主要从算法的执行时间和所须要占用的存储空间两个方面衡量。markdown

一个算法的空间复杂度只考虑在运行过程当中为局部变量分配的存储空间的大小,它包括为参数表中形参变量分配的存储空间和为在函数体中定义的局部变量分配的存储空间两个部分。

function traverse(arr) {
    var n = arr.length;   		// n占用1空间
    for(var i=0;i<n;i++) {		// arr占用n空间
        console.log(arr[i])		// i占用1空间
    }
}
复制代码

空间复杂度为O(n)。

数据结构简介

数组

js原生支持的数据结构

const array = [1, 2, 3, 4, 5];
复制代码

队列

栈是一种先进先出(FIFO,First In First Out)的数据结构。 先进先出,js数组支持,限定使用方法:头部弹出元素【shift】,尾部新增元素【push】

const array = [1, 2, 3, 4, 5];

array.push(6)
array.shift();

console.log(array);  // [2, 3, 4, 5, 6]
复制代码

栈是一种后进先出(LIFO,Last In First Out)的数据结构。 后进先出,js数组支持,限定使用方法:尾部弹出元素【pop】,尾部新增元素【push】

const array = [1, 2, 3, 4, 5];

array.push(6);
array.pop()

console.log(array);   // [1, 2, 3, 4, 5]
复制代码

链表

多个元素组成的列表 元素存储不连续,经过next指针链接一块儿。

var node1Item =  {
	value: 'value',
  next: node2Item
};
  
var node2Item =  {
	value: 'value',
  next: null
}
复制代码

数组 VS 链表

image.png

集合

一组无序且惟一的数据结构。 ES6 集合:Set。 集合的经常使用操做:去重,判断某元素是否在集合中,求交集。

const array = [1, 2, 3, 4, 5];

// 去重
const set1 = [...new Set(array)];

// 判断元素是否在集合中
const set2 = new Set(array);
set2.has(2);

// 求取交集
const set3 = new Set(array);
const set4 = new Set([2, 4, 6]);

const joinSet = new Set([...set3].filter(item => set4.has(item)))
复制代码

字典

与集合相似,字典也是一种存储谓一值的数据结构,可是以键值对的形式来存储。 ES6中有字典,名为Map。 字典的经常使用操做:键值对的增删改查。 ​

const s = new Map();

s.set('name', 'rodchen');
s.set('age', '28');

s.get('name'); // 'rodchen'
s.get('age');
s.delete('age');
s.get('age');

// 修改数据值
s.set('name', 'chenyun');

s.clear();
复制代码

一种分层数据的抽象模型 前端工做中用到的树结构:DOM树,树形控件。

{
  value: 'zhejiang',
  label: 'Zhejiang',
  children: [
    {
      value: 'hangzhou',
      label: 'Hangzhou',
      children: [
        {
          value: 'xihu',
          label: 'West Lake',
        },
      ],
    },
  ],
}
复制代码

经常使用操做:广度优先遍历,深度优先遍历

图示网络结构的抽象模型,是一组由边连接的节点。 图能够表示任何的二元关系,好比道路,航班。 js中没有图,经过Object和Array构件图。 ​

图的表示法:邻接矩阵,邻接表 image.png image.pngimage.png

经常使用操做:广度优先遍历,深度优先遍历

堆是一种彻底二叉树 从第一层到倒数第二层,每一层都是满的,也就是说每一层的结点数都达到了当前层所能达到的最大值最后一层的结点是从左到右连续排列的,不存在跳跃排列的状况(也就是说这一层的全部结点都集中排列在最左边)。 image.png image.png

下面这种就不行 image.png

辅助知识

数组

ES5及以前方法

建立数组

let colors = new Array();
let colors = new Array(20);
let colors = new Array("red", "blue", "green");
let colors = ["red", "blue", "green"];
复制代码

判断数组

value instanceof Array

Array.isArray(value)
复制代码

转换方法

全部对象都有 toLocaleString()、toString()和 valueOf()方法。

  • valueOf()返回的仍是数组自己
  • toString()返回由数组中每一个值的等效字符串拼接而成的一个逗号分隔的字符串,内部调用每一个item的toString方法
  • toLocaleString()则是调用每一个item项目的toLocaleString()
let colors = ["red", "blue", "green"];

console.log(colors.toString()); // red,blue,green 
console.log(colors.valueOf()); // red,blue,green 
console.log(colors); //  ["red", "blue", "green"]
复制代码

栈方法

ECMAScript 数组提供了 push()和 pop()方法,以实现相似栈的行为。

队列方法

ECMAScript 数组提供了 push()和 shift()方法,以实现相似栈的行为。

排序方法

数组有两个方法能够用来对元素从新排序:reverse()和 sort()。

操做方法

  • 合并方法:concat
  • 从现有数组截取建立新数组:slice
  • 在现有数组当中删除 & 新增元素,返回删除的数组:splice
// slice
let colors = ["red", "green", "blue", "yellow", "purple"]; 
let colors2 = colors.slice(1); 
let colors3 = colors.slice(1, 4); // 返回元素的开始索引和结束索引
alert(colors2); // green,blue,yellow,purple 
alert(colors3); // green,blue,yellow

// splice
let colors = ["red", "green", "blue"]; 
let removed = colors.splice(0,1); // 删除第一项

alert(colors); // green,blue 
alert(removed); // red,只有一个元素的数组

removed = colors.splice(1, 0, "yellow", "orange"); // 在位置 1 插入两个元素
alert(colors); // green,yellow,orange,blue 
alert(removed); // 空数组

removed = colors.splice(1, 1, "red", "purple"); // 插入两个值,删除一个元素
alert(colors); // green,red,purple,orange,b
复制代码

搜索和位置方法

indexOf()、lastIndexOf()

  • indexOf()和 includes()方法从数组前头(第一项)开始向后搜索,而 lastIndexOf()从数组末尾(最后一项)开始向前搜索。
  • indexOf()和 lastIndexOf()都返回要查找的元素在数组中的位置,若是没找到则返回 -1。
  • includes()返回布尔值,表示是否至少找到一个与指定元素匹配的项。

迭代方法

  • every():对数组每一项都运行传入的函数,若是对每一项函数都返回 true,则这个方法返回 true。
  • filter():对数组每一项都运行传入的函数,函数返回 true 的项会组成数组以后返回。
  • forEach():对数组每一项都运行传入的函数,没有返回值。
  • map():对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组。
  • some():对数组每一项都运行传入的函数,若是有一项函数返回 true,则这个方法返回 true。

这些方法都不改变调用它们的数组。

归并方法

reduce()和 reduceRight()。这两个方法都会迭代数组的全部项,并在此基础上构建一个最终返回值。reduce()方法从数组第一项开始遍历到最后一项。而 reduceRight()从最后一项开始遍历至第一项。 ​

  • reduce()和 reduceRight()的函数接收 4 个参数:上一个归并值、当前项、当前项的索引和数组自己。这个函数返回的任何值都会做为下一次调用同一个函数的第一个参数。
  • 若是没有给这两个方法传入可选的第二个参数(做为归并起点值),则第一次迭代将从数组的第二项开始,所以传给归并函数的第一个参数是数组的第一项,第二个参数是数组的第二项。
let values = [1, 2, 3, 4, 5]; 
let sum = values.reduce((prev, cur, index, array) => prev + cur);

alert(sum); // 15
复制代码

ES6+方法

建立数组

from()用于将类数组结构转换为数组实例,而 of()用于将一组参数转换为数组实例。

from

// 字符串会被拆分为单字符数组
console.log(Array.from("Matt")); // ["M", "a", "t", "t"] 

// 可使用 from()将集合和映射转换为一个新数组
const m = new Map().set(1, 2) 
 .set(3, 4); 
const s = new Set().add(1) 
 .add(2) 
 .add(3) 
 .add(4); 
console.log(Array.from(m)); // [[1, 2], [3, 4]] 
console.log(Array.from(s)); // [1, 2, 3, 4] 

// Array.from()对现有数组执行浅复制
const a1 = [1, 2, 3, 4]; 
const a2 = Array.from(a1); 
console.log(a1); // [1, 2, 3, 4] 
alert(a1 === a2); // false 

// 可使用任何可迭代对象
const iter = { 
 *[Symbol.iterator]() { 
 yield 1; 
 yield 2; 
 yield 3; 
 yield 4; 
 } 
}; 
console.log(Array.from(iter)); // [1, 2, 3, 4]


/* Array.from()还接收第二个可选的映射函数参数。这个函数能够直接加强新数组的值,而无须像 * 调用 Array.from().map()那样先建立一个中间数组。还能够接收第三个可选参数,用于指定映射函 * 数中 this 的值。但这个重写的 this 值在箭头函数中不适用。 */

const a1 = [1, 2, 3, 4]; 
const a2 = Array.from(a1, x => x**2); 
const a3 = Array.from(a1, function(x) {return x**this.exponent}, {exponent: 2}); 

console.log(a2); // [1, 4, 9, 16] 
console.log(a3); // [1, 4, 9, 16]
复制代码

of

console.log(Array.of(1, 2, 3, 4)); // [1, 2, 3, 4] 
console.log(Array.of(undefined)); // [undefined]
复制代码

迭代器方法

在 ES6 中,Array 的原型上暴露了 3 个用于检索数组内容的方法:keys()、values()和entries()。keys()返回数组索引的迭代器,values()返回数组元素的迭代器,而 entries()返回索引/值对的迭代器:

const a = ["foo", "bar", "baz", "qux"]; 

const aKeys = Array.from(a.keys()); 
const aValues = Array.from(a.values()); 
const aEntries = Array.from(a.entries()); 

console.log(aKeys); // [0, 1, 2, 3] 
console.log(aValues); // ["foo", "bar", "baz", "qux"] 
console.log(aEntries); // [[0, "foo"], [1, "bar"], [2, "baz"], [3, "qux"]]
复制代码

复制 & 填充方法

fill方法

使用 fill()方法能够向一个已有的数组中插入所有或部分相同的值。开始索引用于指定开始填充的位置,它是可选的。若是不提供结束索引,则一直填充到数组末尾。负值索引从数组末尾开始计算。也能够将负索引想象成数组长度加上它获得的一个正索引。

// 用 5 填充整个数组
zeroes.fill(5); 
console.log(zeroes); // [5, 5, 5, 5, 5] 
zeroes.fill(0); // 重置

// 用 6 填充索引大于等于 3 的元素
zeroes.fill(6, 3); 
console.log(zeroes); // [0, 0, 0, 6, 6] 
zeroes.fill(0); // 重置

// 用 7 填充索引大于等于 1 且小于 3 的元素
zeroes.fill(7, 1, 3); 
console.log(zeroes); // [0, 7, 7, 0, 0]; 
zeroes.fill(0); // 重置
复制代码

copyWithin方法

copyWithin()会按照指定范围浅复制数组中的部份内容,而后将它们插入到指定索引开始的位置。开始索引和结束索引则与 fill()使用一样的计算方法

let intArray = [1, 2, 3, 4, 5];

intArray.copyWithin(2, 0, 3); // [1, 2, 1, 2, 3]
复制代码

搜索和位置方法

includes() ES7 includes()返回布尔值,表示是否至少找到一个与指定元素匹配的项

find & findIndex find()和 findIndex()方法使用了断言函数。这两个方法都从数组的最小索引开始。find()返回第一个匹配的元素,findIndex()返回第一个匹配元素的索引。这两个方法也都接收第二个可选的参数,用于指定断言函数内部 this 的值。

数组拉平

Array.prototype.flat()用于将嵌套的数组“拉平”,变成一维的数组。flat()默认只会“拉平”一层,若是想要“拉平”多层的嵌套数组,能够将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1.

[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]

[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]

[1, [2, [3]]].flat(Infinity)

复制代码

flatMap()方法对原数组的每一个成员执行一个函数(至关于执行Array.prototype.map()),而后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。

[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]
复制代码

字符串

ES5及以前方法

建立字符串

let stringObject = new String("hello world");

let message = "abcde";
复制代码

合并字符串

concat:用于将一个或多个字符串拼接成一个新字符串。

截取字符串

slice()、substr()和 substring()。

第一个参数表示子字符串开始的位置,第二个参数表示子字符串结束的位置。对 slice()和 substring()而言,第二个参数是提取结束的位置(即该位置以前的字符会被提取出来)。对 substr()而言,第二个参数表示返回的子字符串数量。 ​

let stringValue = "hello world"; 

console.log(stringValue.slice(3)); // "lo world" 
console.log(stringValue.substring(3)); // "lo world" 
console.log(stringValue.substr(3)); // "lo world" 
console.log(stringValue.slice(3, 7)); // "lo w" 
console.log(stringValue.substring(3,7)); // "lo w" 
console.log(stringValue.substr(3, 7)); // "lo worl"
复制代码

从上面看到slice,substring好像表现的同样,不一样的点在于参数是负数。

  • slice()方法将全部负值参数都当成字符串长度加上负参数值。
  • substr()方法将第一个负参数值当成字符串长度加上该值,将第二个负参数值转换为 0。
  • substring()方法会将全部负参数值都转换为 0。

第一个参数为负数的时候:

let stringValue = "hello world"; 

console.log(stringValue.slice(-3)); // "rld" 
console.log(stringValue.substring(-3)); // "hello world" 
console.log(stringValue.substr(-3)); // "rld"
复制代码

两个参数都是负数的时候:

console.log(stringValue.slice(3, -4)); // "lo w" 
console.log(stringValue.substring(3, -4)); // "hel" 
console.log(stringValue.substr(3, -4)); // "" (empty string)
复制代码

位置方法

indexOf()和 lastIndexOf()。这两个方法从字符串中搜索传入的字符串,并返回位置(若是没找到,则返回-1)。二者的区别在于,

  • indexOf()方法从字符串开头开始查找子字符串
  • 而 lastIndexOf()方法从字符串末尾开始查找子字符串
let stringValue = "hello world";

console.log(stringValue.indexOf("o")); // 4 
console.log(stringValue.lastIndexOf("o")); // 7
复制代码

清空两边空格

trim():返回新的字符串

let stringValue = " hello world "; 
let trimmedStringValue = stringValue.trim(); 
console.log(stringValue); // " hello world " 
console.log(trimmedStringValue); // "hello world"
复制代码

字符串具备@@iterator特性

可以使用for-of和解构操做

for (const c of "abcde") { 
 console.log(c); 
} 
// a 
// b 
// c 
// d 
// e

let message = "abcde"; 
console.log([...message]); // ["a", "b", "c", "d", "e"]
复制代码

匹配功能

search / match / replace方法,具体可查看以前的文章:juejin.cn/post/697103…

比较方法

localeCompare(),这个方法比较两个字符串,返回以下 3 个值中的一个。

  • 若是按照字母表顺序,字符串应该排在字符串参数前头,则返回负值。(一般是-1,具体还要看与实际值相关的实现。)
  • 若是字符串与字符串参数相等,则返回 0。 
  • 若是按照字母表顺序,字符串应该排在字符串参数后头,则返回正值。(一般是 1,具体还要看与实际值相关的实现。)

下面是一个例子:

let stringValue = "yellow";

console.log(stringValue.localeCompare("brick")); // 1 
console.log(stringValue.localeCompare("yellow")); // 0 
console.log(stringValue.localeCompare("zoo")); // -1
复制代码

ES6+方法

包含方法

startsWith()、endsWith()和 includes()。

  • includes():返回布尔值,表示是否找到了参数字符串。
  • startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
  • endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
let message = "foobarbaz"; 

console.log(message.startsWith("foo")); // true 
console.log(message.startsWith("bar")); // false 
console.log(message.endsWith("baz")); // true 
console.log(message.endsWith("bar")); // false 
console.log(message.includes("bar")); // true 
console.log(message.includes("qux")); // false
复制代码

重复字符串

repeat方法返回一个新字符串,表示将原字符串重复n次。

'x'.repeat(3) // "xxx"
复制代码

规则以下:

  • 参数若是是小数,会被取整。
  • 若是repeat的参数是负数或者Infinity,会报错。可是,若是参数是 0 到-1 之间的小数,则等同于 0,这是由于会先进行取整运算。0 到-1 之间的小数,取整之后等于-0,repeat视同为 0。
  • 参数NaN等同于 0。
  • 若是repeat的参数是字符串,则会先转换成数字。

ES8:字符串补全方法

ES2017 引入了字符串补全长度的功能。若是某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。

padStart()和padEnd()一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。

'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'

'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
复制代码

ES10 移除空格方法

ES2019 对字符串实例新增了trimStart()和trimEnd()这两个方法。它们的行为与trim()一致,trimStart()消除字符串头部的空格,trimEnd()消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串。

const s = ' abc ';

s.trim() // "abc"
s.trimStart() // "abc "
s.trimEnd() // " abc"
复制代码

正则方法

  • matchAll():返回正则表达式在字符串的全部匹配
  • ES12 replaceAll(): 替换字符串里全部的匹配项

对象

ES5及以前方法

建立对象

a. 对象直接量 b. 经过new的方式建立对象 c. Object.create() 是一个静态的方法,而不是提供给某个对象调用的方法。 一个参数是新建对象的原型,第二个为可选参数,用以对对象的属性进行说明。

定义属性

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 Object.defineProperties() 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。

const object1 = {};

Object.defineProperty(object1, 'property1', {
  value: 42,
  writable: false
});

Object.defineProperties(obj, {
  'property1': {
    value: true,
    writable: true
  },
  'property2': {
    value: 'Hello',
    writable: false
  }
});
复制代码

检测属性

  • hasOwnProperty 判断一个属性是定义在对象自己仍是继承自原型链。自身对象返回true,继承属性返回false。
  • propertyIsEnumable 是hasOwnProperty()的加强版,只有检测是自有属性的可枚举性,若是是自有属性而且可枚举的返回true。

查询自有可枚举属性

Object.keys() 获取自有属性中枚举属性的合集字符串

查询自有属性属性

Object.getOwnPropertyDescriptor()方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不须要从原型链上进行查找的属性)

var o, d;

o = { get foo() { return 17; } };
d = Object.getOwnPropertyDescriptor(o, "foo");
// d {
// configurable: true,
// enumerable: true,
// get: /*the getter function*/,
// set: undefined
// }
复制代码

Object.getOwnPropertyNames()方法返回一个由指定对象的全部自身属性的属性名(包括不可枚举属性但不包括Symbol值做为名称的属性)组成的数组。

var arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"]
复制代码

原型操做

isPrototypeOf(): p.isPrototypeOf(o) 用来检测p是不是o的原型。

function Foo() {}
function Bar() {}
function Baz() {}

Bar.prototype = Object.create(Foo.prototype);
Baz.prototype = Object.create(Bar.prototype);

var baz = new Baz();

console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true
复制代码

ES6+方法

合并对象

Object.assign() 方法用于将全部可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。

dest = {}; 
src = { id: 'src' }; 
result = Object.assign(dest, src); 
// Object.assign 修改目标对象
// 也会返回修改后的目标对象
console.log(dest === result); // true 
console.log(dest !== src); // true 
console.log(result); // { id: src } 
console.log(dest); // { id: src }


dest = {}; 
result = Object.assign(dest, { a: 'foo' }, { b: 'bar' }); 
console.log(result); // { a: foo, b: bar }
复制代码

判断相等

Object.is() ECMAScript 6 规范新增了 Object.is(),这个方法与===很像,但同时也考虑到了上述边界情形。这个方法必须接收两个参数: 不一样之处只有两个:一是+0不等于-0,二是NaN等于自身

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
复制代码

查询属性

ES5 的Object.getOwnPropertyDescriptor()方法会返回某个对象属性的描述对象(descriptor)。ES2017 引入了Object.getOwnPropertyDescriptors()方法,返回指定对象全部自身属性(非继承属性)的描述对象。

const obj = {
  foo: 123,
  get bar() { return 'abc' }
};

Object.getOwnPropertyDescriptors(obj)
// { foo:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: get bar],
// set: undefined,
// enumerable: true,
// configurable: true } }
复制代码

原型操做

Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值)。 Object.setPrototypeOf() 方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另外一个对象或null。

// 格式
Object.setPrototypeOf(object, prototype)
Object.getPrototypeOf(obj);

// 用法
const o = Object.setPrototypeOf({}, null);
复制代码

Object.setPrototypeOf方法的做用与__proto__相同,用来设置一个对象的原型对象(prototype)。

迭代器方法

Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键值。Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键值对数组。

const obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]

Object.values(obj)
// ["bar", 42]

Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
复制代码

ES6运算符扩展

指数运算符

ES2016 新增了一个指数运算符(**)

2 ** 2 // 4
2 ** 3 // 8

// 右结合运算 至关于 2 ** (3 ** 2)
2 ** 3 ** 2
// 512
复制代码

链判断运算符

编程实务中,若是读取对象内部的某个属性,每每须要判断一下,属性的上层对象是否存在。 ES2020 引入了“链判断运算符”(optional chaining operator)?.,简化上面的写法。

const firstName = message?.body?.user?.firstName || 'default';
const fooValue = myForm.querySelector('input[name=foo]')?.value
复制代码

NUll判断运算符

读取对象属性的时候,若是某个属性的值是null或undefined,有时候须要为它们指定默认值。常见作法是经过||运算符指定默认值。可是属性的值若是为空字符串或false或0,默认值也会生效。 ​

ES2020 引入了一个新的 Null 判断运算符??。它的行为相似||,可是只有运算符左侧的值为null或undefined时,才会返回右侧的值。

const headerText = response.settings.headerText ?? 'Hello, world!';
const animationDuration = response.settings.animationDuration ?? 300;
const showSplashScreen = response.settings.showSplashScreen ?? true;
复制代码

??本质上是逻辑运算,它与其余两个逻辑运算符&&和||有一个优先级问题,它们之间的优先级到底孰高孰低。若是多个逻辑运算符一块儿使用,必须用括号代表优先级,不然会报错。

逻辑赋值运算符

// 或赋值运算符
x ||= y
// 等同于
x || (x = y)

// 与赋值运算符
x &&= y
// 等同于
x && (x = y)

// Null 赋值运算符
x ??= y
// 等同于
x ?? (x = y)



// 老的写法
user.id = user.id || 1;

// 新的写法
user.id ||= 1;
复制代码

学习路线

来源于Lucifer在早早聊的分享其中的一页ppt。

  • 复杂度分析:如何衡量算法的性能
  • 基础的数据结构:线性数据结构 (数组,链表,栈,队列,哈希表)
  • 基础的数据结构:非线形数据结构 (树,图)
  • 排序算法:经典排序算法
  • 递归:一种高级的思惟技巧
  • 暴力搜索篇:回溯,BFS,DFS
  • 暴力优化篇:剪枝,滑动窗口,双指针,单调栈
  • 高级搜索篇:二分法和位运算
  • 动态规划篇:记忆化搜索与动态规划
  • 分治:大事化小,小事化小
  • 贪心:简单高效但不靠谱的算法
  • 逆向思考

算法的掌握程度

来源于叶蒙蒙在早早聊分享的知识,也是一种自我在对于算法掌握的层次考量。

  • 据说
    • 知道名称和功能
  • 了解
    • 知道原理和优缺点
  • 理解
    • 知道过程和实现细节
    • 能描述数据结构和控制流程
    • 知道时空复杂度
  • 实现
    • 可以编程实现
  • 应用
    • 可以运⽤解决实际问题
相关文章
相关标签/搜索