# 前端爱好者学习周刊:第9期
20200405
# 1.Object.seal()
Object.seal方法理解 (opens new window)
Object.seal()方法被用来封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置
var obj = {
prop: function() {},
foo: 'bar'
};
obj.foo = 'baz';
obj.lumpy = 'woof';
delete obj.prop; // true
obj // {foo: "baz", lumpy: "woof"}
// =========使用seal冻结=========
var o = Object.seal(obj);
o === obj; // true
Object.isSealed(obj); // === true
// 可以更改属性值
obj.foo = 'quux';
obj // {foo: "quux", lumpy: "woof"}
// 不能添加访问者(报错)
Object.defineProperty(obj, 'foo', {
get: function() { return 'g'; }
}); // throws a TypeError
// 添加属性不报错但是原对象不变
obj.quaxxor = 'the friendly duck';
// 删除属性失败
delete obj.foo; // false
// 严格模式下添加和删除属性都抛出异常
function fail() {
'use strict';
delete obj.foo; // throws a TypeError
obj.sparky = 'arf'; // throws a TypeError
}
fail();
// 使用defineProperty添加属性报错
Object.defineProperty(obj, 'ohai', {
value: 17
}); // throws a TypeError
// 使用defineProperty修改属性值可行
Object.defineProperty(obj, 'foo', {
value: 'eit'
}); // changes existing property value
obj // {foo: "eit", lumpy: "woof"}
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
46
47
48
49
50
从上面我们可以看出:
- 被封闭对象仍旧全等该对象本身
- 可以通过Object.isSealed来判断当前对象是否被封闭
- 不能为被封闭对象添加任何未知属性, 也不能为其已知属性添加访问者
- 可以修改已知的属性
var a = {b: 1, c: 2, d: {e: 3}}
Object.seal(a)
a.d.f = 4;
a.d
{e: 3, f: 4}
2
3
4
5
可以看出: 与Object.freeze一样, Object.seal方法一样, Object.seal并不是递归的, 在封闭一个对象之后, 我们仍然可以访问/设置其下一级的属性.
小结:
- Object.freeze 不能增删改,但是只是浅层冻结
- Object.seal 不能增删,可以改,但是只是浅层冻结
# 2.peerDependencies
peerDependencies的目的是提示宿主环境去安装满足插件peerDependencies所指定依赖的包,然后在插件import或者require所依赖的包的时候,永远都是引用宿主环境统一安装的npm包,最终解决插件与所依赖包不一致的问题。
一般在发布包时会增加这个配置;
比如antd
的package.json
中就有下面的:
"peerDependencies": {
"react": ">=16.0.0",
"react-dom": ">=16.0.0"
}
2
3
4
组件中引入的react和react-dom包其实都是宿主环境提供的依赖包。
我们内部的组件库中就配置了:
"peerDependencies": {
"antd": "^3.22.2",
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
2
3
4
5
# 3. https
Express实现http和https服务 (opens new window):
- https协议需要到ca申请证书,一般免费证书很少,需要交费。
- http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,默认用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
生成证书文件:
# 创建一个文件夹存放证书
$ mkdir cert
$ cd cert
#生成私钥key文件:
$ openssl genrsa -out privatekey.pem 1024
#通过私钥生成CSR证书签名
$ openssl req -new -key privatekey.pem -out certsign.csr
# 通过私钥和证书签名生成证书文件
$ openssl x509 -req -in certsign.csr -signkey privatekey.pem -out certificate.crt
2
3
4
5
6
7
8
9
10
11
12
express服务代码:
var app = require('express')();
var fs = require('fs');
var http = require('http');
var https = require('https');
var httpServer = http.createServer(app);
var httpsServer = https.createServer({
key: fs.readFileSync('./cert/privatekey.pem', 'utf8'),
cert: fs.readFileSync('./cert/certificate.crt', 'utf8')
}, app);
var PORT = 80;
var SSLPORT = 443;
httpServer.listen(PORT, function() {
console.log('HTTP Server is running on: http://localhost:%s', PORT);
});
httpsServer.listen(SSLPORT, function() {
console.log('HTTPS Server is running on: https://localhost:%s', SSLPORT);
});
// 访问路径
app.get('/:name', function(req, res) {
if(req.protocol === 'https') {
res.send('https:' + req.params.name);
} else {
res.send('http:' + req.params.name);
}
});
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
# 4.URLSearchParams
这个URLSearchParams我并没有用过,但是看到在处理url参数时还挺好用,不过兼容性不好。
const url = 'http://localhost/es6style.html?foo=bar&baz=qux'
const searchs = '?foo=bar&baz=qux' // location.search
const urlPs = new URLSearchParams(searchs)
console.log(urlPs.get('foo')) // bar
const paramsObjs = Object.fromEntries(urlP)
console.log(paramsObjs) // { foo: 'bar', baz: 'qux' }
2
3
4
5
6
7
8
9
在网上发现还挺多人用这个处理请求参数的,不过引发了兼容问题(URLSearchParams 兼容性引发IOS 10 白屏问题 (opens new window)),使用url-search-params-polyfill (opens new window)来处理:
$ npm install url-search-params-polyfill --save
import 'url-search-params-polyfill';
# 5.parcel-bundler
极速零配置Web应用打包工具
很简单的一个打包工具:
// package.json
"scripts": {
"start": "parcel ./src/index.html"
},
2
3
4
基本不用添加什么配置,很多都是自动识别项目下的配置文件,比如babel
的.babelrc,postcss
的.postcssrc等;vue,react这些就直接进行打包,不需要配置。还可以使用动态引用(import)新语法,利于代码拆分。甚至可以不用先安装一些包,parcel会直接去安装
如果要增加配置,就在package.json
中直接添加;
可以使用热重载;
打包神器之Parcel使用指南 (opens new window)这篇文章不错,还有具体的demo
# 6.ES2020
# 1).class中的私有变量
class Message {
#message = "Howdy"
greet() { console.log(this.#message) }
}
const greeting = new Message()
greeting.greet() // Howdy
console.log(greeting.#message) // Private name #message is not defined
2
3
4
5
6
7
8
9
10
# 2).Promist.allSetted
Promise.all 和 Promise.allSettled (opens new window)
由于单一 Promise 进入 rejected 状态便会立即让 Promise.all() 的结果进入 rejected 状态,以至于通过 Promise.all() 进入 rejected 状态时,其中的源 Promise 仍然可能处于 pending 状态,以至于无法获得所有 Promise 完成的时机。
Promise.allSettled() API 被提出,其中 settled 状态的定义是非 pending,即 fulfilled 或者 rejected 中的任一状态。
Promise 中的三兄弟 .all(), .race(), .allSettled() (opens new window)
Promise.all()的类型签名:
Promise.all<T>(promises: Iterable<Promise<T>>): Promise<Array<T>>
返回情况:
完成(Fulfillment): 如果传入的可迭代对象为空,Promise.all 会同步地返回一个已完成(resolved)状态的promise。 如果所有传入的 promise 都变为完成状态,或者传入的可迭代对象内没有 promise,Promise.all 返回的 promise 异步地变为完成。 在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组,它包含所有的传入迭代参数对象的值(也包括非 promise 值)。
失败/拒绝(Rejection): 如果传入的 promise 中有一个失败(rejected),Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成。
# 3).??
let person = {
profile: {
name: "",
age: 0
}
};
console.log(person.profile.name || "Anonymous"); // Anonymous
console.log(person.profile.age || 18); // 18
console.log(person.profile.name ?? "Anonymous"); // ""
console.log(person.profile.age ?? 18); // 0
2
3
4
5
6
7
8
9
10
11
12
# 4).BigInt
原来JS的最大值为MAX_SAFE_INTEGER
2^53
const max = Number.MAX_SAFE_INTEGER;
console.log(max); // 9007199254740991
2
3
现在增加BigInt
,数据后面要加个n
,
const bigNum = 100000000000000000000000000000n;
console.log(bigNum * 2n); // 200000000000000000000000000000n
2
3
# 5).可以使用 async/await
来动态引入import
import()
之后返回一个Promise
对象
// pages/about.js
export function render() {
// 渲染页面
}
// index.js
import('./pages/about').then(function(page) {
// 渲染页面
page.render()
})
// 或者
const page = await import('./pages/about')
// 渲染页面
page.render()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// math.js
const add = (num1, num2) => num1 + num2;
export { add};
// index.js
const doMath = async (num1, num2) => {
if (num1 && num2) {
const math = await import('./math.js');
console.log(math.add(5, 10));
};
};
doMath(4, 2);
2
3
4
5
6
7
8
9
10
11
12
13
# ES2020语法新加插件
{
"plugins": [
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-private-methods",
"@babel/plugin-syntax-bigint"
]
}
2
3
4
5
6
7
8
9