ES6新語法
ES6新語法
js是一種動態型別,弱型別,基於原型的客戶端指令碼語言。
1.塊級作用域:let/const
ES5只有全域性作用域和函式作用域,會帶來很多不合理的場景
//比如:我們只想把i變數放在for迴圈裡面使用,但是如果用var宣告,就會汙染整個作用域
for(var i = 0; i < 5; i++){
console.log(i)
}
//在我們期望的for迴圈範圍外使用i變數可能會導致異常
塊級作用域
- with(嚴格模式下禁止,ES3)
function foo(obj){
with(obj){
a = 2
}
}
var o1 = {
a:3
}
var o2 = {
b:2
}
foo(o1)
console.log(o1.a) //2
foo(o2)
console.log(o2.a) //undefined
console.log(a) // 2,洩露到全域性作用域上
//with可以將一個物件處理為詞法作用域,但是這個塊內正常的var宣告不會被限制在這個塊的作用域裡,而是被新增到with所處的函式作用域中
- try/catch(ES3)
try{
undefined()//執行一個非法操作造成異常
}catch(e){
console.log(e) //正常執行
}
console.log(e) //ReferenceError:e not found
//重點是工具可以將ES6的程式碼轉換成能在 ES6 之前環境中執行的形式。使用塊級作用域寫程式碼,在構建時通過工具對程式碼進行預處理,使之正常工作。
- let(ES6)
let關鍵字可以將變數繫結到所在的任意作用域中(通常是{}內部)
2.物件字面量的屬性賦值簡寫
var obj = {
handler
//等價於
// handler:handler
}
3.字串模板
var name = "zs"
console.log(`hello:${name}`)
4.生成器(function *fn())
(一種返回迭代器的函式,通過function關鍵字後面的*來表示)
// 生成器
function *createIterator() {
//yield指定呼叫迭代器的next()方法時的返回值及返回順序
yield 1;
yield 2;
yield 3;
}
// 生成器能像正規函式那樣被呼叫,但會返回一個迭代器
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
//之後所有的呼叫都是
console.log(iterator.next()); // "{ value: undefined, done: true }"
*5.ES Module
5.1 ES Module(export,import)
在編譯時按需載入,能靜態分析,實現Tree Shaking,輸出的是值的引用,一旦輸出一個值,就生成一個只讀引用,等指令碼真正執行的時候,在根據這個只讀引用取取值,模組內部的值變化會影響這個值。
5.2 Commonjs(module.exports ,require)
動態引入,執行時引入,輸出的是值的拷貝,一旦輸出一個值,模組內部的變化影響不到這個值。CommonJs模組的頂層this指向當前模組。並且CommonJS模組無論載入多少次,只在第一次載入的時候執行一次,以後再載入,就返回第一次執行的結果。
// poeple.js
export var name = 'zhangsan' //輸出變數
export var height = 180
export var age = 18
export function add (x, y) { //輸出函式
return x + y
}
//等價於
// poeple.js
var name = 'zhangsan'
var height = 180
var age = 18
export { name, height, age }
//匯入(按需載入)
import { name, height, age } from './people.js'
function getPeople () {
return `${name} is ${height} cm`
}
//匯入(整體載入)
import * as people from './people.js'
上面的例子中,使用者必須要知道索要載入的變數名或函式名,否則無法載入,為了給使用者方便,用到expoty default
//匯出
export default function () {
console.log('foo')
}
//匯入
import something from './export-default'
something() // 'foo'
6.Proxy
Proxy可以劫持物件的改變,defineProperty需要遍歷
6.1defineProperty
1.劫持物件的改變
let fruit = {
"apple": 2,
"pear": 22,
"peach": 222
}
Object.keys(fruit).forEach(function (key) {
Object.defineProperty(fruit, key, {
enumerable: true,
configurable: true,
get: function () {
return val;
},
set: function (newVal) {
val = newVal; // 輸出 newVal 888
console.log("newVal", newVal)
}
})
})
fruit.apple = 888
//輸出
newVal 888
//不能劫持物件屬性的新增,需要藉助this.$set
this.$set(fruit,"lemon",5)
6.2proxy
1.劫持陣列的改變(相當於陣列的代理)
let fruit = [{name:"apple",num:2},{name:"pear",num:3},{name:"peach",num:4}]
let proxy = new Proxy(fruit, {
get: function (obj, prop) {
return prop in obj ? obj[prop] : undefined
},
set: function (obj, prop, newVal) {
obj[prop] = newVal
console.log("newVal", newVal) // 輸出{ name: "lemon", num: 999 }
return true;
}
})
proxy.push({ name: "lemon", num: 999 })
console.log(fruit)
//輸出
newVal { name: 'lemon', num: 999 } //向陣列中新增資料觸發了set方法
newVal 4 //由於陣列中新增資料長度發生改變觸發了set方法
[
{ name: 'apple', num: 2 },
{ name: 'pear', num: 3 },
{ name: 'peach', num: 4 },
{ name: 'lemon', num: 999 }
]
2.劫持物件的改變
let fruit = {
"apple": 2,
"pear": 22,
"peach": 222
}
let proxy = new Proxy(fruit, {
get: function (obj, prop) {
return prop in obj ? obj[prop] : undefined
},
set: function (obj, prop, newVal) {
obj[prop] = newVal
console.log("newVal", newVal) // 輸出 newVal 888
return true;
}
})
proxy.apple = 888
//newVal 888
//可以劫持物件屬性的新增
proxy相當於代理:
var target = {};
var handler = {
get: function (receiver, name) {
return `Hello, ${name}!`;
}
};
var p = new Proxy(target, handler);
p.world === 'Hello, world!';
7.Map + Set + WeakMap + WeakSet
遍歷Set和Map的順序就是元素插入的順序。
7.1 set
var a = {name:"Jhon"};
var b = {name:"Jhon"};
var set = new Set();
set.add(a).add(b);
console.log(set.size); //2
//這兩個物件應該按相同處理,畢竟它們有完全一樣的屬性。但在JavaScript中,它們是各自獨立、互不相同的。
set.forEach(function(value){ //遍歷Set
console.log(value); //{ name: "Jhon" },輸出2次
});
set.delete(a) //刪除a元素
7.2 map
var map = new Map(); //建立一個新的,空的Map
map.set("one",1); //增加列表項
map.set("two",2);
console.log(map.size); //2,獲取元素個數
if(map.has("one")){ //true,判斷元素存在
console.log("one");
}
console.log(map.get("one")); //1,根據key獲取元素
map.forEach(function(value, key, map){ //遍歷map
console.log(key + ":" + value); //one:1,two:2
}
map.delete("one") //根據key值刪除
7.3 WeakMap + WeakSet
-
map和set都為內部的每個鍵或值保持了強引用,也就是說,如果一個物件被移除了,回收機制無法回收它佔用的記憶體,除非在map和set中刪除它
-
WeakSet和WeakMap中的弱引用物件在沒有其他值引用該弱引用物件時會被垃圾回收機制回收時,他會簡單的從WeakSet和WeakMap中回收
WeakSet:
- 成員都是物件
- 成員都是弱引用。可以被垃圾回收機制回收。可以用來儲存DOM節點,不容易造成記憶體洩漏
- 不能遍歷
WeakMap:
- 只接受物件作為鍵名,鍵值是任意的
- 鍵名是弱引用(鍵值依然是正常引用),鍵名所指向的物件可以被垃圾回收機制回收。
- 不能遍歷
8. 箭頭函式 Arrow functions
- 簡化了程式碼形式,預設return表示式結果
- 本身不存在this,this指向的是定義函式時的this
render:h=>h(App) //函式等同於下面的函式
render:h=>{
return h(App);
}
箭頭函式與普通函式的區別?
-
普通函式可以由具名函式(函式宣告),也可以由匿名函式(函式表示式);箭頭函式都是匿名函式
-
普通函式this指向呼叫它的函式,如果用作建構函式,this指向建立的物件例項
箭頭函式本身不建立this,它的this指向其所在的上下文
-
普通函式可以用於建構函式,箭頭函式不行(沒有this)
使用new建立新物件的過程
建立空物件 var obj = {};
設定新物件的__proto__屬性指向建構函式的prototype物件 obj.proto = ClassA.prototype;
改變this的指向 ClassA.call(obj);
返回該物件
9.class語法
class Person{
constructor(name,age){ //通過new命令生成例項物件時,自動呼叫該方法(預設就返回例項物件this)
//下面屬性、方法都會在例項物件中
this.name = name //this代表的是例項物件
this.age = age
this.sayHello = function(){}
}
//繫結到了Person.property
say(){ //類的方法,1.不能加function 2.方法之間不能加逗號
return 'name:' + this.name + ',age:' + this.age
}
//也在例項物件中
showName = function(){}
//也在例項對像中
showAge = () =>{}
}
console.log(typeof Person); //function
console.log(Person === Person.prototype.constructor); //true
//類的所有方法都定義在Prototype上面
繼承
class Animal {
constructor(){}
name = 'animal';
age = 3;
showName() {
console.log( 'animalName =' + this.name)
}
showAge = ()=>{
console.log('animalAge = ' + this.age)
}
}
class Dog extends Animal {
constructor(){
super()
}
name='dog';
age=5;
fullname = 'Dog';
sex='male';
showSex() {
console.log(this.sex)
}
showName =()=> {
console.log('name' + this.name)
}
showFullName(){
console.log(this.name + this.fullname)
}
}
const dog = new Dog();
dog.showAge();
//animalAge = 5
dog.showName();
//namedog
dog.showSex();
// male
delete dog.showName
dog.showName()
// animalName =dog
//如果一個class的方法並不是定義在prototype方法上,
//而是像通過賦值一樣showName = ()=>{} 這種方式,
//那麼如果delete了例項物件上的屬性,這個屬性就會消失,
//再執行這個方法,就會向上訪問它的原型