ES是一把利器,也是一匹野馬。
紮實好ES基礎,會讓人如虎添翼,你還在猶豫什麼。前端
// IIFE 寫法
(function () {
var num = ...;
...
}());
// 塊級做用域寫法
{
let num = 123;
}
複製代碼
let a = function(){}
)if (true) let a = 1; // 不存在塊級做用域
複製代碼
const a = {};
a.b = 13; // 沒毛病,不會報錯
const arr = [];
arr.push(123); // 也沒毛病
// 若是須要,能夠將對象凍結
const a = Object.freeze({})
// 除了對象自己,其屬性也應該凍結
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key, i) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};
複製代碼
數組解構es6
var [a, c] = [2];
a // 2
c // undefined
複製代碼
let [a, b = 1] = [2, null] // 1, null
let [a, b = 1] = [2] // 2 1
let [a, b = 1] = [2, undefined] // 2 1
複製代碼
let [x = y, y = 1] = []; // 報錯,使用y時,y還未聲明
let [x = 1, y = x] = []; // x=1; y=1
複製代碼
對象解構web
const {a, b} = undefined || []; // 我的推薦這種這種寫法避免報錯,a undefined, b undefined
複製代碼
解構其餘用法數組
// 函數返回多個值只能經過數組或者對象的形式返回
const func = () => [1, {a: 1}, [1,2,3,4]];
const [first, second, third] = func(); // first 1,second {a: 1}, third [1,2,3,4]
const func = () => {
return {
first: 1,
second: { a: 1},
third: [1, 2, 3, 4, 5]
}
};
const {first, second, third} = func(); // first 1, second {a: 1}, third [1, 2, 3, 4, 5]
複製代碼
import { moduleA, moduleB } from 'someModule';
複製代碼
var func = function () {return '123'}
var val = '456'
console.log(`this is string ${func()} + ${val}`) // this is string 123 + 456
複製代碼
toString
方法// 字符串是否包含某個字符串
// 可接受第二個參數表示從下標n開始日後查找
var str = 'abcdefg';
str.includes('c', 1); // true
// 字符開始是否包含某個字符串
// 第二個參數表示從下標n開始是否包含某個字符串
str.startsWith('b') // false
str.startsWith('b', 1) // true
// 結尾是否包含
str.endsWith('b') // false
str.endsWith('b', 2) // true,表示前n個字符的結尾是否包含查詢的字符串
str.endsWith('b', 1) // false
// 返回一個重複n次的新字符串
str.repeat(2) // 'abcdefgabcdefg'
// 補全字符串(返回補全後的新字符串,不改變原字符串)
var str = 'a';
str.padStart(4, 'b') // bbba,在前面補
str.padEnd(4, 'b') // abbb。 後補
str.padStart(4) // ' a', 默認補空格
// 消除前/尾空格 (返回新字符,不改變原字符串)
var str = ' a ';
str.trimStart() // "a "
str.trimEnd() // " a"
複製代碼
// 判斷有限數
Number.isFinite(123) // true
Number.isFinite(Infinity) // false
Number.isFinite('123') // false,非數字類型一概返回false
// parseInt和parseFloat移植到了Number對象上
Number.parseInt()
Number.parseFloat()
// 判斷整數
Number.isInteger(2) // true
Number.isInteger(2.0) // true js中整數和浮點數採用的是一樣的儲存方法,因此 2 和 2.0 被視爲同一個值
複製代碼
JavaScript 採用 IEEE 754 標準, 數值存儲爲64位雙精度格式,
數值精度最多能夠達到 53 個二進制位(1 個隱藏位與 52 個有效位)。
若是數值的精度超過這個限度,第54位及後面的位就會被丟棄,這種狀況下,Number.isInteger可能會誤判。bash
Number.EPSILON
// 2.220446049250313e-160.1 + 0.2 === 0.3 // false
// 能夠設計以下函數,偏差小於某個差值時自動忽略
const isEqualInAcceptErrorRange = (a, b) => Math.abs(a - b) < Number.EPSILON * Math.pow(2, 2);
isEqualInAcceptErrorRange(0.1 + 0.2, 0.3) // true
複製代碼
Math.trunc(1.111) //1, 返回去除小數後的值,等於1.111 | 0
Matn.sign(1.111) // +1,判斷一個數是正數仍是負數,-1負數,0,-0,其餘值反水NaN
複製代碼
// 不能有同名函數參數
// 已聲明的參數變量在函數體內不能夠用let/const重複聲明
// 參數表達式是惰性求值的,每次調用函數時都會從新計算參數的值(也只會在每次調用時才計算參數的值)
function func(a = 1, b = 2, c) {
}
複製代碼
// 與對象解構一塊兒使用,可是若是函數調用時沒傳參數,
// 那麼從undefined進行解構則會報錯
const func = ({ x, y = 1 }) => {};
func({}) // 正常
func() // 報錯
// 與對象解構+函數參數默認值一塊兒使用
const func2 = ({ x, y = 1 } = {}) => {};
func2() // 正常
複製代碼
// 只能使用在最後,後面不能再有參數
// rest參數是一個真正的數組,arguments是類數組
const func = function (...args) {
return args
// 等同於
// return Array.prototype.slice.call(arguments)
}
複製代碼
const func5 = () => ({a: 1, b: 2})
複製代碼
var cat = {
count: 0,
add: () => {
// 因爲對象構不成單獨的做用域,因此若是寫成箭頭函數,
// 則this在此時指向全局了,而不是該對象
this.count ++
}
}
cat.add() // cat.count並無變化
// 事件中須要this指向當前元素時,也不可使用箭頭
button.addEventListener('click', () => {
// 得不到指望的結果
this.classList.toggle('on');
});
複製代碼
// 例如定義一個管道函數,即前一個函數返回的值做爲下一個函數的參數
const pipeline = (...funcs) => v => funcs.reduce((a, b) => b(a), v);
複製代碼
var arg = [1, 2, 3, 4]
func.apply(null, arg)
func(...arg)
Max.max.apply(null, arg)
Math.max(...arg)
複製代碼
// 注意是淺拷貝
var arr = [...arr1, ..arr2, ..arr3]
複製代碼
[...Iterator]
複製代碼
var divs = document.getElementsByTagName('div')
Array.from(divs)
// 接受第二個參數,用於處理每一項數據,相似於map
Array.from(arrayLike, x => x * x);
複製代碼
// 拷貝數組部份內容覆蓋到數組其餘位置
// 參數,覆蓋開始的位置(含)/拷貝開始的位置(含)/拷貝結束的位置(不含)
// 負數表示倒數
[1,2,3,4,5].copyWithin(1, 2, 3) // [1, 3, 3, 4, 5]
// 找到某個值,不然返回undefined
// 接受第二個參數綁定回調函數的上下文
[1,2,3,4].find((e) => e === 3) // 3
// 找到符合條件的第一個值的下標,不然返回-1
var arr = [1,2,3,4,5]
arr.findIndex(e => e > 4) // 4
// 填充數組
// 參數:填充值,填充開始位置,填充結束位置(不含)
// 只會填充已有的值
[1,3,4,5,6,7].fill('a', 3, 11111) // [1, 3, 4, "a", "a", "a"]
// 遍歷鍵名,arr.keys()
var arr = ['a', 'b' ,'c' ,'d']
for(let index of arr.keys()) {
console.log(index)
}
// 遍歷值,arr.values()
var arr = ['a', 'b' ,'c' ,'d']
for(let index of arr.values()) {
console.log(index)
}
// 遍歷鍵值對,arr.entries()
var arr = ['a', 'b' ,'c' ,'d']
for(let index of arr.entries()) {
console.log(index)
}
// 是否包含某個值
[1, 2, 3].includes(2) // true
// falt數組,默認flat一層
[1, [2,3], [[4, [5, [6]]]]].flat() // 只有第一層 嵌套的被flat
// 等價於
[1, [2,3], [[4, [5, [6]]]]].flat(1)
// 接收一個參數表示要flat的層數,若是想flat所有層級
[1, [2,3], [[4, [5, [6]]]]].flat(Infinity) // [1, 2, 3, 4, 5, 6] Infinity表示flat所有層級
// flatMap先對數組每項的值進行回調函數的處理後再flat
// 只能拉伸一層
[2, 3, 4].flatMap((x) => [x, x * 2])
// 空位
// 空位的值不是undefined,[,,,,]或者new Array(5)都會產生空位
// es6明確規定空位會轉換成undefined
各類方法對空位的處理不一致,因此要絕對避免開發中出現空位
複製代碼
var name = 'xiaoming';
var o = {
['liu'+ name]: 1
}
o.liuxiaoming // 1
複製代碼
Object.getOwnPropertyDescriptor({a: 1}, 'a')
複製代碼
var o = {a: 1}
for/in // 自身和繼承的除symbols外的全部屬性
Object.keys(o) // 自身的除Symbols和不可枚舉外的全部屬性
Object.getOwnPropertyNames(o) // 自身的除Symbols外全部屬性
Object.getOwnPropertySymbols(o) // 全部Symbols屬性
Reflect.ownKeys(o) // 自身全部屬性
複製代碼
// es6新增super指向對象的原型對象
// 只能用在對象的方法中,不然報錯
var o = {a: 1}
var o2 = {
a: 2,
b () {
return super.a
}
}
// 將o2的原型設置爲o
Object.setPrototypeOf(o2, o)
o2.b() // 1
複製代碼
var o = Object.create({a: 1})
var {a} = o // a 1
var {...rest} = {} // rest {}
複製代碼
// 是否相等
Object.is(a, b) // 判斷兩個值是否徹底相等,比===強在+0-0,NaN的判斷
// 對象淺拷貝
Object.assign(target, o2, o3, o4) // 將o234合併到target對象上,同名屬性替換
// 獲取對象單個屬性的描述對象
Object.getOwnPropertyDescriptor(o2, 'a')
// 獲取對象全部屬性的描述對象,注意二者的區別,一個加s,一個沒有s
Object.getOwnPropertyDescriptors(o2)
// 設置對象的原型
var o1 = {}
var o2 = {a: 1}
Object.setPrototypeOf(o1, o2) // 把o1的原型設置爲o2
// 讀取對象的原型對象
Object.getPrototypeOf(o1)
複製代碼
var s1 = Symbol()
var s2 = Symbol('s2') // 爲s2增長一個描述
s2.description // 獲取s2的描述
// 做爲屬性名使用
var o = {
[s2]: 456
}
o[s1] = 123 // 不能使用點運算符,不然會認爲是字符串
複製代碼
Symbol不會被for...in
、for...of
循環,也不會被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回app
Symbol.for()/Symbol.keyfor()dom
// Symbol.for接收一個參數,每次先搜索有沒有存在這個Symbol,有則返回,無則建立再返回
var s1 = Symbol.for('s1')
var s2 = Symbol.for('s1')
s1 === s2
// Symbol.keyFor(s1)返回一個Symbol.for()登記過的值的key
// 參數是一個Symbol.for()註冊的數據類型
Symbol.keyFor(s1) // "s1"
複製代碼
// 對象的Symbol.hasInstance指向對象內部一個方法,使用instanceOf判斷一個變量是不是該對象的實例時,會自動調用該對象的這個方法去驗證
// 好比,foo instanceof Foo在語言內部,實際調用的是Foo[Symbol.hasInstance](foo)
class MyClass {
[Symbol.hasInstance] (arr) {
return arr instanceof Array
}
}
[] instanceof new MyClass() // true
'aa' instanceof new MyClass() // false
var o = {}
o instanceof new MyClass() // false
複製代碼
// 相似與不能重複的數組
var s = new Set()
var s2 = new Set([1, 2, 3])
s2.add(4)
// 利用Set去重
[...new Set([1,2,3,4,5,5,5,5])]
// 獲取長度
s.size
// 刪除
s.delete(1) // 刪除成功返回true,不然返回false
// 清除全部
s.clear()
// 檢測是否含有
s.has(2) // 返回true/false
// 轉換成數組
Array.from(new Set([1,2,3,4]))
// Set能夠直接使用forEach方法
// filter/map等只能間接使用
s.forEach((value, key) => {})
s = new Set([...s].filter(e => {}))
// 利用Set實現並集
var s1 = new Set([1,2,3])
var s2 = new Set([2,3,4])
new Set([...s1, ...s2])
// 交集
new Set([...s1].filter(e => s2.has(e)))
複製代碼
// 鍵值對的集合,相似於對象,可是鍵再也不只是字符串
var m = new Map()
var m2 = new Map([[1, 2], ['key', 345]])
// 若是鍵是基本數據類型,只要嚴格相等則認爲是同一個鍵
// 若是鍵是引用類型,只有是同一個引用才斷定是同一個鍵
// 新增數據,set返回當前map對象,因此支持鏈式調用
// 有則覆蓋,無則生成
m.set(2, 3)
m.set(['aa'], 1234)
m.set({}, 543).set('b', 123)
// 讀取鍵值,無則返回undefined
m.get(2)
// 獲取長度
m.size
// 刪除
m.delete(鍵名) // 返回true/false
// 清除全部
m.clear()
// 判斷是否含有某個鍵
m.has()
// 遍歷,遍歷順序就是插入順序
m.forEach()
m.keys()
m.values()
m.entries()
複製代碼
var obj = {x: 1}
var proxyObj = new Proxy(obj, {
get () {
return 2222;
}
})
console.log(proxyObj.x); // 2222
// Proxy的實例能夠做爲其餘對象的原型對象使用
var obj2 = Object.create(proxyObj)
console.log(obj2.x) // 2222
複製代碼
// get攔截對象屬性的讀取
// 接收三個參數:攔截目標,攔截屬性,proxy實例
// 例如,利用proxy生成dom節點的函數
const dom = new Proxy({}, {
get (target, key, proxySelf) {
return function (attrs = {}, ...children) {
let el = document.createElement(key);
for (let i of Object.keys(attrs)) {
el.setAttribute(i, attrs[i])
}
for (let child of children) {
if (typeof child === 'string') {
child = document.createTextNode(child)
}
el.appendChild(child)
};
return el;
}
}
});
// 調用生成節點
const el = dom.div({},
'Hello, my name is ',
dom.a({href: '//example.com'}, 'Mark'),
'. I like:',
dom.ul({},
dom.li({}, 'The web'),
dom.li({}, 'Food'),
dom.li({}, '…actually that\'s it') ) ); document.body.appendChild(el); // set攔截對象屬性的設置 // 接收四個參數:目標對象,設置的屬性,屬性值,proxy實例 var proxyHandler = { get(target, key, value, proxySelf) { if (key[0] === '_') { throw new Error(`${key}是一個內部屬性`) } return target[key] }, set(target, key, value, proxySelf) { if (key[0] === '_') { throw new Error(`${key}是一個內部屬性`) } target[key] = value } } var objProxy = new Proxy({}, proxyHandler) objProxy.a = 123 objProxy.a // 123 objProxy._a // 報錯內部屬性 // has攔截HasProperty操做,例如典型的'a' in obj,可是不對for/in生效 // 第一個參數源對象,第二個參數屬性 // construct 攔截new操做 // 三個參數:原目標對象/函數參數/proxy實例自己 var Person = function() {} var PersonProxy = new Proxy(Person, { construct (target, args, proxySelf) { console.log('攔截了new操做') return new target(args) } }) new PersonProxy() // deleteProperty攔截delete操做,若是返回false則沒法刪除 // 參數 target,key // defineProperty攔截Object.defineProperty操做 // 返回false則該操做無效 // 參數: target, key, proxySelf // getOwnPropertyDescriptor攔截Object.getOwnPropertyDescriptor()操做 // 其餘攔截方法 - getPrototypeOf - isExtensible - ownKeys - preventExtensions - setPrototypeOf // 取消proxy的代理器,用於在完成代理後,當即收回代理權 // Proxy.revocable返回一個對象,該對象的proxy屬性是該代理的實例,revoke是一個能夠收回proxy代理權的函數。 var Person = function() {} var {proxy, revoke} = Proxy.revocable(Person, { construct (target, args, proxySelf) { console.log('攔截了new操做') return new target(args) } }) new proxy() // 正常實例化 revoke() // 取消其proxy的代理權 new proxy() // 沒法實例化 // proxy實例以後,實例中的this指代proxy實例 複製代碼
const getname = "GET_USER_NAME";
class Person {
// 實例屬性也能夠寫在最頂部,此時不須要加this
time = new Date();
// 構造函數裏面的內容
constructor (x, y) {
this.x = x;
this.y = y;
console.log(new.target === Person) //
}
// 類原型上的方法
toString () {
console.log(this.x + ' - ' + this.y);
}
// 靜態方法,只有類能訪問的,實例不能訪問
// 所以這裏的x,y都是undefined,由於x,y屬性都是實例屬性
static toString () {
console.log('靜態方法:', this.x + ' - ' + this.y)
}
// 可使用表達式命名
[getName] () {
}
}
const p1 = Person('mack', 25);
p1.toString(); // mack - 25
Person.toString() // 靜態方法: undefined - undefined
複製代碼
function Person () {
// 之前的寫法
if (!(this instanceof Person)) {
return new Person()
}
// 如今能夠經過new.target
if (new.target !== Person) {
return new Person()
}
}
複製代碼
// 定義父類
class Parent {
constructor (name, age) {
this.name = name;
this.age = age;
}
static getName () {
console.log(this.name);
return this.name;
}
getAge () {
console.log('age: ', this.age);
}
}
// 定義子類,子類繼承父類
class Child extends Parent {
constructor (...arg) {
// 經過super繼承父類的屬性和方法
// 必須經過super繼承後,才能使用子類本身的this
// 不然報錯,得不到子類的this對象
super(...arg); // es5的實現方式Parent.apply(this, arg)
// this.name = name;
// this.age = age;
}
}
var p1 = new Child('xiaoming', 24);
Child.getName() // 父類的靜態方法,會被子類繼承
p1.getAge() // 父類的原型方法,會被子類的實例繼承
複製代碼
Object.getPrototypeOf(Child)
獲取父類,能夠用來判斷一個類是否繼承另外一個類const a = 5
const b = function(){}
const c = class {}
// 導出
export const age = '123'
export { a, b, c } // 導出多個,建議採起該方式,放在文件底部,一眼就看清楚有哪些導出
export { a as bobyAge } // 導出時定義別名
// 導入
import { a, b, c } from './someJs' // 須要和導出的變量名對應
import { a as otherName } './someJs' // 能夠起一個別名
import * as types from './someJs' // 導入全部變量,並起一個types變量名
複製代碼
const a = 123;
const f = function () {}
const o = {}
const C = Class {}
// 默認導出
// 一個模塊文件只能有一個默認導出
export default a;
// 或
export default f
// 或
export default {
a,
f,
o,
C
}
// 導入
import newName from './some.js' // 導入時不用和導出的變量名對應,能夠隨便起一個名字
import _ from 'underscore';
// 同時導入默認內容和其餘內容
import o, {a, b, c} from './some.js'
複製代碼
// 先導入後導出,此時並無把a,b導入到當前模塊,只至關於對外作了一個轉發
export {a, b} from './some.js'
// 也可使用別名
export {a as otherName} from './some.js'
複製代碼
本文內容爲溫習es6內容,對遺漏知識點進行記錄,便於往後翻閱、加深記憶。 內容拜讀的阮一峯大大的ES6入門模塊化
百尺竿頭、日進一步。
我是愣錘,一名前端愛好者。
歡迎批評與交流。函數