JavaScript闯关笔记

介绍

通过Array/Object/Function/Api基础类型编写。

看到自己不了解的或者比较新颖的用法便会写上。

不定时更新内容。

本文首发于我的个人网站: Timbok.top

目录

Array

迭代方法

  1. every()方法对数组中的每一项运行给定函数,如果该函数对每一项都返回 true,则返回 true
1
2
3
4
5
const arr = [1,2,3,4];
const result = arr.every((item, index, arr)=>{
return item > 2;
});
console.log(result); // false
  1. some()方法 对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true
1
2
3
4
5
const arr = [1, 2, 3, 4];
const result = arr.some((item, index, arr)=>{
return item > 2;
});
console.log(result); // true
  1. filter()方法对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组
1
2
3
4
5
const arr = [1, 2, 3, 4];
const result = arr.filter((item, index)=>{
return item > 2;
});
console.log(result); // [3, 4]
  1. map()方法 对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组
1
2
3
4
5
const arr = [1, 2, 3, 4];
const result = arr.map((item, index)=>{
return item * index;
});
console.log(result); // [0, 2, 6, 12]
  1. forEach()方法 对数组中的每一项运行给定函数。这个方法没有返回值,本质上与使用 for 循环迭代数组一样
1
2
3
4
const arr = [1, 2, 3, 4];
const result = arr.forEach((item, index)=>{
// 执行某些操作
});
  1. reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。对空数组是不会执行回调函数的。

arr.reduce(callback,[initialValue])

  • callback (执行数组中每个值的函数,包含四个参数)
    • previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
    • currentValue (数组中当前被处理的元素)
    • index (当前元素在数组中的索引)
    • array (调用 reduce 的数组)
  • initialValue (作为第一次调用 callback 的第一个参数。)

无返回值

1
2
3
4
5
const arr = [1, 2, 3];
arr.reduce((pev, item)=>{
console.log(pev, item);
}, 0);
// 运行结果依次为:0 1; undefined 2; undefined 3;

有返回值

1
2
3
4
5
6
7
8
// pev为上次迭代return的值
const arr = [1, 2, 3, 4];
const result = arr.reduce((pev, item)=>{
console.log(pev);
return pev + item;
}, 0);
console.log(result); // 10
// pev运行结果依次为:0, 1, 3, 6

split和join

split(): 用于把一个字符串分割成字符串数组。

1
2
const string = '1, 2, 3, 4, 5';
string.split(','); // ["1", "2", "3", "4", "5"]

如果string为空,则返回一个空数组

1
2
3
const string = '';
string.split(','); // [""]
string.split(); // [""]

join(): 用于把数组中的所有元素放入一个字符串。

1
2
3
const array = [1, 2, 3, 4, 5];
array.join(); // '1,2,3,4,5' 默认用,分割
array.join('|'); // "1|2|3|4|5" 默认用,分割

splice

splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。

注释:该方法会改变原始数组。

arrayObject.splice(index,howmany,item1,.....,itemX)

参数 描述
index 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany 必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, …, itemX 可选。向数组添加的新项目。

举个例子🌰

1
2
3
4
5
6
7
8
var arr = [];
//增加
arr.splice(0, 1, 1); // arr = [1]
arr.splice(1, 1, 2); // arr = [1, 2]
arr.splice(2, 1, 3); // arr = [1, 2, 3]

// 删除
arr.splice(2, 1); // arr = [1, 2]

from

MDN释义:Array.from() 方法从一个类似数组或可迭代对象中创建一个新的

用法:

  • 将字符串拆成数组

    1
    2
    Array.from('foo'); 
    // ["f", "o", "o"]
  • 将类数组转换为数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let array = {
    0: 'name',
    1: 'age',
    2: 'sex',
    3: ['user1','user2','user3'],
    'length': 4
    }
    let arr = Array.from(array )
    console.log(arr) // ['name','age','sex',['user1','user2','user3']]
  • 用length生成数组

    1
    2
    Array.from({ length: 4 }, (...arg) => arg[1])
    // [0, 1, 2, 3]

Object

object映射

定义一个object作为配置对象来存放不同状态,通过链表查找

1
2
3
4
5
6
7
8
9
10
11
12
const statusMap = {
1:()=>{
console.log('a1')
},
2:()=>{
console.log('b2')
}
/* n.... */
}
// 执行
let a = 1
statusMap[a]() // a1

这样比较清晰,将条件配置与具体执行分离。如果要增加其他状态,只修改配置对象即可。

Function

promise

ECMAscript 6 原生提供了 Promise 对象。

Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。

Promise 对象有以下两个特点:

1、对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:

  • pending: 初始状态,不是成功或失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。

只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 Promise 这个名字的由来,它的英语意思就是「承诺」,表示其他手段无法改变。

2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

简单实现:

1
2
3
4
5
6
7
8
function _promise(params) {
return new Promise((resolve, reject)=>{
params>0 ? resolve('正数') : reject('负数');
});
}
_promise(1).then(res=>console.log(res)) // 正数

_promise(-1).catch(res=>console.log(res)) // 负数

Promise.all

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let p1 = new Promise((resolve, reject) => {
resolve('成功了')
})

let p2 = new Promise((resolve, reject) => {
resolve('success')
})

let p3 = Promise.reject('失败')

Promise.all([p1, p2]).then((result) => {
console.log(result) //['成功了', 'success']
}).catch((error) => {
console.log(error)
})

Promise.all([p1,p3,p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // '失败'
})

需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。

Promise.race

顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})

let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})

Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 打开的是 'failed'
})

async-await

ES2017 标准引入了async 函数,使得异步操作变得更加方便。

async 函数是什么?一句话,它其实就是promiseGenerator 函数的语法糖。

async

async 用来表示函数是异步的,定义的函数会返回一个promise对象,可以使用then方法添加回调函数。

1
2
3
4
5
6
7
8
async function test() {
return 123;
}

test().then(res => {
console.log(res);// 123
});
async 定义的函数有返回值,return 123;相当于Promise.resolve(123),没有声明式的 return则相当于执行了Promise.resolve();

await

await 可以理解为是 async wait 的简写。await 必须出现在 async 函数内部,不能单独使用。

1
2
3
4
function notAsyncFunc() {
await Math.random();
}
notAsyncFunc();//Uncaught SyntaxError: Unexpected identifier

await 后面可以跟任何的JS 表达式。虽然说 await 可以等很多类型的东西,但是它最主要的意图是用来等待 Promise 对象的状态被 resolved。如果await的promise对象会造成异步函数停止执行并且等待 promise 的解决,如果等的是正常的表达式则立即执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function sleep(second) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(' enough sleep~');
}, second);
})
}
function normalFunc() {
console.log('normalFunc');
}
async function awaitDemo() {
await normalFunc();
console.log('something, ~~');
let result = await sleep(2000);
console.log(result);// 两秒之后会被打印出来
}
awaitDemo();
// normalFunc
// VM4036:13 something, ~~
// VM4036:15 enough sleep~

希望通过上面的 demo,大家可以理解我上面的话。

错误处理

上述的代码好像给的都是resolve的情况,那么reject的时候我们该如何处理呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function sleep(second) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('want to sleep~');
}, second);
})
}

async function errorDemo() {
let result = await sleep(1000);
console.log(result);
}
errorDemo();// VM706:11 Uncaught (in promise) want to sleep~

// 为了处理Promise.reject 的情况我们应该将代码块用 try catch 包裹一下
async function errorDemoSuper() {
try {
let result = await sleep(1000);
console.log(result);
} catch (err) {
console.log(err);
}
}

errorDemoSuper();// want to sleep~
// 有了 try catch 之后我们就能够拿到 Promise.reject 回来的数据了。

最后一点,await必须在async函数的上下文中的。

参考文章

获取函数参数名

1
2
3
4
5
6
7
8
9
10
11
12
13
function getParameterName(fn) {
if(typeof fn !== 'object' && typeof fn !== 'function' ) return;
const COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
const DEFAULT_PARAMS = /=[^,)]+/mg;
const FAT_ARROWS = /=>.*$/mg;
let code = fn.prototype ? fn.prototype.constructor.toString() : fn.toString();
code = code
.replace(COMMENTS, '')
.replace(FAT_ARROWS, '')
.replace(DEFAULT_PARAMS, '');
let result = code.slice(code.indexOf('(') + 1, code.indexOf(')')).match(/([^\s,]+)/g);
return result === null ? [] :result;
}

示例

1
2
3
function example(x, y) { return x, y };

getParameterName(example); // ["x", "y"]

Api

可选链?.

MDN释义

可选链操作符?.能够去读取一个被连接对象的深层次的属性的值而无需明确校验链条上每一个引用的有效性

基本使用

1
2
3
let prop = obj?.prop
// 等同于
let prop = obj && obj.prop

可选链与函数调用

函数调用时如果被调用的方法不存在,使用可选链可以使表达式自动返回undefined而不是抛出一个异常。

1
props.onSearch?.()

注意:可选链在赋值时无效

1
2
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment

逗号表达式

MDN释义:对它的每个操作数求值(从左到右),并返回最后一个操作数的值。


1
2
3
4
5
6
7
8
9
10
var a = (1, 2, 3);
console.log(a); // 3

// ...

function num() {
var a, b, c = 1, 2, 3;
return a, b, c;
}
num() // 3

原型和原型链

原型

在 JavaScript 中,函数(function)是允许拥有属性的。所有的函数会有一个特别的属性 —— prototype,这个属性就是原型,它是一个对象。

原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中

1
2
3
4
5
6
7
8
9
10
11
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
return this.name;
}
}
var timbok = new Person('timbok', 18);
var lucy = new Person('lucy', 20);

console.log(timbok.sayName === lucy.sayName); // false

可以看到,对于同一个函数,我们通过 new 生成出来的实例,都会开出新的一块堆区,所以上面代码中 timbok 和 lucy的sayName不相等。

当使用prototype

1
2
3
4
5
6
7
Person.prototype.eat = function() {
console.log('吃');
}
var timbok = new Person('timbok', 18);
var lucy = new Person('lucy', 20);

console.log(timbok.eat === lucy.eat); // true

原型链

在JavaScript中万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条,专业术语称之为原型链。

1
2
3
Person.prototype.constructor === Person // true

Person.prototype === timbok.__proto__ // true

当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。如果没有则去原型的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined。

1
2
3
4
5
6
Person.prototype.a = 123;

var person = new Person()

console.log(person.a) // 123
console.log(person.b) // undefined

person.a:

先在person对象里找a -> 没找到会再到person.__proto__,也就是 Person.prototype内找 -> 找到了

person.b:

先在person对象里找b -> 没找到会再到person.__proto__内找 -> 查找与对象关联的原型中的属性 -> 找原型的原型,一直找到最顶层Object为止 -> 找不到就undefined

衍生扩展-new操作符

要想弄懂new,得先了解一下何为构造函数

构造函数

构造函数与其他函数的唯一区别,就在于调用它们的方式不同。不过,构造函数毕竟也是函数,不存在定义构造函数的特殊语法。任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数

用以下的例子来模仿 var person = new Person() 的过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 1. 需要一个创造器
function Creator() {
this.name='creator'
console.log("创造器");
}

// 2. 新建变量,开辟内存
var person = {};

// 3. 通过 __proto__ 指向Creator的原型
person.__proto__ = Creator.prototype

// 4. call person 使其可以扩展name
Creator.call(person) // 创造器

// 5.在原型上增加方法
Creator.prototype.action = function() {
console.log('创造动作')
}

person.action() // 创造动作
console.log(person) // Creator {name: 1}

关于 this、apply、call、bind 可以看这篇文章。

Copyright © 2017 - 2021 Timbok's Blog All Rights Reserved.

访客数 : | 访问量 :