前言

前段时间整理了ES5的读书笔记:《你可能遗漏的JS知识点(一)》《你可能遗漏的JS知识点(二)》,现在轮到ES6了,总共分为四篇,以便于知识点的梳理和查看,本篇内容包括:

  • 一、let和const
  • 二、解构赋值
  • 三、字符串扩展
  • 四、数值扩展
  • 五、正则扩展
  • 六、Symbol

本文笔记也主要是根据阮一峰老师的《ECMAScript 6 入门》和平时的理解进行整理的,希望对你有所帮助,喜欢的就点个赞吧!

一、let和const

1.1 let

1.声明变量的方法有6种:var、 function、 let、 const、 import 、class。

2.函数内let声明的变量不能提前使用,没有变量提升。

3.暂时性死区:在代码块内,使用let命令声明变量之前,该变量都是不可用的,只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响:

// 例一:
var tmp = 123;
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError let tmp; // TDZ结束
console.log(tmp); // undefined tmp = 123;
console.log(tmp); // 123
} // 例二:
function bar(x = y, y = 2) {
return [x, y];
} bar(); // 报错,会出现暂时性死区,从左到右,x=y时y还未声明 // 例三:
function bar(x = 2, y = x) {
return [x, y];
}
bar(); // [2, 2] 反过来就可以,此时x已声明 // 例四:
var x = x; // 不报错
let x = x; // 报错 ReferenceError: x is not defined 变量x的声明语句还没有执行完成前,就去取x的值,导致报错 // 例五:
function func(arg) {
let arg; // 报错 不能在同一作用域声明同一个变量
} function func(arg) {
{
let arg; // 不报错 因为不在同一作用域
}
}

4.for循环里面是父级作用域,块里面是单独的子作用域:

for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc

5.顶层对象:在浏览器环境指的是window对象,在Node指的是global对象。

在ES5之中,顶层对象的属性与全局变量是等价的:

var a = 1;
window.a // 1
// 如果在Node的REPL环境,可以写成global.a
// 或者采用通用方法,写成 this.a

在ES6中,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性:

let b = 1;
window.b // undefined
// 这说明从ES6开始,全局变量将逐步与顶层对象的属性脱钩

6.块作用域函数:不建议这样声明函数,应该使用函数表达式,避免函数提升的兼容性:

// 在块内声明函数
{
foo();
function foo() {}
}
foo(); // ReferenceError

1.2 const

1.const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。

二、解构赋值

从数组和对象中提取值,对变量进行赋值,称为解构。

2.1 数组的解构

1.数组解构例子:

// 例一:
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3 // 例二:
let [a, b] = [1, [2]];
a // 1
b // [2] // 例三:
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 // []

2.允许指定默认值:

let [foo = true] = [];
foo // true let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

ES6内部使用严格相等运算符(===)来判断一个位置是否有值,所以只有当一个数组成员严格等于undefined,默认值才会生效:

let [x = 1] = [undefined];
x // 1 let [x = 1] = [null];
x // null

3.应用:

①交换变量的值:

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

②从函数返回多个值:

function example() {
return [1, 2, 3];
}
let [a, b, c] = example();

③解构结合展开/收集:

var a = [2,3,4];
var [ b, ...c ] = a;
console.log( b, c ); // 2 [3,4]

④默认值可以引用解构赋值的其他变量,但该变量必须已经声明:

let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2]; // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ReferenceError: y is not defined

2.2 对象的解构

1.对象的解构与数组有一个重要的不同:数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值:

let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb" // 如果变量名与属性名不一致,必须写成下面这样:
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa" let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'

2.对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量;真正被赋值的是后者,而不是前者:

①匹配模式:

let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined

以上的foo是匹配的模式,baz才是变量,真正被赋值的是变量baz,而不是模式foo。

②对象简写的本质:

var [ a, b, c ] = [1, 2, 3];
var { x: x, y: y, z: z } = { x: 1, y: 2, z: 3};

对象简写后就是{x, y, z} = {x: 1, y: 2, z: 3}; 其实就是省略了"x:"这个部分。

③如果要不同名的对象属性:

var { x: a, y: b, z: b } = { x: 1, y: 2, z: 3};
console.log(a, b, c); // 1, 2, 3
console.log(x, y, z); // referenceError

④解构变量的声明:

// 先声明变量再解构
var a, b, c, x, y, z;
[a,b,c] = [1, 2, 3]; // 同时声明和解构
var [a,b,c] = [1, 2, 3]; // 如果不声明,则对象需要用括号括起来,否则会被当成一个块,而不是对象
var a, b, c, x, y, z;
( { x, y, z } = { x: 1, y: 2, z: 3} )

⑤易错:

let {foo: {bar}} = {baz: 'baz'};  // 报错,因为首先foo这时等于undefined,再取子属性bar就会报错

3.应用:

①返回一个对象:

function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();

②重复赋值:

var { a: X, a: Y } = { a: 1 };
X; // 1
Y; // 1 var { a: { x: X, x: Y }, a } = { a: { x: 1 } };
X; // 1
Y; // 1
a; // { x: 1 } ( { a: X, a: Y, a: [ Z ] } = { a: [ 1 ] } );
X.push( 2 );
Y[0] = 10;
X; // [10,2] // 因为都是同一个引用,所以会同时改变为10
Y; // [10,2]
Z; // 1

③链式赋值:

var o = { a:1, b:2, c:3 },
p = [4,5,6],
a, b, c, x, y, z;
( {a} = {b,c} = o );
[x,y] = [z] = p;
console.log( a, b, c ); // 1 2 3
console.log( x, y, z ); // 4 5 4 z也是4

2.3 函数参数的解构

1.例子:

// 例一:
function add([x, y]){
return x + y;
} add([1, 2]); // 3 // 例二:
[[1, 2], [3, 4]].map(([a, b]) => a + b); // [ 3, 7 ] // 例三:参数默认值
function move({x = 0, y = 0} = {}) {
return [x, y];
} move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]

2.应用:

①函数参数的定义:

//参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]); //参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});

②解构默认值+参数默认值:

function f6({ x = 10 } = {}, { y } = { y: 10 }) {
console.log( x, y );
}
f6(); // 10 10
f6( {}, {} ); // 10 undefined

③提取JSON数据:

let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
}; let { id, status, data: number } = jsonData; console.log(id, status, number); // 42, "OK", [867, 5309]

④遍历 Map 结构:

// 获取键名
for (let [key] of map) {
// ...
} // 获取键值
for (let [,value] of map) {
// ...
}

2.4 字符串解构

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

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

2.类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值:

let {length : len} = 'hello';   // 相当于 let {length: len} = {length: 5}
len // 5

2.5 数值和布尔值的解构

1.数值:

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

2.布尔值:

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

3.解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错:

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

三、字符串扩展

1.包含:includes()、startsWith()、endsWith()

  • includes():返回布尔值,表示是否找到了参数字符串。
  • startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
  • endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
let s = 'Hello world!';

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

这三个方法都支持第二个参数,表示开始搜索的位置:

let s = 'Hello world!';

s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true 第二参数表示针对的是前5个字符
s.includes('Hello', 6) // false

2.重复:repeat()

返回一个新字符串,表示将原字符串重复n次:

'x'.repeat(3)         // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // "" 'na'.repeat(2.9) // "nana" 如果是小数,会被取整
'na'.repeat(Infinity) // RangeError
'na'.repeat(-1) // RangeError 负数报错
'na'.repeat(-0.9) // "" 0~-1会被取整为0
'na'.repeat(NaN) // "" NaN等同为0
'na'.repeat('na') // "" 字符串会先转换为数字,转化了NaN,然后为0
'na'.repeat('3') // "nanana"

3.补全长度:padStart(),padEnd()

返回新的字符串,不会改变原字符串:

'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax' 'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'

①如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串:

'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'

②如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串:

'abc'.padStart(10, '0123456789')  // '0123456abc'

③如果省略第二个参数,默认使用空格补全长度:

'x'.padStart(4) // '   x'
'x'.padEnd(4) // 'x '

用途:

①补全指定位数:

'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"

②提示字符串格式:

'12'.padStart(10, 'YYYY-MM-DD')    // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"

3.模板字符串:``

①大括号${}内部可以放入任意的表达式,可以进行运算,如果得到的不是字符串,会调用toString()方法,且可以直接放字符串:${'hello'},还可以嵌套使用,以及引用对象属性:

let x = 1;
let y = 2; `${x} + ${y} = ${x + y}` // "1 + 2 = 3" `${x} + ${y * 2} = ${x + y * 2}` // "1 + 4 = 5" let obj = {x: 1, y: 2};
`${obj.x + obj.y}` // "3"

②模板字符串之中还能调用函数:

function fn() {
return "Hello World";
} `foo ${fn()} bar` // foo Hello World bar

③``类似于IIFE,会自行执行解析内部的变量/表达式,空格、换行、缩进都会被保存:

var text =
`Now is the time for all good men
to come to the aid of their
country!`; console.log( text ); // 换行会被保存
// Now is the time for all good men
// to come to the aid of their
// country! `A very ${upper( "warm" )} welcome` // 可插入表达式

④运行函数:

alert`123`
// 等同于
alert(123)

4.可精确计算字符串长度:

var gclef = "一个长度用普通方法计算得不到2的特殊图形符号";
[...gclef].length; // 1 借助扩展运算符
Array.from( gclef ).length; // 1 借助Array.from

5.扩展了码点和字节的精确计算。

6.matchAll()返回一个正则表达式在当前字符串的所有匹配。

四、数值扩展

1.Number.isFinite()、Number.isNaN()、Number.isInteger():

①Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity,如果参时不是数值,一律返回false:

Number.isFinite(NaN);       // false
Number.isFinite(15); // true
Number.isFinite(Infinity); // false

②Number.isNaN()用来检查一个值是否为NaN,注意与以前的isNaN()进行区别:

Number.isNaN(NaN)      // true
isNaN( 'NaN' ); // true
Number.isNaN( 'NaN' ) // false 已修正

与传统的全局方法isFinite()和isNaN()的区别在于,传统方法先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,Number.isFinite()对于非数值一律返回false, Number.isNaN()只有对于NaN才返回true,非NaN一律返回false。

③Number.isInteger()用来判断一个数值是否为整数(javaScript的数字值永远都是浮点数,所以判断整数,其实是判断小数部分是否为0):

Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false

整数范围:-253到253之间(不含两个端点),超过这个范围,无法精确表示这个值,Number.isSafeInteger()用来判断一个整数是否落在这个范围之内:

Math.pow(2, 53) === Math.pow(2, 53) + 1  // true

2.ES6将全局方法parseInt()和parseFloat()移植到Number对象上面,行为完全保持不变:

// ES5的写法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45 // ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45 Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true

3.Number.EPSILON

Number.EPSILON === Math.pow(2, -52)  // true

4.Math上的方法:

Math.trunc()用于去除一个数的小数部分,返回整数部分:

Math.trunc(4.1)     //  4
Math.trunc(4.9) // 4
Math.trunc(-4.1) // -4
Math.trunc(-4.9) // -4
Math.trunc(-0.1234) // -0
Math.trunc(true) // 1
Math.trunc(false) // 0
Math.trunc(null) // 0
Math.trunc(NaN); // NaN
Math.trunc('foo'); // NaN
Math.trunc(); // NaN
Math.trunc(undefined) // NaN

Math.sign()用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值,它会返回五种值:

  • 参数为正数,返回+1;
  • 参数为负数,返回-1;
  • 参数为 0,返回0;
  • 参数为-0,返回-0;
  • 其他值,返回NaN。

5.前缀0b(或0B)表示二进制,0o(或0O)表示八进制:

0b111110111 === 503   // true
0o767 === 503 // true

6.指数运算符(**): 右结合

2 ** 2  // 4
2 ** 3 // 8 2 ** 3 ** 2 // 512 相当于 2 ** (3 ** 2) let a = 1.5;
a **= 2; // 等同于 a = a * a;

五、正则扩展

1.修饰符:

①unicode标识u:处理大于\uFFFF的 Unicode 字符。

②定点标识y(sticky)“粘连”:作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始,不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始:

var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y; r1.exec(s) // ["aaa"]
r1.exec(s) // ["aa"] r2.exec(s) // ["aaa"]
r2.exec(s) // null

2.单单一个y修饰符对match方法,只能返回第一个匹配,必须与g修饰符联用,才能返回所有匹配:

'a1a2a3'.match(/a\d/y)  // ["a1"]
'a1a2a3'.match(/a\d/gy) // ["a1", "a2", "a3"]

3.s修饰符,称为dotAll模式,即点(dot)代表一切字符:

以前.点不能匹配以下:

  • U+000A 换行符(\n)
  • U+000D 回车符(\r)
  • U+2028 行分隔符(line separator)
  • U+2029 段分隔符(paragraph separator)

但如果加上s修饰符,则可以匹配任意单个字符:

/foo.bar/.test('foo\nbar')  // false
/foo.bar/s.test('foo\nbar') // true

4.flags属性:

var re = /foo/ig;
re.flags; // "gi" 默认顺序为"gimuy" new RegExp(/abc/ig, 'i').flags // 'i' 原有正则对象的修饰符是ig,它会被第二个参数i覆盖

5.字符串对象共有 4 个方法,可以使用正则表达式:match()、replace()、search()和split()。

ES6 将这 4 个方法,在语言内部全部调用RegExp的实例方法,从而做到所有与正则相关的方法,全都定义在RegExp对象上:

  • String.prototype.match 调用 RegExp.prototype[Symbol.match]
  • String.prototype.replace 调用 RegExp.prototype[Symbol.replace]
  • String.prototype.search 调用 RegExp.prototype[Symbol.search]
  • String.prototype.split 调用 RegExp.prototype[Symbol.split]

6.具名组匹配: ?<组名>

const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // 1999
const month = matchObj.groups.month; // 12
const day = matchObj.groups.day; // 31

六、Symbol

1.表示独一无二的值,是一种类似于字符串的数据类型(不是引用类型),通过Symbol函数生成(不能使用new命令),可以保证不会与对象中的其他属性名产生冲突。

let s = Symbol();
typeof s // "symbol"

Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分:

let s1 = Symbol('foo');
let s2 = Symbol('bar'); s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"

如果 Symbol 的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,然后才生成一个 Symbol 值:

const obj = {
toString() {
return 'abc';
}};
const sym = Symbol(obj);
sym // Symbol(abc)

Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的:

// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false // 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false

Symbol值不能与其他类型的值进行运算,会报错,可显式转换类型后再运算:

let sym = Symbol('My symbol');
"your symbol is " + sym // TypeError: can't convert symbol to string //转为字符串:
let sym = Symbol('My symbol'); String(sym) // 'Symbol(My symbol)'
sym.toString()+"123" // 'Symbol(My symbol)123' //转为布尔值:
Boolean(sym) // true //但不能转为数值:
Number(sym) // TypeError

2.作为属性名,是公开属性:要使用方括号,使用属性时也是,不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回,但也不是私有属性,Object.getOwnPropertySymbols方法可以获取指定对象的所有 Symbol 属性名:

let mySymbol = Symbol();

// 第一种写法
let a = {};
a[mySymbol] = 'Hello!'; // 第二种写法
let a = {
[mySymbol]: 'Hello!'
}; // 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' }); // 以上写法都得到同样结果
a[mySymbol] // "Hello!"

不能用点运算符:

const mySymbol = Symbol();
const a = {}; a.mySymbol = 'Hello!';
a['mySymbol'] // "Hello!"
a[mySymbol] // undefined

3.也可作为属性值:定义一组常量,保证这组常量的值都是不相等的。

const log = {};

log.levels = {
DEBUG: Symbol('debug'),
INFO: Symbol('info'),
WARN: Symbol('warn')
};
console.log(log.levels.DEBUG, 'debug message');
console.log(log.levels.INFO, 'info message');

4.遍历Symbol属性:

①Object.getOwnPropertySymbols()返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值:

const obj = {};
let a = Symbol('a');
let b = Symbol('b'); obj[a] = 'Hello';
obj[b] = 'World'; const objectSymbols = Object.getOwnPropertySymbols(obj); objectSymbols // [Symbol(a), Symbol(b)]

②Reflect.ownKeys()返回所有类型的键名,包括常规键名和 Symbol 键名:

let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
}; Reflect.ownKeys(obj) // ["enum", "nonEnum", Symbol(my_key)]

5.Symbol.for()接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值,它登记的名字,是全局环境的,可以在不同的iframe或service worker中取到同一个值:

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo'); s1 === s2 // true Symbol.for("bar") === Symbol.for("bar") // true Symbol("bar") === Symbol("bar") // false

6.Symbol.keyFor()返回一个已登记的 Symbol 类型值的key:

let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo" let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined 变量s2属于未登记的 Symbol 值,所以返回undefined

6.内置的Symbol值:对象的Symbol.iterator属性,指向该对象的默认遍历器方法。

最后

好了,本篇就到这里,主要都是摘抄常用的知识点和备注自己的理解,希望对你有所帮助,后面会持续更新,欢迎关注!也感谢你能看到这里!

GitHub传送门

博客园传送门

ES6读书笔记(一)的更多相关文章

  1. ES6读书笔记(三)

    前言 前段时间整理了ES6的读书笔记:<ES6读书笔记(一)>,<ES6读书笔记(二)>,现在为第三篇,本篇内容包括: 一.Promise 二.Iterator和for of循 ...

  2. ES6读书笔记(二)

    前言 前段时间整理了ES6的读书笔记:<ES6读书笔记(一)>,现在为第二篇,本篇内容包括: 一.数组扩展 二.对象扩展 三.函数扩展 四.Set和Map数据结构 五.Reflect 本文 ...

  3. ES6 读书笔记

    一.let和const命令 二.变量的解构赋值 三.字符串的扩展 四.数值的扩展 五.正则的扩展 六.数组的扩展 七.函数的扩展 八.对象的扩展 九.symbol 十.proxy和reflect 十一 ...

  4. React 读书笔记

    序言: 领导安排部门同事本月内看一本跟自己职业相关的书籍, 根基类的书籍已经看过了,重复阅读的意义不大,所以我平时看的都是视频,也许是视频作者没有出书的条件,也许是现在出书看的人越来越少了,也许有其他 ...

  5. 《你不知道的JavaScript(上卷)》读书笔记

    第一次尝试用思维导图记笔记,感觉还不错~~~不过还是改不了我读书笔记写成抄书笔记的毛病 =.= 因为开始学JS的时候,一般浏览器就已经支持ES6了,所以比较喜欢使用ES6语法,let,=>等,文 ...

  6. 《你不知道的javascript》读书笔记2

    概述 放假读完了<你不知道的javascript>上篇,学到了很多东西,记录下来,供以后开发时参考,相信对其他人也有用. 这篇笔记是这本书的下半部分,上半部分请见<你不知道的java ...

  7. YDKJ 读书笔记 01 Function vs. Block Scope

    Introduction 本系列文章为You Don't Know JS的读书笔记. 书籍地址:https://github.com/getify/You-Dont-Know-JS Scope Fro ...

  8. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  9. 读书笔记--SQL必知必会18--视图

    读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...

随机推荐

  1. JS获取第二个横杠后面的内容

    假设数据为: let str = "zheng-shize-zsz"; 获取第一个横杠的位置: str.indexOf("-") 1. 那获取第二个横杠怎么写呢 ...

  2. ES6 模块化与 CommonJS 模块化

    ES6 模块化 import命令用于输入其他模块提供的功能;export命令用于规定模块的对外接口. export 可以有多个,export default 仅有一个 a.js 模块a文件 导出多个方 ...

  3. bootstrap 的模态框的宽与高设置

    1,改变bootstrap 的宽与高, 将style=“height:900px”放在<div class = "modal-dialog">或者更外层上,整个模态框的 ...

  4. Java快速入门-04-Java.util包简单总结

    学Java的程序员,lang包和util包最好是要过一遍的. 建议大家都序下载一个离线版开发文档,查阅非常方便,我给大家提供一个中文版 jdk1.8 离线文档,查看:JAVA - JDK 1.8 AP ...

  5. Android解析WindowManagerService(一)WMS的诞生

    前言 此前我用多篇文章介绍了WindowManager,这个系列我们来介绍WindowManager的管理者WMS,首先我们先来学习WMS是如何产生的.本文源码基于Android 8.0,与Andro ...

  6. android.view.WindowLeaked的解决办法

    按字面了解,Window Leaked大概就是说一个窗体泄漏了,也就是我们常说的内存泄漏,为什么窗体会泄漏呢? 产生原因: 我们知道Android的每一个Activity都有个WindowManage ...

  7. Vue实例对象的数据选项(火柴)

    前言 一般地,当模板内容比较简单的时候,使用data选项配合表达式即可.涉及到复杂逻辑时,则需要用到methods.computed.watch等方法.本文将详细介绍Vue实例对象的数据选项. dat ...

  8. Python初探-Pycharm,Anaconda-人脸识别

    版权声明:博客版权所有,转载注明出处. https://blog.csdn.net/qq_33083551/article/details/82253026 1.建议先安装Anaconda,再安装Py ...

  9. Oracle PL/SQL Dev工具(破解版)被植入勒索病毒的安全预警及自查通告

    [问题描述] 近日,有项目组遇到了勒索软件攻击:勒索代码隐藏在Oracle PL/SQL Dev软件中(网上下载的破解版),里面的一个文件afterconnet.sql被黑客注入了病毒代码.这个代码会 ...

  10. ProxySQL读写分离

    我们首先看一下自己的环境: MHA已经搭建: master: slave: slave: MHA manager在172.16.16.34,配置文件如下: [root@localhost bin]# ...