前言
原子操作這是Java多線程編程的老生常談了。所謂原子操作是指不會被線程調(diào)度機制打斷的操作;這種操作一旦開始,就一直運行到結(jié)束,中間不會有任何 context switch (切換到另一個線程)。
當(dāng)然JS是單線程的,所以不存在線程打斷這么一說,我只是從Java中借引了這么一個概念。如果一段JS代碼在執(zhí)行過程中沒有未知操作被引入,那么這段代碼就是100%可控和安全的,這就是原子操作。反之非原子操作可能會因為外界操作的引入導(dǎo)致代碼變得難以控制而產(chǎn)生隱晦的bug。
JavaScript中可以通過Object.create(null)來創(chuàng)建原子,這是非常自然而又易于理解的方式。不過也有一些其它的方法來實現(xiàn)相同的效果,雖然在概念上有所不同,但是它們創(chuàng)建的一樣是“原子對象”。
創(chuàng)建原子
使用Object.create()
// 方法1atom = Object.create(null)
使用Object.setPrototypeOf()
// 方法2atom = Object.setPrototypeOf(new Object, null)// ORatom = Object.setPrototypeOf({}, null)重置構(gòu)造器的原型屬性
// 方法3function MyObject() { // ...}Object.setPrototypeOf(MyObject.prototype, null);atom = new MyObject;重置類的原型
注:“非派生類(沒有extends聲明的類)”,與將一個普通函數(shù)用作構(gòu)造器時的特性基本一致。
class MyClass { // ...}Object.setPrototypeOf(MyClass.prototype, null);atom = new MyClass;使用派生自null值的類
JavaScript在處理extends null時會將MyClass.prototype的原型置為null,因此這個類構(gòu)建的實例自然就是atom。但是,派生自null值的類無法直接構(gòu)建,因此需要聲明自己的構(gòu)造方法(以該方法創(chuàng)建和返回的對象作為this)。
// 方法4class MyClass extends null { constructor() { return Object.create(new.target.prototype); }}atom = new MyClass;上例在實現(xiàn)構(gòu)造方法constructor()時是直接引用new.target.prototype來作為原型的,這樣也就可以在new運算時引用到MyClass子類的原型。例如:
// 方法5class MyClassEx extends MyClass { get description() { return 'class MyClassEx'; }}atom = new MyClassEx;console.log(atom.description); // class MyClassEx使用一般函數(shù)并直接返回原子
下面的代碼是兼容構(gòu)造器、原型繼承和函數(shù)調(diào)用等方式的。
// 方法6// (當(dāng)作為函數(shù)調(diào)用時,new.target為undefined值)function MyAtom() { return Object.create(new.target && new.target.prototype || null);}// 示例1atom = new MyAtom;// 示例2atom = MyAtom();使用類來創(chuàng)建原子的一個特例
在上述方法4中,由于聲明了extends null,因此類MyClass必須擁有一個自己的構(gòu)造方法。但事實上在JavaScript中,
新聞熱點
疑難解答
圖片精選