惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
Jina AI
Jina AI
大猫的无限游戏
大猫的无限游戏
Martin Fowler
Martin Fowler
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
C
Cybersecurity and Infrastructure Security Agency CISA
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
S
Securelist
S
Security Affairs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LINUX DO - 热门话题
博客园 - 三生石上(FineUI控件)
T
Threatpost
T
The Blog of Author Tim Ferriss
C
CERT Recently Published Vulnerability Notes
IT之家
IT之家
P
Palo Alto Networks Blog
Microsoft Azure Blog
Microsoft Azure Blog
Spread Privacy
Spread Privacy
Cyberwarzone
Cyberwarzone
腾讯CDC
L
LangChain Blog
Know Your Adversary
Know Your Adversary
C
CXSECURITY Database RSS Feed - CXSecurity.com
GbyAI
GbyAI
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
I
Intezer
T
Tor Project blog
AWS News Blog
AWS News Blog
T
Tenable Blog
NISL@THU
NISL@THU
Security Latest
Security Latest
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
H
Hackread – Cybersecurity News, Data Breaches, AI and More
人人都是产品经理
人人都是产品经理
MongoDB | Blog
MongoDB | Blog
MyScale Blog
MyScale Blog
D
DataBreaches.Net
Microsoft Security Blog
Microsoft Security Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
量子位
美团技术团队
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
罗磊的独立博客
The GitHub Blog
The GitHub Blog
阮一峰的网络日志
阮一峰的网络日志
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Stack Overflow Blog
Stack Overflow Blog

夜行人

回家路上 第一期的直播演示项目 震动检测器 正能量 在线参观CodeLab Neverland 发布 CodeLab Adapter 3.3.1 DynamicTable 之 纸糊方向盘 CodeLab DynamicTable: 一个可实施的技术方案 CodeLab Insight 发布 Alpha 版 情人节 Home Assistant 周报 && IoT 周报 (02) Joplin: 关注隐私的 Evernote 开源替代软件 浏览器的未来与 Web 传感器 Home Assistant 周报 && IoT 周报 (01) 百宝箱(01) 论自由 介绍 WebThings Home Assistant 周报 && iot 周报 (00) 百宝箱(00) 毛姆读书心得 传世之作 周末徒步 CodeLab Adapter ❤️ Jupyter/Python 航班 躲雨 夏令营途中 [译]思想--作为一种技术 The future of coding 美国之行 三门问题的程序模拟 从Python转向Pharo https://blog.just4fun.site/post/iot/iot-open-source-projects/ Python异步编程笔记 https://blog.just4fun.site/post/iot/iot-open-source-hardware-community/ 万物积木化开发者社区 CodeLab ❤️ Blender Scratch3技术分析之云变量 API(第7篇) [译]对管道(Pipes)的偏爱 [译]提出正确的问题比得到正确答案更重要 蓝牙设备与Scratch3.0 创建你的第一个Scratch3.0 Extension Scratch3技术分析之项目内部数据(第6篇) Scratch3技术分析之社区 API(第5篇) Scratch3技术分析之User API(第4篇) Scratch3技术分析之项目主页API(第3篇) Scratch3技术分析之静态资源API(第2篇) Scratch3.0、micro:bit与Windows7 https://blog.just4fun.site/post/iot/zerynth-vs-micropython/ 核聚变、方所与半宅空间 可视化编程为何是个糟糕的主意 codelab.club周末聚会 关于codelab.club '下一件大事'是一个房间 Hungry Robot - Eat everything 编程作为一种思考方式 今日简史 史蒂夫·乔布斯传 罗素自选文集 https://blog.just4fun.site/post/edx/tianjin-scratch-ai/ https://blog.just4fun.site/post/edx/richie-cms-openedx/ 徒步武功山 WebUSB与micro:bit 积木化编程与3D场景 夜宿武功山顶 scratch3-adapter接入优必选Alpha系列机器人 https://blog.just4fun.site/post/edx/video-migration-note/ scratch3-adapter重构笔记 https://blog.just4fun.site/post/edx/edx-community-members/ 两种硬件编程风格的比较 使用micro:bit自制PPT翻页笔 柏拉图对话集 scratch3.0 + micro:bit 七月电影放映计划 非营利组织的管理 Screenly--用树莓派让任何屏幕变为可编程的数字标牌 以最佳实践开始你的Django项目 micro:bit与事件驱动 为Scratch3.0设计的插件系统(上篇) OCR应用一例 近两年读过的一些好书 blockly开发之使用python驱动浏览器中的turtle(2) 牛顿新传 文学理论入门 逻辑的引擎 人生的意义 blockly开发之生成并运行js代码(1) blockly开发之hello world(0) micro:bit使用笔记 神器之Termux https://blog.just4fun.site/post/iot/micropython-notes/ Cozmo what is this Scratch的前世今生 下段旅程 我行在远方 爆裂 途中杂记 https://blog.just4fun.site/post/edx/open-edx-startup/ cozmo系列之入门 - 有性格且可编程的机器人 PaperWeekly开发笔记 创业二三事
JavaScript 备忘
种瓜 · 2020-10-28 · via 夜行人

前言

近期在浏览器中使用 Smalltalk,由于其底层基于 JavaScript(ES6),近期抽空重新过了一下 JavaScript 的语法和特性。

表达式与运算符

在函数调用/数组构造时, 将数组表达式语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
function sum(x, y, z) {
  return x + y + z;
}

const numbers = [1, 2, 3];

console.log(sum(...numbers));
// expected output: 6

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2]; //[0, 1, 2, 3, 4, 5]

var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var mergedObj = { ...obj1, ...obj2 }; // {foo: "baz", x: 42, y: 13}

赋值

解构赋值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20


// Stage 4(已完成)提案中的特性
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});
console.log(a); // 10
console.log(b); // 20
console.log(rest); // {c: 30, d: 40}

展开语法(Spread syntax)

处理数组

For loops, array reduce and method chaining

For loops

1
2
3
4
5
6
7
const files = ["foo.txt ", ".bar", "   ", "baz.foo"];
const filePaths = files
	.map((file) => file.trim())
	.filter(Boolean)
	.map((fileName) => `~/cool_app/${fileName}`);

// filePaths = [ '~/cool_app/foo.txt', '~/cool_app/.bar', '~/cool_app/baz.foo']

函数式风格,易于阅读和扩展,但对迭代的控制较少,不能 return 跳过元素。

数组与对象

4 种数组相关的方法

JavaScript 数组具有非常健壮的 API,提供了许多惊人的工具

map : 将提供的转换应用于原始数组的每个元素, 结果是一个数组的长度与原始数组相同

1
2
3
const arr = [1, 2, 3];
const double = (x) => x * 2;
arr.map(double); // [2, 4, 6]

filter: 使用过滤函数创建新数组,以仅保留 true 基于该函数返回的元素。结果是一个等于或小于原始数组长度的数组

1
2
3
const arr = [1, 2, 3];
const isOdd = (x) => x % 2 === 1;
arr.filter(isOdd); // [1, 3]

reduce: 根据 reduce 函数和初始值创建任何类型的单一输出值。

1
2
3
4
5
6
7
const arr = [1, 2, 3];

const sum = (x, y) => x + y;
arr.reduce(sum, 0); // 6

const increment = (x, y) => [...x, x[x.length - 1] + y];
arr.reduce(increment, [0]); // [0, 1, 3, 6]

reduce 相关参数与细节参考 Array.prototype.reduce()

find: 返回匹配器函数返回的第一个元素 true。结果是原始数组中的单个元素。

1
2
3
const arr = [1, 2, 3];
const isOdd = (x) => x % 2 === 1;
arr.find(isOdd); // 1

将可迭代对象转换为数组

使用spread operator

String

1
2
const name = "Zelda";
const letters = [...name]; // 'Z', 'e', 'l', 'd', 'a'

Set

1
2
3
const data = [1, 2, 3, 1, 2, 4];
const values = new Set(data);
const uniqueValues = [...values]; // [1, 2, 3, 4]

NodeList

1
2
const nodes = document.childNodes;
const nodeArray = [...nodes]; // [ <!DOCTYPE html>, html ]

for…in, for…of and forEach

MDN: for…of 语句 for…in 语句循环一个指定的变量来循环一个对象所有可枚举的属性。

for…of 语句在可迭代对象(包括Array、Map、Set、arguments 等等)上创建了一个循环,对值的每一个独特属性调用一次迭代。

for...in 可用于数组字符串或普通对象,但不能用于 Map 或 Set 对象。(适合我)

1
2
3
4
5
6
7
for (let prop in ["a", "b", "c"]) console.log(prop); // 0, 1, 2 (array indexes)

for (let prop in "str") console.log(prop); // 0, 1, 2 (string indexes)

for (let prop in { a: 1, b: 2, c: 3 }) console.log(prop); // a, b, c (object property names)

for (let prop in new Set(["a", "b", "a", "d"])) console.log(prop); // undefined (no enumerable properties)

forEach()仅迭代数组,但它可以在迭代时访问每个元素的值和索引。

1
2
3
4
5
6
7
["a", "b", "c"].forEach(
	(val) => console.log(val) // a, b, c (array values)
);

["a", "b", "c"].forEach(
	(val, i) => console.log(i) // 0, 1, 2 (array indexes)
);

for...of 可用于数组,字符串 Map 或 Set 对象,但不能用于普通对象。

1
2
3
4
5
6
7
for (let val of ["a", "b", "c"]) console.log(val); // a, b, c (array values)

for (let val of "str") console.log(val); // s, t, r (string characters)

for (let val of { a: 1, b: 2, c: 3 }) console.log(prop); // TypeError (not iterable)

for (let val of new Set(["a", "b", "a", "d"])) console.log(val); // a, b, d (Set values)

map-object

1
2
3
4
5
6
7
const mapObject = (arr, fn) =>
	arr.reduce((acc, el, i) => {
		acc[el] = fn(el, i, arr); // 当前的fn只使用了一个参数
		return acc;
	}, {});
// EXAMPLES
mapObject([1, 2, 3], (a) => a * a); // { 1: 1, 2: 4, 3: 9 }

map-keys

1
2
3
4
5
6
7
const mapKeys = (obj, fn) =>
	Object.keys(obj).reduce((acc, k) => {
		acc[fn(obj[k], k, obj)] = obj[k]; //当前fn只用到2个参数
		return acc;
	}, {});
// 例子
mapKeys({ a: 1, b: 2 }, (val, key) => key + val); // { a1: 1, b2: 2 }

reduce

reduce() 方法对数组中的每个元素执行一个由您提供的 reducer 函数(升序执行),将其结果汇总为单个返回值。

reducer 函数接收 4 个参数:

  • Accumulator (acc) (累计器)
  • Current Value (cur) (当前值)
  • Current Index (idx) (当前索引)
  • Source Array (src) (源数组)

arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

参数细节参考原文。

initialValue: 作为第一次调用 callback 函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 计算数组中每个元素出现的次数

var names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];

var countedNames = names.reduce(function (allNames, name) {
	if (name in allNames) {
		allNames[name]++;
	} else {
		allNames[name] = 1;
	}
	return allNames;
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

对象

在javascript中,一个对象可以是一个单独的拥有属性和类型的实体。我们拿它和一个杯子做下类比。一个杯子是一个对象(物体),拥有属性。杯子有颜色,图案,重量,由什么材质构成等等。同样,javascript对象也有属性来定义它的特征。

使用getter和setter方法扩展原型

使用getter和setter方法扩展 Date原型,为预定义好的Date类添加一个year的属性。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var d = Date.prototype;
Object.defineProperty(d, "year", {
  get: function() { return this.getFullYear() },
  set: function(y) { this.setFullYear(y) }
});

var now = new Date();
console.log(now.year); // 2000
now.year = 2001; // 987617605170
console.log(now);
// Wed Apr 18 11:13:25 GMT-0700 (Pacific Daylight Time) 2001

this

了解 JavaScript 中的’this’关键字

在JavaScript中,this关键字指的是当前正在执行代码的对象。简而言之,常见情况:

  • 默认情况下,this引用全局对象。
  • 在函数中,当不处于严格模式时,this指的是全局对象。
  • 在函数中,在严格模式下this为 undefined。
  • 箭头函数中,this保留封闭词法上下文中this的值this。
  • 在对象方法中,this指的是调用该方法的对象。
  • 在构造函数调用中,this绑定到正在构造的新对象。
  • 在事件处理程序中,this绑定到放置侦听器的元素。

对象上下文

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const obj = {
  f: function() {
    return this;
  }
};

const myObj = Object.create(obj);
myObj.foo = 1;

console.log(myObj.f()); // { foo: 1 }

箭头函数上下文

1
2
3
4
5
6
7
8
9
window.age = 10; // <-- notice me?
function Person() {
  this.age = 42; // <-- notice me?
  setTimeout(() => { // <-- Arrow function executing in the "p" (an instance of Person) scope
    console.log("this.age", this.age); // yields "42" because the function executes on the Person scope
  }, 100);
}

var p = new Person();

事件处理程序上下文

1
2
3
4
5
const el = document.getElementById('my-el');

el.addEventListener('click', function() {
  console.log(this === el); // true
});

Binding this

1
2
3
4
5
6
function f() {
  return this.foo;
}

var x = f.bind({foo: 'hello'});
console.log(x()); // 'hello'

class & this

实例的属性必须定义在类的方法里. ES6 类的方法内部如果含有this,它默认指向类的实例。

1
2
3
4
5
6
class Rectangle {
  constructor(height, width) {    
    this.height = height;
    this.width = width;
  }
}

Promise

Promise 很棒的一点就是链式调用(chaining)。

参考:

prototype

Self语言基于 prototype

在 ES2015/ES6 中引入了 class 关键字,但那只是语法糖,JavaScript 仍然是基于原型的

JavaScript 对象是动态的属性“包”(指其自己的属性)。JavaScript 对象有一个指向一个原型对象的链。

 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
let f = function () {
   this.a = 1;
   this.b = 2;
}
/* 这么写也一样
function f() {
  this.a = 1;
  this.b = 2;
}
*/
let o = new f(); // {a: 1, b: 2}

// 在f函数的原型上定义属性
f.prototype.b = 3;
f.prototype.c = 4;

// 不要在 f 函数的原型上直接定义 f.prototype = {b:3,c:4};这样会直接打破原型链
// o.[[Prototype]] 有属性 b 和 c
//  (其实就是 o.__proto__ 或者 o.constructor.prototype)
// o.[[Prototype]].[[Prototype]] 是 Object.prototype.
// 最后o.[[Prototype]].[[Prototype]].[[Prototype]]是null
// 这就是原型链的末尾,即 null,
// 根据定义,null 就是没有 [[Prototype]]。

// 综上,整个原型链如下: 

// {a:1, b:2} ---> {b:3, c:4} ---> Object.prototype---> null

console.log(o.a); // 1
// a是o的自身属性吗?是的,该属性的值为 1

console.log(o.b); // 2
// b是o的自身属性吗?是的,该属性的值为 2
// 原型上也有一个'b'属性,但是它不会被访问到。
// 这种情况被称为"属性遮蔽 (property shadowing)"

console.log(o.c); // 4
// c是o的自身属性吗?不是,那看看它的原型上有没有
// c是o.[[Prototype]]的属性吗?是的,该属性的值为 4

console.log(o.d); // undefined
// d 是 o 的自身属性吗?不是,那看看它的原型上有没有
// d 是 o.[[Prototype]] 的属性吗?不是,那看看它的原型上有没有
// o.[[Prototype]].[[Prototype]] 为 null,停止搜索
// 找不到 d 属性,返回 undefined

当继承的函数被调用时,this 指向的是当前继承的对象,而不是继承的函数所在的原型对象。

async 和 await

ECMAScript 2017 JavaScript版的一部分

简单来说,它们是基基于promises的语法糖,使异步代码更易于编写和阅读。通过使用它们,异步代码看起来更像是老式同步代码

async

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
async function hello() { return "Hello" };
hello(); // 调用该函数会返回一个 promise

// 异步函数表达式
let hello = async function() { return "Hello" };
hello();

let hello = async () => { return "Hello" };

// 要实际使用promise完成时返回的值,我们可以使用.then()块
hello().then((value) => console.log(value))

将 async 关键字加到函数申明中,可以告诉它们返回的是 promise,而不是直接返回值。此外,它避免了同步函数为支持使用 await 带来的任何潜在开销。

await

await 只在异步函数里面才起作用。它可以放在任何异步的,基于 promise 的函数之前。它会暂停代码在该行上,直到 promise 完成,然后返回结果值。

1
2
3
4
5
async function hello() {
  return greeting = await Promise.resolve("Hello");
};

hello().then(alert); // 当前这行代码并不会阻塞上下文,它的内部是阻塞的,它自身被循环队列处理。

由于 async 关键字将函数转换为 promise,您可以使用 promise 和 await 的混合方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
async function myFetch() {
  let response = await fetch('coffee.jpg');
  return await response.blob();
}

myFetch().then((blob) => {
  let objectURL = URL.createObjectURL(blob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
});

闭包 (Closure)

闭包在实现上是一个结构体,它存储了一个函数和一个关联的环境。环境里是若干对符号和值的对应关系.

闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function makeFunc() {
    var name = "Mozilla";
    function displayName() {
        alert(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();

在一些编程语言中,一个函数中的局部变量仅存在于此函数的执行期间。一旦 makeFunc() 执行完毕,你可能会认为 name 变量将不能再被访问。

JavaScript 中情况显然与此不同。 displayName 的实例维持了一个对它的词法环境(变量 name 存在于其中)的引用。因此,当 myFunc 被调用时,变量 name 仍然可用,其值 Mozilla 就被传递到alert中。

元编程

反射(Reflect)

反射(reflection)是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const duck = {
  name: 'Maurice',
  color: 'white',
  greeting: function() {
    console.log(`Quaaaack! My name is ${this.name}`);
  }
}

Reflect.has(duck, 'color');
// true
Reflect.has(duck, 'haircut');
// false

代理(Proxy

在 ECMAScript 6 中引入的 Proxy 对象可以拦截某些操作并实现自定义行为)

1
2
3
4
5
6
7
8
9
let handler = {
  get: function(target, name){
    return name in target ? target[name] : 42;
}};

let p = new Proxy({}, handler);
p.a = 1;

console.log(p.a, p.b); // 1, 42

Proxy 对象定义了一个目标(这里是一个空对象)和一个实现了 get 陷阱的 handler 对象。这里,代理的对象在获取未定义的属性时不会返回 undefined,而是返回 42。

事件

事件 是你正在编写的 系统 中发生的动作或事件,系统告诉你的是这些动作或事件,如果需要的话,你可以以某种方式对它们做出反应。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const btn = document.querySelector('button');

function random(number) {
  return Math.floor(Math.random()*(number+1));
}

btn.onclick = function() {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  document.body.style.backgroundColor = rndCol;
}

try/except & error

流程控制与错误处理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
function doSomethingErrorProne () {
  if (ourCodeMakesAMistake()) {
    throw (new Error('The message'));
  } else {
    doSomethingToGetAJavascriptError();
  }
}
....
try {
  doSomethingErrorProne();
}
catch (e) {
  console.log(e.name); // logs 'Error'
  console.log(e.message); // logs 'The message' or a JavaScript error message)
}

//finally

函数

函数参数

默认参数

从ECMAScript 6开始,有两个新的类型的参数:默认参数,剩余参数。

在JavaScript中,函数参数的默认值是undefined。

1
2
3
4
5
function multiply(a, b = 1) {
  return a*b;
}

multiply(5); // 5

剩余参数

剩余参数语法允许将不确定数量的参数表示为数组。

1
2
3
4
5
6
function multiply(multiplier, ...theArgs) {
  return theArgs.map(x => multiplier * x);
}

var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]

arguments 对象

函数的实际参数会被保存在一个类似数组的arguments对象中。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function myConcat(separator) {
   var result = ''; // 把值初始化成一个字符串,这样就可以用来保存字符串了!!
   var i;
   // iterate through arguments
   for (i = 1; i < arguments.length; i++) {
      result += arguments[i] + separator;
   }
   return result;
}

// returns "red, orange, blue, "
myConcat(", ", "red", "orange", "blue");

变量

变量的作用域

在函数之外声明的变量,叫做全局变量, 因为它可被 当前文档 中的任何其他代码所访问。

ES 6 有 语句块 作用域;语句块中声明的变量将成为 语句块 所在函数(或全局作用域)的局部变量

1
2
3
4
if (true) {
  let y = 5;
}
console.log(y); // ReferenceError: y 没有被声明

let不像 var 一样,let不会在全局对象里新建一个属性。

语句块

语句块通常用于流程控制,如if,for,while等等。 该块由一对大括号界定

1
2
3
4
while (x < 10) {
  x++;
}
//这里{ x++; }就是语句块。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let x = 1;

if (x === 1) {
  let x = 2;

  console.log(x);
  // expected output: 2
}

console.log(x);
// expected output: 1

全局变量

全局变量是全局对象的属性。在网页中,(译注:缺省的)全局对象是 window ,所以你可以用形如 window.variable 的语法来设置和访问全局变量。

常量(Constants)

用关键字 const 创建一个只读的常量

常量的作用域规则与 let 块级作用域变量相同。

utils

1
2
let {x:{y:z}} = {x:{y:1}}
z // 1

正则表达式

正则表达式是用于匹配字符串中字符组合的模式。

在 JavaScript中,正则表达式也是对象。这些模式被用于 RegExp 的 exec 和 test 方法, 以及 String 的 match、matchAll、replace、search 和 split 方法。

创建

  • 字面量: var re = /ab+c/;
  • 构造函数: var re = new RegExp("ab+c");

使用正则表达式的方法

  • exec: 一个在字符串中执行查找匹配的RegExp方法,它返回一个数组(未匹配到则返回 null)。
  • test: 一个在字符串中测试是否匹配的RegExp方法,它返回 true 或 false。
  • match: 一个在字符串中执行查找匹配的String方法,它返回一个数组,在未匹配到时会返回 null。
  • matchAll: 一个在字符串中执行查找所有匹配的String方法,它返回一个迭代器(iterator)。
  • search: 一个在字符串中测试匹配的String方法,它返回匹配到的位置索引,或者在失败时返回-1。
  • replace: 一个在字符串中执行查找匹配的String方法,并且使用替换字符串替换掉匹配到的子字符串。
  • split: 一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的 String 方法。
1
2
var myRe = /d(b+)d/g;
var myArray = myRe.exec("cdbbdbsbz");

模块

浏览器开始原生支持。

<script type="module"> 属性用于指示引入的模块:

1
<script type="module" src="main.mjs"></script>

只能在模块内部使用 import 和export 语句 ;不是普通脚本文件

export

1
2
// 在模块文件的末尾使用一个export 语句
export { name, draw, reportArea, reportPerimeter };

默认 export

1
2
3
// 注意,不要大括号。 import 也是
export default randomSquare;
// import randomSquare from './modules/square.mjs'; 等效于 import {default as randomSquare} from './modules/square.mjs';

import

1
import { name, draw, reportArea, reportPerimeter } from '/js-examples/modules/basic-modules/modules/square.mjs';

模块对象

1
2
3
4
import * as Module from '/modules/module.mjs';

Module.function1()
Module.function2()

ES6 模块

最新的浏览器开始原生支持模块功能

使用JavaScript 模块依赖于import和 export

systemjs

Dynamic ES module loader

SystemJS允许编写和使用依赖于 ES6 导入和导出语句的模块化javacsript代码。

utils

1
2
3
let a = 1
let c = {a}
c // {a: 1}

杂货铺

sleep

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
function sleep(ms) {
  return new Promise(
    resolve => setTimeout(resolve, ms)
  );
}

async function delayedFunc() { 
  for (let i of [...Array(30).keys()]){
	  await sleep(100);
    // this.rotation = i; // 让object旋转起来
    console.log(i);
  }
  }


delayedFunc.bind(this)();

感受

我侧重使用函数式风格(map/reduce/filter)的表达方式,js 可真是有着 C 语法的 LISP

参考