ECMAScript
es3(ECMAScript 1999)
1999年,ECMAScript第三個版本
es4(ECMAScript 2007)
ECMAScript第四個版本,廢棄
es5(ECMAScript 2009)
2009年,ECMAScript第五個版本
strict模式
'use strict'
Array新增方法
every、some 、forEach、filter 、indexOf、lastIndexOf、isArray、map、reduce、reduceRight
PS: 還有其他方法 Function.prototype.bind、String.prototype.trim、Date.now
Object新增方法
Object.getPrototypeOf
Object.getPrototypeOf()
方法傳回指定對象的原型(内部
[[Prototype]]
屬性的值)。傳回值:給定對象的原型。如果沒有繼承屬性,則傳回
null
。
var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true
var obj1 = {}
console.log(Object.getPrototypeOf(obj1) === Object.prototype) //true
var reg = /a/;
Object.getPrototypeOf(reg) === RegExp.prototype; // true
複制
**
Object.create()
**方法建立一個新對象,使用現有的對象來提供新建立的對象的__proto__。
可以使用
Object.create()
來實作類式繼承。
var o;
// 建立一個原型為null的空對象
o = Object.create(null);
o = {};
// 以字面量方式建立的空對象就相當于:
o = Object.create(Object.prototype);
複制
Object.getOwnPropertyNames
**
Object.getOwnPropertyNames()
**方法傳回一個由指定對象的所有自身屬性的屬性名(包括不可枚舉屬性但不包括Symbol值作為名稱的屬性)組成的數組。
var arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"]
// 類數組對象
var obj = { 0: "a", 1: "b", 2: "c"};
console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]
// 使用Array.forEach輸出屬性名和屬性值
Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {
console.log(val + " -> " + obj[val]);
});
// 輸出
// 0 -> a
// 1 -> b
// 2 -> c
複制
Object.getOwnPropertyDescriptor
Object.getOwnPropertyDescriptor()
方法傳回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不需要從原型鍊上進行查找的屬性)
var o, d;
o = { get foo() { return 17; } };
d = Object.getOwnPropertyDescriptor(o, "foo");
// d {
// configurable: true,
// enumerable: true,
// get: /*the getter function*/,
// set: undefined
// }
o = { bar: 42 };
d = Object.getOwnPropertyDescriptor(o, "bar");
// d {
// configurable: true,
// enumerable: true,
// value: 42,
// writable: true
// }
o = {};
Object.defineProperty(o, "baz", {
value: 8675309,
writable: false,
enumerable: false
});
d = Object.getOwnPropertyDescriptor(o, "baz");
// d {
// value: 8675309,
// writable: false,
// enumerable: false,
// configurable: false
// }
複制
Object.defineProperty
vue2使用的響應式就是根據Object.defineProperty進行的。
var o = {}; // 建立一個新對象
// 在對象中添加一個屬性與資料描述符的示例
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : true
});
// 對象 o 擁有了屬性 a,值為 37
複制
Object.defineProperties
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
});
複制
Object.keys
在ES5裡,如果此方法的參數不是對象(而是一個原始值),那麼它會抛出 TypeError。在ES2015中,非對象的參數将被強制轉換為一個對象。
Object.keys("foo");
// TypeError: "foo" is not an object (ES5 code)
Object.keys("foo");
// ["0", "1", "2"] (ES2015 code)
複制
Object.preventExtensions
Object.preventExtensions()
方法讓一個對象變的不可擴充,也就是永遠不能再添加新的屬性。
如果一個對象可以添加新的屬性,則這個對象是可擴充的。
Object.preventExtensions()
将對象标記為不再可擴充,這樣它将永遠不會具有它被标記為不可擴充時持有的屬性之外的屬性。注意,一般來說,不可擴充對象的屬性可能仍然可被删除。嘗試将新屬性添加到不可擴充對象将靜默失敗或抛出
TypeError
(最常見的情況是strict mode (en-US)中,但不排除其他情況)。
Object.preventExtensions()
僅阻止添加自身的屬性。但其對象類型的原型依然可以添加新的屬性。
該方法使得目标對象的
[[prototype]]
不可變;任何重新指派
[[prototype]]
操作都會抛出
TypeError
。這種行為隻針對内部的
[[prototype]]
屬性, 目标對象的其它屬性将保持可變。
一旦将對象變為不可擴充的對象,就再也不能使其可擴充。
// Object.preventExtensions将原對象變的不可擴充,并且傳回原對象.
var obj = {};
var obj2 = Object.preventExtensions(obj);
obj === obj2; // true
// 字面量方式定義的對象預設是可擴充的.
var empty = {};
Object.isExtensible(empty) //=== true
// ...但可以改變.
Object.preventExtensions(empty);
Object.isExtensible(empty) //=== false
// 使用Object.defineProperty方法為一個不可擴充的對象添加新屬性會抛出異常.
var nonExtensible = { removable: true };
Object.preventExtensions(nonExtensible);
Object.defineProperty(nonExtensible, "new", { value: 8675309 }); // 抛出TypeError異常
// 在嚴格模式中,為一個不可擴充對象的新屬性指派會抛出TypeError異常.
function fail()
{
"use strict";
nonExtensible.newProperty = "FAIL"; // throws a TypeError
}
fail();
複制
不可擴充對象的原型是不可變的:
var fixed = Object.preventExtensions({});
// throws a 'TypeError'.
fixed.__proto__ = { oh: 'hai' };
複制
Object.isExtensible
Object.isExtensible()
方法判斷一個對象是否是可擴充的(是否可以在它上面添加新的屬性)。
預設情況下,對象是可擴充的:即可以為他們添加新的屬性。以及它們的
__proto__
屬性可以被更改。
Object.preventExtensions
,
Object.seal
或
Object.freeze
方法都可以标記一個對象為不可擴充(non-extensible)。
// 新對象預設是可擴充的.
var empty = {};
Object.isExtensible(empty); // === true
// Object.preventExtensions可以讓它變的不可擴充.
Object.preventExtensions(empty);
Object.isExtensible(empty); // === false
// 密封對象是不可擴充的.
var sealed = Object.seal({});
Object.isExtensible(sealed); // === false
// 當機對象也是不可擴充.
var frozen = Object.freeze({});
Object.isExtensible(frozen); // === false
複制
Object.seal
Object.seal()
方法封閉一個對象,阻止添加新屬性并将所有現有屬性标記為不可配置。目前屬性的值隻要原來是可寫的就可以改變。
通常,一個對象是可擴充的(可以添加新的屬性)。密封一個對象會讓這個對象變的不能添加新屬性,且所有已有屬性會變的不可配置。屬性不可配置的效果就是屬性變的不可删除,以及一個資料屬性不能被重新定義成為通路器屬性,或者反之。但屬性的值仍然可以修改。嘗試删除一個密封對象的屬性或者将某個密封對象的屬性從資料屬性轉換成通路器屬性,結果會靜默失敗或抛出
TypeError
(在嚴格模式 中最常見的,但不唯一)。
不會影響從原型鍊上繼承的屬性。但
__proto__
( ) 屬性的值也會不能修改。
傳回被密封對象的引用。
var obj = {
prop: function() {},
foo: 'bar'
};
// 可以添加新的屬性
// 可以更改或删除現有的屬性
obj.foo = 'baz';
obj.lumpy = 'woof';
delete obj.prop;
var o = Object.seal(obj);
o === obj; // true
Object.isSealed(obj); // === true
// 仍然可以修改密封對象的屬性值
obj.foo = 'quux';
// 但是你不能将屬性重新定義成為通路器屬性
// 反之亦然
Object.defineProperty(obj, 'foo', {
get: function() { return 'g'; }
}); // throws a TypeError
// 除了屬性值以外的任何變化,都會失敗.
obj.quaxxor = 'the friendly duck';
// 添加屬性将會失敗
delete obj.foo;
// 删除屬性将會失敗
// 在嚴格模式下,這樣的嘗試将會抛出錯誤
function fail() {
'use strict';
delete obj.foo; // throws a TypeError
obj.sparky = 'arf'; // throws a TypeError
}
fail();
// 通過Object.defineProperty添加屬性将會報錯
Object.defineProperty(obj, 'ohai', {
value: 17
}); // throws a TypeError
Object.defineProperty(obj, 'foo', {
value: 'eit'
}); // 通過Object.defineProperty修改屬性值
複制
Object.isSealed
Object.isSealed()
方法判斷一個對象是否被密封。
如果這個對象是密封的,則傳回
true
,否則傳回
false
。密封對象是指那些不可
擴充
的,且所有自身屬性都不可配置且是以不可删除(但不一定是不可寫)的對象。
// 建立的對象預設不是密封的.
var empty = {};
Object.isSealed(empty); // === false
// 如果你把一個空對象變的不可擴充,則它同時也會變成個密封對象.
Object.preventExtensions(empty);
Object.isSealed(empty); // === true
// 但如果這個對象不是空對象,則它不會變成密封對象,因為密封對象的所有自身屬性必須是不可配置的.
var hasProp = { fee: "fie foe fum" };
Object.preventExtensions(hasProp);
Object.isSealed(hasProp); // === false
// 如果把這個屬性變的不可配置,則這個屬性也就成了密封對象.
Object.defineProperty(hasProp, "fee", { configurable: false });
Object.isSealed(hasProp); // === false
Object.isSealed(hasProp.fee); // === true
// 最簡單的方法來生成一個密封對象,當然是使用Object.seal.
var sealed = {};
Object.seal(sealed);
Object.isSealed(sealed); // === true
// 一個密封對象同時也是不可擴充的.
Object.isExtensible(sealed); // === false
// 一個密封對象也可以是一個當機對象,但不是必須的.
Object.isFrozen(sealed); // === true ,所有的屬性都是不可寫的
var s2 = Object.seal({ p: 3 });
Object.isFrozen(s2); // === false, 屬性"p"可寫
var s3 = Object.seal({ get p() { return 0; } });
Object.isFrozen(s3); // === true ,通路器屬性不考慮可寫不可寫,隻考慮是否可配置
複制
Object.freeze
Object.freeze()
方法可以當機一個對象。一個被當機的對象再也不能被修改;當機了一個對象則不能向這個對象添加新的屬性,不能删除已有屬性,不能修改該對象已有屬性的可枚舉性、可配置性、可寫性,以及不能修改已有屬性的值。此外,當機一個對象後該對象的原型也不能被修改。
freeze()
傳回和傳入的參數相同的對象。
被當機對象自身的所有屬性都不可能以任何方式被修改。任何修改嘗試都會失敗,無論是靜默地還是通過抛出
TypeError
異常(最常見但不僅限于strict mode)。
資料屬性的值不可更改,通路器屬性(有getter和setter)也同樣(但由于是函數調用,給人的錯覺是還是可以修改這個屬性)。如果一個屬性的值是個對象,則這個對象中的屬性是可以修改的,除非它也是個當機對象。數組作為一種對象,被當機,其元素不能被修改。沒有數組元素可以被添加或移除。
這個方法傳回傳遞的對象,而不是建立一個被當機的副本。
var obj = {
prop: function() {},
foo: 'bar'
};
// 新的屬性會被添加, 已存在的屬性可能
// 會被修改或移除
obj.foo = 'baz';
obj.lumpy = 'woof';
delete obj.prop;
// 作為參數傳遞的對象與傳回的對象都被當機
// 是以不必儲存傳回的對象(因為兩個對象全等)
var o = Object.freeze(obj);
o === obj; // true
Object.isFrozen(obj); // === true
// 現在任何改變都會失效
obj.foo = 'quux'; // 靜默地不做任何事
// 靜默地不添加此屬性
obj.quaxxor = 'the friendly duck';
// 在嚴格模式,如此行為将抛出 TypeErrors
function fail(){
'use strict';
obj.foo = 'sparky'; // throws a TypeError
delete obj.quaxxor; // 傳回true,因為quaxxor屬性從來未被添加
obj.sparky = 'arf'; // throws a TypeError
}
fail();
// 試圖通過 Object.defineProperty 更改屬性
// 下面兩個語句都會抛出 TypeError.
Object.defineProperty(obj, 'ohai', { value: 17 });
Object.defineProperty(obj, 'foo', { value: 'eit' });
// 也不能更改原型
// 下面兩個語句都會抛出 TypeError.
Object.setPrototypeOf(obj, { x: 20 })
obj.__proto__ = { x: 20 }
複制
Object.isFrozen
Object.isFrozen()
方法判斷一個對象是否被當機。
// 一個對象預設是可擴充的,是以它也是非當機的.
Object.isFrozen({}); // === false
// 一個不可擴充的空對象同時也是一個當機對象.
var vacuouslyFrozen = Object.preventExtensions({});
Object.isFrozen(vacuouslyFrozen) //=== true;
// 一個非空對象預設也是非當機的.
var oneProp = { p: 42 };
Object.isFrozen(oneProp) //=== false
// 讓這個對象變的不可擴充,并不意味着這個對象變成了當機對象,
// 因為p屬性仍然是可以配置的(而且可寫的).
Object.preventExtensions(oneProp);
Object.isFrozen(oneProp) //=== false
// 此時,如果删除了這個屬性,則它會成為一個當機對象.
delete oneProp.p;
Object.isFrozen(oneProp) //=== true
// 一個不可擴充的對象,擁有一個不可寫但可配置的屬性,則它仍然是非當機的.
var nonWritable = { e: "plep" };
Object.preventExtensions(nonWritable);
Object.defineProperty(nonWritable, "e", { writable: false }); // 變得不可寫
Object.isFrozen(nonWritable) //=== false
// 把這個屬性改為不可配置,會讓這個對象成為當機對象.
Object.defineProperty(nonWritable, "e", { configurable: false }); // 變得不可配置
Object.isFrozen(nonWritable) //=== true
// 一個不可擴充的對象,擁有一個不可配置但可寫的屬性,則它仍然是非當機的.
var nonConfigurable = { release: "the kraken!" };
Object.preventExtensions(nonConfigurable);
Object.defineProperty(nonConfigurable, "release", { configurable: false });
Object.isFrozen(nonConfigurable) //=== false
// 把這個屬性改為不可寫,會讓這個對象成為當機對象.
Object.defineProperty(nonConfigurable, "release", { writable: false });
Object.isFrozen(nonConfigurable) //=== true
// 一個不可擴充的對象,值擁有一個通路器屬性,則它仍然是非當機的.
var accessor = { get food() { return "yum"; } };
Object.preventExtensions(accessor);
Object.isFrozen(accessor) //=== false
// ...但把這個屬性改為不可配置,會讓這個對象成為當機對象.
Object.defineProperty(accessor, "food", { configurable: false });
Object.isFrozen(accessor) //=== true
// 使用Object.freeze是當機一個對象最友善的方法.
var frozen = { 1: 81 };
Object.isFrozen(frozen) //=== false
Object.freeze(frozen);
Object.isFrozen(frozen) //=== true
// 一個當機對象也是一個密封對象.
Object.isSealed(frozen) //=== true
// 當然,更是一個不可擴充的對象.
Object.isExtensible(frozen) //=== false
複制
es6(ECMAScript 2015)
2015年,ECMAScript第六個版本
塊級作用域
let,const
const
定義常量與使用
let
定義的變量相似:
- 二者都是塊級作用域
- 都不能和它所在作用域内的其他變量或函數擁有相同的名稱
兩者還有以下兩點差別:
-
聲明的常量必須初始化,而const
聲明的變量不用let
- const 定義常量的值不能通過再指派修改,也不能再次聲明。而 let 定義的變量值可以修改,但也不能再次聲明。
對象字面量的屬性指派簡寫
var obj = {name,age,say(){}}
// 約等于
var obj = {name:name,age:age,say:function(){}}
複制
解構指派
let info = { name: "Bob", age: 18 };
let { name: n, age: a } = info; // 相當于 n = "Bob", a = 18
複制
函數參數預設值
// 基本用法
function say(name = 'hss', age = 18) {
console.log(name, age);
}
say() //hss,18
say('why', 21) //why,21
say('why') //why,18
say(22) //22,18
// 與解構指派預設值結合
function pet({ name = 'cat', age = 3 }) {
console.log(name, age);
}
pet({}) //cat,3
pet({ name: 'dog', age: 4 }) //dog,4
pet({age:5}) //cat,5
// 雙重預設值
function son({name='tom',age=10}={}){
console.log(name,age);
}
son() //tom,10
son({name:'lili'}) //lili,10
son({age:14}) //tom,14
複制
擴充/剩餘運算符
var arr = [1, 2, 3]
console.log(arr); //[1, 2, 3]
console.log(...arr); //1 2 3
var arr1 = [2, 3, 4]
var arr2 = [5, 6, 7]
var arr3 = [...arr1, ...arr2]
console.log(arr3); //[2, 3, 4, 5, 6, 7]
var obj1 = { name: 'hss', age: 21 }
// console.log(...obj1); //報錯Uncaught TypeError: Found non-callable @@iterator
console.log({ ...obj1 }); //{name: "hss", age: 21}
// 剩餘運算符
var obj2 = { name: 'hss', age: 21, hobby: 'code' }
var { age, ...obj3 } = obj2
console.log(obj3); //{name: "hss", hobby: "code"}
複制
箭頭函數
箭頭函數沒有自己的
this
,
arguments
,
super
或
new.target
。箭頭函數表達式更适用于那些本來需要匿名函數的地方,并且它不能用作構造函數。
字元串模闆
var name = 'hss'
var str = `${name},喜歡code`
console.log(str) //hss,喜歡code
複制
Iterators(疊代器)+ for..of
生成器 (Generators)
Class
類表達式:
let Foo = class {
constructor() {}
bar() {
return "Hello World!";
}
};
let instance = new Foo();
instance.bar();
// "Hello World!"
複制
Class和類表達式一樣,類聲明體在嚴格模式下運作。構造函數是可選的。
類聲明不可以提升(這與函數聲明不同)。
Modules
export、export default、和import
Map + Set + WeakMap + WeakSet
Proxy
vue3使用的響應式就是根據Proxy對象進行的。
Promises
es7(ECMAScript 2016)
2016年,ECMAScript第七個版本
Array.prototype.includes()
es8(ECMAScript 2017)
2017年,ECMAScript第八個版本
async/await
Object.values()
MDN:
Object.values()
方法傳回一個給定對象自身的所有可枚舉屬性值的數組,值的順序與使用
for...in
循環的順序相同 ( 差別在于 for-in 循環枚舉原型鍊中的屬性 )。
即:
Object.values()
是一個與
Object.keys()
類似的新函數,但傳回的是Object自身屬性的所有值,不包括繼承的值。
假設我們要周遊如下對象
obj
的所有值:
const obj = {a: 1, b: 2, c: 3};
複制
不使用Object.values() :ES6
const obj = {a: 1, b: 2, c: 3};
const vals = Object.keys(obj).map(key=>obj[key]);
console.log(vals);//[1, 2, 3]
複制
使用Object.values() :ES8
const obj = {a: 1, b: 2, c: 3};
const values = Object.values(obj);
console.log(values);//[1, 2, 3]
複制
Object.entries()
MDN:
Object.entries()
方法傳回一個給定對象自身可枚舉屬性的鍵值對數組,其排列與使用
for...in
循環周遊該對象時傳回的順序一緻(差別在于 for-in 循環還會枚舉原型鍊中的屬性)。
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
// array like object
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
// array like object with random key ordering
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]
複制
es9(ECMAScript 2018)
2018年,ECMAScript第九個版本
es10(ECMAScript 2019)
2019年,ECMAScript第十個版本