原文链接:css-tricks.com

第9版ECMAScript标准于2018年6月发布,正式名称为ECMAScript 2018(简称ES2018)。从ES2016开始,ECMAScript规范的新版本每年发布一次,而不是每隔几年发布一次,相应的,每版增加的功能也更少一些。最新版本的标准通过添加4个新的RegExp特性、rest/spread属性、异步迭代和Promise.prototype.finally来延续每年的发布周期。此外,ES2018取消了标记模板转义序列的语法限制。

以下将逐一解释这些变动。

Rest/Spread 特性


ES2015中添加的最有趣的特性之一是spread操作符。你可以用它替换cancat()和slice()方法,使数组的操作(复制、合并)更加简单。

const arr1 = [10, 20, 30];

// make a copy of arr1
const copy = [...arr1]; console.log(copy); // → [10, 20, 30] const arr2 = [40, 50]; // merge arr2 with arr1
const merge = [...arr1, ...arr2]; console.log(merge); // → [10, 20, 30, 40, 50]

在数组必须以拆解的方式作为函数参数的情况下,spread操作符也很有用。例如:

const arr = [10, 20, 30]

// equivalent to
// console.log(Math.max(10, 20, 30));
console.log(Math.max(...arr)); // → 30

ES2018通过向对象文本添加扩展属性进一步扩展了这种语法。他可以将一个对象的属性拷贝到另一个对象上,参考以下情形:

const obj1 = {
a: 10,
b: 20
}; const obj2 = {
...obj1,
c: 30
}; console.log(obj2); // → {a: 10, b: 20, c: 30}

在上述代码中,spread操作符遍历obj1属性,并将其添加到obj2的属性中;而在之前的版本中,如此处理会抛出一个异常。需要注意的是,如果存在相同的属性名,只有最后一个会生效。

const obj1 = {
a: 10,
b: 20
}; const obj2 = {
...obj1,
a: 30
}; console.log(obj2); // → {a: 30, b: 20}

同时,Spread操作符可以作为Object.assign() 的一个替代方案进行对象融合:

const obj1 = {a: 10};
const obj2 = {b: 20};
const obj3 = {c: 30}; // ES2018
console.log({...obj1, ...obj2, ...obj3}); // → {a: 10, b: 20, c: 30} // ES2015
console.log(Object.assign({}, obj1, obj2, obj3)); // → {a: 10, b: 20, c: 30}

然而,在进行对象融合时,Spread操作结果并不总是与Object.assign()一致,例如:

Object.defineProperty(Object.prototype, 'a', {
set(value) {
console.log('set called!');
}
}); const obj = {a: 10}; console.log({...obj});
// → {a: 10} console.log(Object.assign({}, obj));
// → set called!
// → {}

在上述代码中,Object.assign()方法继承了setter属性;而spread操作忽略了setter。

划重点:spread只复制枚举属性。在下面的例子中,type属性不会出现在复制对象中,因为它的枚举属性被设置为false:

const car = {
color: 'blue'
}; Object.defineProperty(car, 'type', {
value: 'coupe',
enumerable: false
}); console.log({...car}); // → {color: "blue"}

继承的属性即使是可枚举的也会被忽略:

const car = {
color: 'blue'
}; const car2 = Object.create(car, {
type: {
value: 'coupe',
enumerable: true,
}
}); console.log(car2.color); // → blue
console.log(car2.hasOwnProperty('color')); // → false console.log(car2.type); // → coupe
console.log(car2.hasOwnProperty('type')); // → true console.log({...car2}); // → {type: "coupe"}

在上述代码中,car2继承了car中的color属性。因为spread操作只会复制对象自身的属性,color并没有出现在新的对象中。

spread只会进行浅拷贝,如果属性的值是一个对象的话,只有对象的引用会被拷贝:

const obj = {x: {y: 10}};
const copy1 = {...obj};
const copy2 = {...obj}; console.log(copy1.x === copy2.x); // → true

copy1.x 和 copy2.x 指向同一个对象的引用,所以他们严格相等。

ES2015增加的另一个有用特性是rest参数,它允许JS使用……将值表示为数组:

const arr = [10, 20, 30];
const [x, ...rest] = arr; console.log(x); // → 10
console.log(rest); // → [20, 30]

在上述代码中,arr中的第一项分配给x,其余元素分配给rest变量。这种模式称为数组析构,非常流行,Ecma技术委员会决定为对象提供类似的功能:

const obj = {
a: 10,
b: 20,
c: 30
}; const {a, ...rest} = obj; console.log(a); // → 10
console.log(rest); // → {b: 20, c: 30}

这段代码使用析构赋值中的rest属性将剩余的可枚举属性复制到一个新对象中。注意,rest属性必须始终出现在对象的末尾,否则将抛出错误:

const obj = {
a: 10,
b: 20,
c: 30
}; const {...rest, a} = obj; // → SyntaxError: Rest element must be last element

此外,在对象中使用多个rest语法会抛异常,除非它们是嵌套的:

const obj = {
a: 10,
b: {
x: 20,
y: 30,
z: 40
}
}; const {b: {x, ...rest1}, ...rest2} = obj; // no error const {...rest, ...rest2} = obj; // → SyntaxError: Rest element must be last element

Rest/Spread 特性支持

 Chrome   Firefox   Safari   Edge 
60   55   11.1  No 

 Chrome 

 Android 

 Firefox

 Android 

 iOS

 Safari 

 Edge

 Mobile 

 Samsung

 Internet  

 Android

 Webview 

60 55 11.3 No 8.2 60

Node.js:

  • 8.0.0 (需要 --harmony 运行环境)

  • 8.3.0 (完全支持)

异步迭代


遍历是编程的一个重要部分。JS提供了for、for…in和while以及map()、filter()和forEach()等遍历数据的方法。在ES2015则引入了迭代器接口。

包含Symbol.iterator属性的对象是可迭代对象,如字符串和集合对象(如Set、Map和Array)。如下为迭代遍历的示例:

const arr = [10, 20, 30];
const iterator = arr[Symbol.iterator](); console.log(iterator.next()); // → {value: 10, done: false}
console.log(iterator.next()); // → {value: 20, done: false}
console.log(iterator.next()); // → {value: 30, done: false}
console.log(iterator.next()); // → {value: undefined, done: true}

Symbol.iterator是指定返回迭代器的函数. 迭代器包含next()方法,返回包含value和done属性的对象。其中value为下一个元素,done为布尔值,表示遍历是否结束。

普通对象进行迭代需要定义Symbol.iterator属性。示例如下:

const collection = {
a: 10,
b: 20,
c: 30,
[Symbol.iterator]() {
const values = Object.keys(this);
let i = 0;
return {
next: () => {
return {
value: this[values[i++]],
done: i > values.length
}
}
};
}
}; const iterator = collection[Symbol.iterator](); console.log(iterator.next()); // → {value: 10, done: false}
console.log(iterator.next()); // → {value: 20, done: false}
console.log(iterator.next()); // → {value: 30, done: false}
console.log(iterator.next()); // → {value: undefined, done: true}

对象的迭代器通过Object.keys()方法获取属性名数组,将其赋值给values常量,同时定义一个默认值为0的计数器。当迭代器开始执行时,会返回一个包含next()方法的对象。该方法会返回包含value和done的对象,value为下一迭代值,done为布尔值,表示迭代器是否到达终点。

上述实现方式还是过于复杂,可以通过generator函数简化:

const collection = {
a: 10,
b: 20,
c: 30,
[Symbol.iterator]: function * () {
for (let key in this) {
yield this[key];
}
}
}; const iterator = collection[Symbol.iterator](); console.log(iterator.next()); // → {value: 10, done: false}
console.log(iterator.next()); // → {value: 20, done: false}
console.log(iterator.next()); // → {value: 30, done: false}
console.log(iterator.next()); // → {value: undefined, done: true}

在该generator函数中,利用for in循环枚举生成属性值。结果与前面的示例完全相同,但是要短得多。

迭代器的缺点是不适合表示异步数据源。ES2018的解决方案是异步迭代器和异步迭代。异步迭代器与传统迭代器的不同之处在于,它没有返回{value, done}形式的普通对象,而是返回一个Promise,其resolve返回{value, done}对象。一个可异步迭代对象中包含Symbol.asyncIterator属性(而不是Symbol.iterator),其功能为返回一个异步迭代器。

如下示例应该会使这一点更清楚:

const collection = {
a: 10,
b: 20,
c: 30,
[Symbol.asyncIterator]() {
const values = Object.keys(this);
let i = 0;
return {
next: () => {
return Promise.resolve({
value: this[values[i++]],
done: i > values.length
});
}
};
}
}; const iterator = collection[Symbol.asyncIterator](); console.log(iterator.next().then(result => {
console.log(result); // → {value: 10, done: false}
})); console.log(iterator.next().then(result => {
console.log(result); // → {value: 20, done: false}
})); console.log(iterator.next().then(result => {
console.log(result); // → {value: 30, done: false}
})); console.log(iterator.next().then(result => {
console.log(result); // → {value: undefined, done: true}
}));

注意,promise+迭代器并不能代替异步迭代器。虽然一个普通的同步迭代器可以异步地确定值,但是它仍然需要同步地确定“完成”的状态。

当然,您同样可以使用generator函数简化该过程,如下所示:

const collection = {
a: 10,
b: 20,
c: 30,
[Symbol.asyncIterator]: async function * () {
for (let key in this) {
yield this[key];
}
}
}; const iterator = collection[Symbol.asyncIterator](); console.log(iterator.next().then(result => {
console.log(result); // → {value: 10, done: false}
})); console.log(iterator.next().then(result => {
console.log(result); // → {value: 20, done: false}
})); console.log(iterator.next().then(result => {
console.log(result); // → {value: 30, done: false}
})); console.log(iterator.next().then(result => {
console.log(result); // → {value: undefined, done: true}
}));

同样,异步迭代执行后会返回一个包含next()方法的对象。调用next()会返回一个包含{value, done}的对象,而value值则变为一个promise对象

在可迭代对象上迭代的一个简单方法是使用for of,但由于异步迭代对象的value和done并不是同步指定的,因此for of并不适用。基于此,ES2018提供了for await of方法。让我们来看一个例子:

const collection = {
a: 10,
b: 20,
c: 30,
[Symbol.asyncIterator]: async function * () {
for (let key in this) {
yield this[key];
}
}
}; (async function () {
for await (const x of collection) {
console.log(x);
}
})(); // logs:
// → 10
// → 20
// → 30

在本代码中,for await of语句隐式调用了Symbol.asyncIterator方法。在每次循环时,都会调用迭代器的next()方法,该方法返回一个promise。promise对象的value属性将被读入x变量。循环继续,直到返回对象的done属性的值为true。

注意:for await of语句仅在异步生成器和异步函数中有效。违反此规则会报SyntaxError错误。

next()方法可能返回一个包含rejects的promise。要优雅地处理,你可以把for await of用try catch包裹,如下所示:

const collection = {
[Symbol.asyncIterator]() {
return {
next: () => {
return Promise.reject(new Error('Something went wrong.'))
}
};
}
}; (async function() {
try {
for await (const value of collection) {}
} catch (error) {
console.log('Caught: ' + error.message);
}
})(); // logs:
// → Caught: Something went wrong.

异步迭代器支持

 Chrome   Firefox   Safari   Edge 
63  57   12  No 

 Chrome 

 Android 

 Firefox

 Android 

 iOS

 Safari 

 Edge

 Mobile 

 Samsung

 Internet  

 Android

 Webview 

63 57 12 No 8.2 63

Node.js:

  • 8.0.0 (需要 --harmony\ async\ iteration标志)

  • 8.3.0 (完全支持)

Promise.prototype.finally


ES2018的另一个令人兴奋的新特性是finally()方法。几个JavaScript库以前实现过类似的方法,这在许多情况下都很有用。这鼓励Ecma技术委员会正式将finally()添加到规范中。无论promise的结果如何,finally()方法中的代码都会执行。让我们看一个简单的例子:

fetch('https://www.google.com')
.then((response) => {
console.log(response.status);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
document.querySelector('#spinner').style.display = 'none';
});

无论操作是否成功,当您需要在操作完成后进行一些清理时,finally()方法就派上用场了。在这段代码中,finally()方法在请求数据之后隐藏loading,无论请求是否成功。

您可以使用promise来实现相同的结果,使用then(func, func)而不是promise.finally(func),但是你必须在fulfillment handler和rejection handler中重复相同的代码,或者为它声明一个变量:

fetch('https://www.google.com')
.then((response) => {
console.log(response.status);
})
.catch((error) => {
console.log(error);
})
.then(final, final); function final() {
document.querySelector('#spinner').style.display = 'none';
}

与then()和catch()一样,finally()方法总是返回一个promise,因此可以链接更多的方法。通常,您希望使用finally()作为最后一个链,但是在某些情况下,例如在发出HTTP请求时,最好将另一个catch()链接起来,以处理finally()中可能出现的错误。

Promise.prototype.finall支持

 Chrome   Firefox   Safari   Edge 
63  58   11.1  18 

 Chrome 

 Android 

 Firefox

 Android 

 iOS

 Safari 

 Edge

 Mobile 

 Samsung

 Internet  

 Android

 Webview 

63 58 11.1 No 8.2 63

Node.js:

  • 10.0.0 (完全支持)

新的正则表达式特性


ES2018为正则表达式添加了四个新特性,进一步提高了JavaScript的字符串处理能力。这些特点如下:

  • s (dotAll) 标志

  • 命名捕获组

  • Lookbehind 后行断言

  • Unicode属性转义

s (dotAll) 标志

点(.)是正则表达式模式中的一个特殊字符,它匹配除换行符(如换行符(\n)或回车符(\r)之外的任何字符。匹配所有字符(包括换行符)的一种方法是使用一个包含两个短字符的字符类,比如[\d\D]。这个表达式查询数字(\d)或非数字(\D)字符。因此,它匹配任何字符:

console.log(/one[\d\D]two/.test('one\ntwo'));    // → true

ES2018引入了一种模式,在这种模式中,点(.)可以用来实现相同的结果。通过在原正则表达式基础上添加s表示,可以激活该模式:

console.log(/one.two/.test('one\ntwo'));     // → false
console.log(/one.two/s.test('one\ntwo')); // → true

使用标志位来定义新行为的好处是向后兼容性。因此,使用点字符的现有正则表达式模式不受影响。

命名捕获组

在一些正则表达式模式中,使用数字进行匹配可能会令人混淆。例如,使用正则表达式/(\d{4})-(\d{2})-(\d{2})/来匹配日期。因为美式英语中的日期表示法和英式英语中的日期表示法不同,所以很难区分哪一组表示日期,哪一组表示月份:

const re = /(\d{4})-(\d{2})-(\d{2})/;
const match= re.exec('2019-01-10'); console.log(match[0]); // → 2019-01-10
console.log(match[1]); // → 2019
console.log(match[2]); // → 01
console.log(match[3]); // → 10

ES2018引入了使用(?…)语法的命名捕获组。因此,匹配日期的模式可以用一种不那么模棱两可的方式来写:

const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = re.exec('2019-01-10'); console.log(match.groups); // → {year: "2019", month: "01", day: "10"}
console.log(match.groups.year); // → 2019
console.log(match.groups.month); // → 01
console.log(match.groups.day); // → 10

你可以在一个正则表达式中使用\k语法重复调用名称捕获组。例如,要在一个句子中找到连续重复的单词,可以使用/\b(?\w+)\s+\k\b/:

const re = /\b(?<dup>\w+)\s+\k<dup>\b/;
const match = re.exec('Get that that cat off the table!'); console.log(match.index); // → 4
console.log(match[0]); // → that that

要将命名捕获组插入replace()方法的替换字符串中,需要使用$构造。例如:

const str = 'red & blue';

console.log(str.replace(/(red) & (blue)/, '$2 & $1'));
// → blue & red console.log(str.replace(/(?<red>red) & (?<blue>blue)/, '$<blue> & $<red>'));
// → blue & red

Lookbehind后行断言

ES2018将lookbehind后行断言引入JavaScript,以前JavaScript只支持前行断言。后行断言由(?<=…)表示,代表字符串中的一个位置,紧接该位置之前的字符序列能够匹配pattern。例如,如果您想匹配以美元、英镑或欧元表示的产品的价格,而不需要捕获货币符号,您可以使用/(?<=\$|£|€)\d+(.\d*)?/:

const re = /(?<=\$|£|€)\d+(\.\d*)?/;

console.log(re.exec('199'));
// → null console.log(re.exec('$199'));
// → ["199", undefined, index: 1, input: "$199", groups: undefined] console.log(re.exec('€50'));
// → ["50", undefined, index: 1, input: "€50", groups: undefined]

还有一种负向后行断言,表示为(?<!…),代表字符串中的一个位置,紧接该位置之前的字符序列不能匹配pattern。例如,如果模式/(?<!un)available/没有“un”前缀,那么它将匹配可用的单词:

const re = /(?<!un)available/;

console.log(re.exec('We regret this service is currently unavailable'));
// → null console.log(re.exec('The service is available'));
// → ["available", index: 15, input: "The service is available", groups: undefined]

Unicode 属性转义

ES2018提供了一种新的转义序列类型,称为Unicode属性转义,可以匹配所有的Unicode。你可以使用\p{Number}来匹配所有的Unicode数字,例如,假设你想匹配的Unicode字符㉛字符串:

const str = '㉛';

console.log(/\d/u.test(str));    // → false
console.log(/\p{Number}/u.test(str)); // → true

同样的,你可以使用\p{Alphabetic}来匹配所有的Unicode单词字符:

const str = 'ض';

console.log(/\p{Alphabetic}/u.test(str));     // → true

// the \w shorthand cannot match ض
console.log(/\w/u.test(str)); // → false

同样有一个负向的Unicode属性转义模板 \P{...}:

console.log(/\P{Number}/u.test('㉛'));    // → false
console.log(/\P{Number}/u.test('ض')); // → true console.log(/\P{Alphabetic}/u.test('㉛')); // → true
console.log(/\P{Alphabetic}/u.test('ض')); // → false

除了字母和数字之外,Unicode属性转义中还可以使用其他一些属性。您可以在现行规范中找到受支持的Unicode属性列表。

新正则表达式支持

  Chrome Firefox Safari Edge
s (dotAll) Flag 62 No 11.1 No
Named Capture Groups 64 No 11.1 No
Lookbehind Assertions 62 No No No
Unicode Property Escapes 64 No 11.1 No
 

Chrome

(Android)

Firefox

(Android)

iOS

Safari

Edge

Mobile

Samsung

Internet

Android

Webview

s (dotAll) Flag 62 No 11.3 No 8.2 62

Named

Capture

Groups

64 No 11.3 No No 64

Lookbehind

Assertions

62 No No No 8.2 62

Unicode

Property

Escapes

64 No 11.3 No No 64

Node.js:

  • 8.3.0 (需要 --harmony 标志)

  • 8.10.0 (支持 s (dotAll) 标志和后行断言)

  • 10.0.0 (全部支持)

模板文字修订

当模板文字前紧跟着一个表达式时,它被称为带标记的模板文字。当您想用函数解析模板文字时,带标记的模板就派上用场了。考虑下面的例子:

function fn(string, substitute) {
if(substitute === 'ES6') {
substitute = 'ES2015'
}
return substitute + string[1];
} const version = 'ES6';
const result = fn${version} was a major update; console.log(result); // → ES2015 was a major update

在这段代码中,模板文字调用了一个标记表达式(函数):修改字符串中的变量部分。

在ES2018之前,标记模板文字具有与转义序列相关的语法限制。后跟特定字符序列的反斜杠被视为特殊字符:十六进制转义的\x、unicode转义的\u和八进制转义的\u。因此,像“C:\xxx\uuu”或“\ubuntu”这样的字符串被解释器认为是无效的转义序列,并且会抛出一个SyntaxError。

ES2018从标记模板中移除这些限制,并不是抛出错误,而是将无效的转义序列表示为undefined:

function fn(string, substitute) {
console.log(substitute); // → escape sequences:
console.log(string[1]); // → undefined
} const str = 'escape sequences:';
const result = fn${str} \ubuntu C:\xxx\uuu;

注意,在常规模板文字中使用非法转义序列仍然会导致错误:

const result = \ubuntu;
// → SyntaxError: Invalid Unicode escape sequence

模板文字修订支持

 Chrome   Firefox   Safari   Edge 
63  58   11.1  18 

 Chrome 

 Android 

 Firefox

 Android 

 iOS

 Safari 

 Edge

 Mobile 

 Samsung

 Internet  

 Android

 Webview 

63 58 11.1 No 8.2 63

Node.js:

  • 8.3.0 (需要 --harmony 标志)

  • 8.10.0 (全部支持)

总结

我们已经很好地了解了ES2018中引入的几个关键特性,包括异步迭代、rest/spread属性、Promise.prototype.finally()以及正则表达式新特性的添加。尽管一些浏览器厂商还没有完全实现其中的一些特性,但是仍然可以用诸如Babel之类转义器进行使用。

ECMAScript正在快速发展,经常会有新特性被引入,有兴趣可以查询已完成提案列表,了解全部最新内容。有没有什么新功能让你特别兴奋?在评论中分享吧!

ES2018新特性(译文)的更多相关文章

  1. [译文]React v16(新特性)

    [译文]React v16(新特性) 查看原文内容 我们很高兴的宣布React v16.0发布了! 这个版本有很多长期被使用者期待的功能,包括: fragments (返回片段类型) error bo ...

  2. EXTJS 6 新特性(译文)

    Extjs 新特性 简介 使用extjs,sencha 团队开发一个简单的框架,可以为创建在任何类型设备上运行的应用,从手机端到平板电脑再到桌面应用,你将能够产生最佳的用户体验,编写更少的代码量,结合 ...

  3. Android Studio3.0 新特性 ~ New Features in Android Studio Preview (译文)

    原文地址:https://developer.android.google.cn/studio/preview/features/index.html 最新Android Studio版本是Andro ...

  4. 译文《全新首发JDK 16全部新特性》

    封面:洛小汐 译者:潘潘 JDK 8 的新特性都还没摸透,JDK 16 的新特性就提着刀来了. 郑重申明: 第一次冒险翻译专业领域的文献,可想而知,效果特别糟糕.一般翻译文献特别是 技术专业领域 的内 ...

  5. 深入理解JVM内幕:从基本结构到Java 7新特性

    转自:http://www.importnew.com/1486.html 每个Java开发者都知道Java字节码是执行在JRE((Java Runtime Environment Java运行时环境 ...

  6. JAVA JDK1.5-1.9新特性

    1.51.自动装箱与拆箱:2.枚举(常用来设计单例模式)3.静态导入4.可变参数5.内省 1.61.Web服务元数据2.脚本语言支持3.JTable的排序和过滤4.更简单,更强大的JAX-WS5.轻量 ...

  7. java8 新特性

    [转载]:http://www.importnew.com/11908.html 本文由 ImportNew - 刘 家财 翻译自 javacodegeeks.欢迎加入翻译小组.转载请见文末要求. 编 ...

  8. ios7新特性实践

    一 iOS 7 新特性:视图控制器切换API 二 iOS 7系列译文:认识 TextKit 三 iOS 7系列译文:iOS7的多任务处理 四 iOS7 最佳实践:一个天气应用案例(上) 五 iOS7 ...

  9. 这可能是史上最好的 Java8 新特性 Stream 流教程

    本文翻译自 https://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ 作者: @Winterbe 欢迎关注个人微信公众 ...

随机推荐

  1. JDK 新特性

    Jdk8新特性 一:接口默认方法和静态方法: 我们可以在接口中定义默认方法,使用default关键字,并提供默认的实现.所有实现这个接口的类都会接受默认方法的实现,除非子类提供的自己的实现. 我们还可 ...

  2. CSS绝对定位元素居中的几种方法

    转载自-CSS居中绝对https://www.cnblogs.com/skura23/p/6530556.html 作者:PajamaCat 1,div宽度未知1 <body> <d ...

  3. 「Algospot」龙曲线DRAGON

    一道考验思维的好题,顺便总结求第k大问题的常规思路: 传送门:$>here<$ 题意 给出初始串FX,每分形一次所有X替换为X+YF,所有Y替换为FX-Y.问$n$代字符串第$p$位起长度 ...

  4. 洛谷P5155 [USACO18DEC]Balance Beam(期望,凸包)

    你以为它是一个期望dp,其实它是一个凸包哒! 设平衡木长度为\(L\),把向右走平衡木那个式子写一下: \[dp[i]=\frac{dp[i+1]+dp[i-1]}{2}\] 然后会发现这是一个等差数 ...

  5. Docke--Dockerfile 构建LNMP环境

    Dockerfile 构建nginx并结合php 1.构建基础镜像 先构建一个基础镜像,添加repo的环境和编译的环境,而centos镜像就是初始的官方镜像,后面构建php.nginx.mysql都使 ...

  6. x86汇编语言实践(3)

    0 写在前面 为了更深入的了解程序的实现原理,近期我学习了IBM-PC相关原理,并手工编写了一些x86汇编程序. 在2017年的计算机组成原理中,曾对MIPS体系结构及其汇编语言有过一定的了解,考虑到 ...

  7. 微信小程序之:wepy(二)

    一大堆实例:人家的博客园 代码规范: 1.尽量使用驼峰命名,避免使用$开头,框架内建属性都已$开头,可以使用this直接调用. 2.入口文件.页面.组件后缀都为.wpy. 3.使用ES6语法开发. 4 ...

  8. scws安装

    mkdir scws cd scws wget http://www.xunsearch.com/scws/down/scws-1.2.3.tar.bz2 tar xvjf scws-.tar.bz2 ...

  9. TCP/IP详解(包含ack,seq)

    前言 个人认为在web开发中,对于TCP/IP协议的理解是首当其冲的,在大多数框架的冲击下,使我们淡化了对于TCP/IP协议的理解. 理解好TCP/IP对于每个web开发者都是很有必要的. TCP/I ...

  10. postman接口测试笔记

    1.GET 和POST 的区别: GET 使用URL 或Cookie 传参,而POST将数据放在Body 中. GET的URL 在长度上会有限制,而POST没有. POST比GET相对安全,因为在地址 ...