原生JS

工作线程(webWorker)

简介:web worker是HTML5引入的一个工作线程的概念,是运行在后台的JavaScript,独立于其他脚本。允许开发人员编写能够长时间运行而不被用户所中断的后台程序,去执行事务或者逻辑,并同时保证页面对用户的响应。

简而言之,就是允许JavaScript创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。
从而,可以用webWorker来处理一些比较耗时的计算。

 web js
  

es6

ES6项目构建

let和const命令

let命令

let声明

1
2
3
4
5
6
{
let a=10;//let声明的变量只在它所在的代码块有效
var b=1;
}
console.log(b);
// console.log(a);//报错

let应用

1
2
3
4
5
6
7
8
9
10
11
for(let i=0;i<10;i++){}
//console.log(i);//i不能在外面引用
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6]();
//如果是var声明,则会输出10;如果是let声明,则会输出6
//let声明中,每次循环的i其实都是一个新的变量

let不支持变量提升

只要块级作用域内存在let命令,它所声明的变量就“绑定”了这块区域,不再受外部的影响

1
2
3
4
5
6
7
8
9
10
11
var temp=123;
if(true){
temp='abc';//会报错,因为下面的let声明了temp,所以这里的temp和外面的就没有关系了,
//但是此处的赋值在声明之前,还没有声明就赋值会报错
let temp;
/*ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。*/
//称为暂时性死区
}
typeof x; // 报错
let x;
//let不予许重复声明

块级作用域

外层作用域无法读取内层作用域的变量

1
2
3
4
{{{{
{let insane = 'Hello World'}
console.log(insane); // 报错
}}}};

内层作用域可以定义外层作用域的同名变量

1
2
3
4
{{{{
let insane = 'Hello World';
{let insane = 'Hello World'}
}}}};

作用:使的获得广泛应用的立即执行函数表达式(IIFE)不再必要了

1
2
3
4
5
6
7
8
9
10
// IIFE 写法
(function () {
var tmp = ...;
...
}());
// 块级作用域写法
{
let tmp = ...;
...
}

do 表达式

块级作用域本质上是语句,没有返回值,所以在外部没法或许执行结果

可以通过do表达式获取块级作用于中的最后执行的表达式的值。

1
2
3
4
let x = do{
let t = f();
t * t + 1;
}

const 命令

const 声明一个只读的常量。一旦声明,常量的值就不能改变。—所以常量一旦声明就必须立即初始化,不能留到以后赋值
const 的作用域与let命令相同:只在声明所在的块级作用域内有效
const 命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。

const实际保证的,并不是变量的值不得改动,而是变量指向的哪个地址不得改动
如:const foo={};
foo存的是地址,这个地址指向一个对象,这个对象本身是可变的,故可添加属性foo.prop=123;
但是不可把foo指向另一个地址:foo = {}//错误

————-让对象冻结的方法(不可改变属性)—————

1
2
const foo=Object freeze({});
foo.prop=123;//常规模式下,此行代码不起作用。 严格模式下会报错

————-让对象彻底冻结的方法————————-
注:对象的属性有可能还是对象,那么对象的属性就有可能有自己的属性,那么对象的属性也要被冻结

***使用回调函数

1
2
3
4
5
6
7
8
var constantize = (obj)=>{
Object freeze(obj);
Object keys(obj).forEach((key,i)=>{
if(typeof obj[key]==='object'){
constantize(obj[key]);
}
});
}

es6声明变量的6种方法

var function let const import class es5只有前两种

顶层对象的属性

顶层对象:window(浏览器环境),global(Node环境)

window.a=1; 和 a=1; 是一样的,即顶层对象属性和全局变量是一样的

这是JavaScript设计的败笔之一,ES6为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。

1
2
3
4
5
6
var a = 1;
// 如果在Node的REPL环境,可以写成global.a
// 或者采用通用方法,写成this.a
window.a // 1
let b = 1;
window.b // undefined

global对象

有一个提案,在语言标准的层面,引入global作为顶层对象。也就是说,在所有环境下,global都是存在的,都可以从它拿到顶层对象

垫片库(system.global)模拟了这个提案,可以在所有环境中拿到global

1
2
import getGlobal from 'system.global';
const global = getGlobal();

变量的解构赋值

数组的解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

如果解构不成功,变量的值就等于undefined。

1
2
let [foo] = [];
let [bar, foo] = [1];

以上两种情况都属于解构不成功,foo的值都会等于undefined。

不完全解构:

1
2
let [x, y] = [1, 2, 3];// x 为1, y为2
let [a, [b], d] = [1, [2, 3], 4];//a 为 1,b为 2,d为4

//下面情况将会报错,右边必须为数组(可遍历的结构——Iterator 接口)形式

1
2
3
let [foo] = 1;
let [foo] = undefined;
let [foo] = {};

对于 Set 结构,也可以使用数组的解构赋值。

1
2
let [x, y, z] = new Set(['a', 'b', 'c']);
x // "a"

事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。

1
2
3
4
5
6
7
8
9
10
function* fibs() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5

默认值

解构赋值允许指定默认值

1
2
3
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'

ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值是不会生效的。

1
2
3
4
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null

如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。
==惰性求值==:即只有在用到的时候才会求值
默认值可以引用解构赋值的其他变量,但该变量必须已经声明

1
2
3
let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ReferenceError

对象的解构赋值

数组的解构赋值是有顺序的,但是对象的解构赋值是无需的,变量名和属性同名才能获取到正确的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let { bar: bar, foo: foo } = { foo: "aaa", bar: "bbb"};
// 可以简写为
let { bar, foo } = { foo: "aaa", bar: "bbb"};
foo // "aaa"
bar // "bbb"
let {foo: xiao , baz } = { foo: "aaa", bar: "bbb"};
baz // undefined
xiao // "aaa"
//真正被赋值的是后者
foo // error : foo is not defined

let obj = { first: 'hello', last: 'world' };
let { first: f, last: 1 } = obj;
f // 'hello'
l // 'world'

与数组一样,结构也可以用于嵌套结构的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
//如果写法如下:那么p既是模式又是变量
let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]

一个嵌套的例子:

1
2
3
4
5
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true});// 此处必须加小括号,否则会报错
obj // {prop:123}
arr // [true]

对象的结构也可以设置默认值,默认值生效的条件是严格等于undefined

如果结构失败,变量的值等于undefined

1
2
3
var { x = 1, y = 2 } = { x: undefined, y: null };
x // 1
y // null

对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量

1
2
3
let {sin, cos, tan} = Math;
Math.sin // 一个sin function
sin // 一个sin function 直接将Math中的方法给了sin

字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象

1
2
3
4
5
6
7
const [a, b, c, d, e] = 'hello';
a // "h"
e // "o"

//类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值
let {length : len} = 'hello';
len // 5

数值和布尔值得解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转为对象,无法转化成对象,将会报错

1
2
3
4
5
6
7
8
let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError

函数参数的解构赋值

1
2
3
4
5
6
7
function add([x, y]){
return x + y;
}
add([1, 2]); // 3

[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]

undefined就会触发函数参数的默认值。

1
2
[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]

圆括号问题

建议只要有可能,就不要在模式中放置圆括号

不能使用圆括号的情况

1.变量声明语句

1
2
3
4
5
6
7
//全部报错
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };

2.函数参数

1
2
3
4
// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }

3.赋值语句模式

1
2
3
4
5
6
// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];

// 报错
[({ p: a }), { x: c }] = [{}, {}];

可以使用圆括号的情况

只有一种:赋值语句的非模式部分,可以使用圆括号

1
2
3
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确

用途

1.交换变量的值

1
2
3
let x = 1;
let y =2;
[x, y] = [y, x];

2.从函数返回多个值
直接取值就可以

1
2
3
4
5
6
7
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();

3.函数参数的定义
4.提取JSON数据

1
2
3
4
5
6
7
8
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]

5.函数参数的默认值

1
2
3
4
5
6
7
8
9
10
11
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
}) {
// ... do stuff
};

指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || ‘default foo’;这样的语句
6.遍历Map结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world

//如果只想获取键名,或者只想获取键值,可以写成下面这样。
// 获取键名
for (let [key] of map) {
// ...
}
// 获取键值
for (let [,value] of map) {
// ...
}

7.输入模块的指定方法
加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

1
const { SourceMapConsumer, SourceNode } = require("source-map");

字符串的扩展

字符的Unicode表示法

codePointAt()

String.fromCodePoint()

字符串的遍历器接口

es6为字符串添加了遍历器接口,而且增加的for…of循环识别码点

1
2
3
4
5
6
7
8
9
10
11
let text = String.fromCodePoint(0x20BB7);
for (let i of text) {
console.log(i);
}
// "𠮷"

for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "

at()

es5中的charAt方法可以返回字符串指定位置的字符,但是不识别码点大于0xFFFF的字符。es6提供了at()方法,可以实现这一要求

6
1
2
3
4
'abc'.charAt(0) //"a"
'𠮷'.charAt(0) // "\uD842"
'abc'.at(0) // "a"
'𠮷'.at(0) // "𠮷"

normalize()

includes()、startWith()、endsWith

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

6
1
2
3
4
5
6
7
8
9
10
let s = 'Hello world!';

s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true

//这三个方法都支持第二个参数,表示开始搜索的位置。
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false

repeat()

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

6
1
'hello'.repeat(2) // "hellohello"

padStart(),padEnd()

字符串补全长度的功能9

 web js
  

:D 一言句子获取中...