Powershell的幾點基礎知識
es6宣告變數的方法:var、function、let、const、import、class。
頂層物件的屬性與全域性變數掛鉤,被認為是JavaScript語言最大的設計敗筆之一。這樣的設計帶來了幾個很大的問題,首先是沒法在編譯時就報出變數未宣告的錯誤,只有執行時才能知道(因為全域性變數可能是頂層物件的屬性創造的,而屬性的創造是動態的);其次程式設計師很容易不知不覺地就創造了全域性變數;最後,頂層物件的屬性是到處可以讀寫的,這非常不利於模組化程式設計。另一方面,window物件有實體含義,值的是瀏覽器的視窗物件,頂層物件是一個有實體含義的物件也是不合適的。
var、function命令宣告的全域性變數依舊是頂層物件的屬性,let、const、class命令宣告的全域性變數不屬於頂層物件的屬性。也就是說,從es6開始,全域性變數將逐步與頂層物件的屬性脫鉤(進行剝離)。
獲取頂層物件
(typeof window !== 'undefined' ? window : (typeof process === 'object' && typeof require === 'function' && typeof global === 'object') ? global : this) function getGlobal(){ if(typeof self !== 'undefined'){ return self } if(typeof window !== 'undefined'){ return window } if(typeof global !== 'undefined'){ return global } throw new Error('unable to locate global object') }
解構賦值報錯:等號右邊的值,要麼轉為物件以後不具備Iterator介面,要麼本身就不具備Iterator介面。事實上,只要某種資料結構具有Iterator介面,都可以採用陣列形式的解構賦值。
解構賦值允許指定預設值。es6內部使用嚴格相等運算子(===),判斷一個位置是否有值。只有當一個數組(物件中屬性)成員的值嚴格等於undefined,預設值才會生效。
物件的解構賦值是下面形式的簡寫。
let {foo:foo,bar:bar} = {foo:'aaa',bar:'bbb'}
也就是說,物件的解構賦值的內部機制是先找到同名屬性,然後再賦給對應的變數。真正被賦值的是後者,而不是前者。
let {foo:baz} = {foo:'aaa',bar:'bbb'} baz //'aaa' foo //error:foo is not defined
前者是匹配模式。後者才是變數。
在模板字串(template string)中使用反引號,需要在其前面用反斜槓轉義。
使用模板字串表示多行字串,所有空格和縮排都會被保留在輸出之中。
ES6 提供了二進位制和八進位制數值的新的寫法,分別用字首0b
(或0B
)和0o
(或0O
)表示。
函式引數制定了預設值以後,函式的length屬性將返回沒有指定預設值的引數的個數。
一旦設定了引數的預設值,函式進行宣告初始化時,引數會形成一個單獨的作用域(context)。等初始化結束,這個作用於就會消失。這種語法行為,在不設定引數預設值時,是不會出現的。
var x = 1 function fn(x,y = x){ console.log(y) } fn(2) //2 fn() //undefined
利用引數預設值,可以指定某個引數不得省略,如果省略就會丟擲錯誤。
function throwIfMiss(){ throw new Error('Missing Parameter') } function fn(mustBeProvidedParam = throwIfMiss()){ return mustBeProvidedParam } fn()
將引數預設值設為undefined
,表明這個引數是可以省略的。
函式的length屬性,不包括rest引數(函式的多餘引數)。
es6規定,只要函式引數使用了預設值、解構賦值、擴充套件運算子,那麼函式就不能顯式設定為嚴格模式,否則報錯。有兩種方法可以規避這種限制:
第一種是設定全域性性的嚴格模式
'use strict'; function doSomething(a, b = a) { // code }
第二種是把函式包在一個無引數立即執行函式裡面。
const doSomething = (function () { 'use strict'; return function(a,b = a) { // code }; }());
箭頭函式有幾個使用注意點:
- 函式體內的this物件,就是定義時所在的物件,而不是使用時所在的物件。
- 不可以當做建構函式,也就是說,不可以使用new命令,否則會丟擲一個錯誤。
- 不可以使用arguments物件,該物件在函式體內不存在。如果要使用,可以使用rest引數代替。
- 不可以使用yield命令,因此箭頭函式不能用作Generator函式。
Array.from()方法可將類陣列物件(array-like object)和可遍歷(iterable)的物件轉為真正的陣列。
Array.of()方法用於將一組值轉換為陣列。
物件中屬性名錶達式如果是一個物件,預設情況下會自動將物件轉為字串[object Object],而物件中只會有最後一個[object Object],前面的均會被覆蓋掉。
isPrototypeOf()、getPrototypeOf()、setPrototype()用法示例:
如果Symbol的引數是一個物件,就會呼叫該物件的toString方法,將其轉為字串,然後再生成一個symbol值。
Symbol例項屬性description,直接返回symbol的描述。
使用Set很容易實現並集(Union)、交集(Intersect)和差集(Difference)。
let s1 = new Set([1,2,3]) let s2 = new Set([3,4,5]) let union = new Set([...s1,...s2]) let intersect = new Set([...s1].filter(i => s2.has(i))) let difference = new Set([...s1].filter(i => !s2.has(i)))
Proxy建構函式:let proxy = new Proxy(target,handler);
target引數表示所要攔截的目標物件,handler引數也是一個物件。
下面是 Proxy 支援的攔截操作一覽,一共 13 種。
-
get(target, propKey, receiver):攔截物件屬性的讀取,比如
proxy.foo
和proxy['foo']
。 -
set(target, propKey, value, receiver):攔截物件屬性的設定,比如
proxy.foo = v
或proxy['foo'] = v
,返回一個布林值。 -
has(target, propKey):攔截
propKey in proxy
的操作,返回一個布林值。 -
deleteProperty(target, propKey):攔截
delete proxy[propKey]
的操作,返回一個布林值。 -
ownKeys(target):攔截
Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
迴圈,返回一個數組。該方法返回目標物件所有自身的屬性的屬性名,而Object.keys()
的返回結果僅包括目標物件自身的可遍歷屬性。 -
getOwnPropertyDescriptor(target, propKey):攔截
Object.getOwnPropertyDescriptor(proxy, propKey)
,返回屬性的描述物件。 -
defineProperty(target, propKey, propDesc):攔截
Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一個布林值。 -
preventExtensions(target):攔截
Object.preventExtensions(proxy)
,返回一個布林值。 -
getPrototypeOf(target):攔截
Object.getPrototypeOf(proxy)
,返回一個物件。 -
isExtensible(target):攔截
Object.isExtensible(proxy)
,返回一個布林值。 -
setPrototypeOf(target, proto):攔截
Object.setPrototypeOf(proxy, proto)
,返回一個布林值。如果目標物件是函式,那麼還有兩種額外操作可以攔截。 -
apply(target, object, args):攔截 Proxy 例項作為函式呼叫的操作,比如
proxy(...args)
、proxy.call(object, ...args)
、proxy.apply(...)
。 -
construct(target, args):攔截 Proxy 例項作為建構函式呼叫的操作,比如
new proxy(...args)
。
Reflect
物件一共有 13 個靜態方法。
-
Reflect.apply(target, thisArg, args)用於繫結
this
物件後執行給定函式 -
Reflect.construct(target, args)提供了一種不使用
new
,來呼叫建構函式的方法。 -
Reflect.get(target, name, receiver)
-
Reflect.set(target, name, value, receiver)
-
Reflect.defineProperty(target, name, desc)用來為物件定義屬性
-
Reflect.deleteProperty(target, name)用於刪除物件的屬性
-
Reflect.has(target, name)方法對應
name in obj
裡面的in
運算子。 -
Reflect.ownKeys(target) 用於返回物件的所有屬性,基本等同於
Object.getOwnPropertyNames
與Object.getOwnPropertySymbols
之和。 -
Reflect.isExtensible(target) 返回一個布林值,表示當前物件是否可擴充套件。
-
Reflect.preventExtensions(target)用於讓一個物件變為不可擴充套件。
-
Reflect.getOwnPropertyDescriptor(target, name)用於得到指定屬性的描述物件,
-
Reflect.getPrototypeOf(target)用於讀取物件的
__proto__
屬性 -
Reflect.setPrototypeOf(target, prototype)用於設定目標物件的原型(prototype)
promise
例項的狀態都變成fulfilled
,或者其中有一個變為rejected
,才會呼叫Promise.all
方法後面的回撥函式。
一個例項率先改變狀態,Promise.race()的狀態就跟著改變。那個率先改變的 Promise 例項的返回值,就傳遞給Promise.rece()的回撥函式
Promise.allSettled()
方法只有等到所有這些引數例項都返回結果,不管是fulfilled
還是rejected
,包裝例項才會結束。
Promise.any()只要引數例項有一個變成fulfilled
狀態,包裝例項就會變成fulfilled
狀態;如果所有引數例項都變成rejected
狀態,包裝例項就會變成rejected
狀態。
Promise.try()
原生具備Iterator介面的資料結構
- Array
- Map
- Set
- String
- TypedArray
- 函式的arguments物件
- NodeList物件
類相當於例項的原型,所有在類中定義的方法都會被例項繼承。如果在一個方法前,加上static關鍵字,表示該方法不會被例項繼承,而是直接通過類呼叫,這就成為靜態方法。
如果靜態方法中包含this關鍵字,這個this指的是類,而不是例項。
class Foo{ static bar(){ this.baz() } static baz(){ console.log('hello') } baz(){ console.log('world') } } Foo.bar() // hello
提案:私有屬性、方法,前面加#
new.target 屬性
new
是從建構函式生成例項物件的命令。ES6 為new
命令引入了一個new.target
屬性,該屬性一般用在建構函式之中,返回new
命令作用於的那個建構函式。如果建構函式不是通過new
命令或Reflect.construct()
呼叫的,new.target
會返回undefined
,因此這個屬性可以用來確定建構函式是怎麼呼叫的
需要注意的是,子類繼承父類時,new.target
會返回子類,利用這個特點,可以寫出不能獨立使用,必須繼承後才能使用的類。
class Father{ constructor(){ if(new.target === Father){ throw new Error('本類不能例項化') } } } class Son extends Father{ constructor(x,y){ super() this.x = x; this.y = y } }
未完待續...