ES2018新特性(译文)
原文链接: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新特性(译文)的更多相关文章
- [译文]React v16(新特性)
[译文]React v16(新特性) 查看原文内容 我们很高兴的宣布React v16.0发布了! 这个版本有很多长期被使用者期待的功能,包括: fragments (返回片段类型) error bo ...
- EXTJS 6 新特性(译文)
Extjs 新特性 简介 使用extjs,sencha 团队开发一个简单的框架,可以为创建在任何类型设备上运行的应用,从手机端到平板电脑再到桌面应用,你将能够产生最佳的用户体验,编写更少的代码量,结合 ...
- Android Studio3.0 新特性 ~ New Features in Android Studio Preview (译文)
原文地址:https://developer.android.google.cn/studio/preview/features/index.html 最新Android Studio版本是Andro ...
- 译文《全新首发JDK 16全部新特性》
封面:洛小汐 译者:潘潘 JDK 8 的新特性都还没摸透,JDK 16 的新特性就提着刀来了. 郑重申明: 第一次冒险翻译专业领域的文献,可想而知,效果特别糟糕.一般翻译文献特别是 技术专业领域 的内 ...
- 深入理解JVM内幕:从基本结构到Java 7新特性
转自:http://www.importnew.com/1486.html 每个Java开发者都知道Java字节码是执行在JRE((Java Runtime Environment Java运行时环境 ...
- JAVA JDK1.5-1.9新特性
1.51.自动装箱与拆箱:2.枚举(常用来设计单例模式)3.静态导入4.可变参数5.内省 1.61.Web服务元数据2.脚本语言支持3.JTable的排序和过滤4.更简单,更强大的JAX-WS5.轻量 ...
- java8 新特性
[转载]:http://www.importnew.com/11908.html 本文由 ImportNew - 刘 家财 翻译自 javacodegeeks.欢迎加入翻译小组.转载请见文末要求. 编 ...
- ios7新特性实践
一 iOS 7 新特性:视图控制器切换API 二 iOS 7系列译文:认识 TextKit 三 iOS 7系列译文:iOS7的多任务处理 四 iOS7 最佳实践:一个天气应用案例(上) 五 iOS7 ...
- 这可能是史上最好的 Java8 新特性 Stream 流教程
本文翻译自 https://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ 作者: @Winterbe 欢迎关注个人微信公众 ...
随机推荐
- styled-components解决全局样式'injectGlobal' 废除的问题
最新版的 styled-components v4 已经将原有的 injectGlobal() 方法替换成了 createGlobalStyle() ,而且用法也和之前的 injectGlobal 方 ...
- C#中字符串转日期类型
1,yyyyMMdd DateTime date = DateTime.ParseExact(", "yyyyMMdd", System.Globalization.Cu ...
- python一(字符串,字典)
list操作 name = ['小王','小米','小张','王强','张三','李四'] name.append('黄霑')#添加元素在最后一个 name.insert(,'王五')#指定下标插入元 ...
- django rest framework serializers
django rest framework serializers序列化 serializers是将复杂的数据结构变成json或者xml这个格式的 serializers有以下几个作用:- 将qu ...
- BlockQueue 解析
生产者.消费者模式 https://www.jianshu.com/p/024a36b83099
- LIS ZOJ - 4028
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4028 memset超时 这题竟然是一个差分约束 好吧呢 对于每一个a[i] ...
- 使用 mysqltuner 检测 mysql 稳定性
github : https://github.com/major/MySQLTuner-perl MySQLTuner是一个用Perl编写的脚本,它可以帮助您进行MySQL配置,并提出增强性能和稳定 ...
- MT【332】椭圆正交变换
(2018河南数学联赛解答10) 已知方程$17x^2-16xy+4y^2-34x+16y+13=0$表示椭圆,求它的对称中心和对称轴. 解:设对称中心为$(a,b)$,显然$A(1,1),B(1,- ...
- 2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(../Frameworks/caching_sha2_password.so, 2): image not found
mac本地安装mysql后,navicat连接报错: - Authentication plugin ): image not found 解决方法 在控制台登陆后重新改下密码即可 ALTER USE ...
- Python3 找不到库
import sys sys.path.append('/usr/local/lib64/python3.6/site-packages')sys.path.append('/usr/local/li ...