一文讀懂ES6(附PY3對比)

 

Ⅰ.ES6~POP

代碼示例:https://github.com/lotapp/BaseCode/tree/master/javascript/1.ES6javascript

在線演示:https://github.lesschina.com/js/1.base/ES6與PY3.htmlcss

ES6如今瀏覽器基本上都支持了,能夠收一波韭菜了~(關鍵移動端都支持了)html

1.變量

驗證

  1. var:能夠重複定義,不能限制修改,沒有塊級做用域(和Python差很少)
  2. let:不能夠重複定義,至關於C#的變量,塊級做用域(之後var所有換成let)
  3. const:不能夠重複定義,至關於C#的常量,塊級做用域

能夠重複定義的驗證

1.var能夠重複定義前端

var a1 = 12; // 定義了一個a變量
// ...寫了若干代碼
var a1 = 5; // 而後又從新定義了一個a,這時候可能就有潛在bug了

console.log(a1); // 5

2.let不能夠重複定義,至關於C#的變量(之後var所有換成let)java

let a2 = 12;
let a2 = 5;

// 標識符a已經被聲明
console.log(a2); // Identifier 'a2' has already been declared

3.const:不能夠重複定義,至關於C#的常量react

const a3 = 12;
const a3 = 5;

// 標識符a已經被聲明
console.log(a3); // Identifier 'a3' has already been declared

能夠被修改的驗證

1.var能夠修改git

var a = 2;
a = 3;

// var 能夠修改
console.log(a); //3

2.let能夠修改github

let b = 2;
b = 3;

// let能夠修改
console.log(b);

3.const不能夠修改ajax

const c = 12;
c = 5;

// 不能賦值給常量變量
console.log(c); // Assignment to constant variable.

驗證做用域

1.var沒有塊級做用域npm

if(1<2){
    var b1 = 1;
}

// var沒有塊級做用域
console.log(b1); // 1

2.let複合正常變量特性

// 和咱們平時使用差很少了
if(1<2){
    let b2 = 1;
}

// ReferenceError: b2 is not defined
console.log(b2); // b2 沒有定義

3.更嚴格的const就更不說了

if(1<2){
    const b3 = 1;
}

// ReferenceError: b3 is not defined
console.log(b3); // b3 沒有定義

Python3

變量沒有修飾符的,直接定義,全局變量global引用便可

1.var變量和Python相似

if 1 < 2:
    b = 1
print(b) # 1

2.全局變量建議global引用一下

age = 20

def test():
    global age
    print(age) # 20

結論:(之後var所有換成let)

  1. var:能夠重複定義,不能限制修改,沒有塊級做用域(和Python差很少)
  2. let:不能夠重複定義,至關於C#的變量,塊級做用域(之後var所有換成let)
  3. const:不能夠重複定義,至關於C#的常量,塊級做用域
 

2.解構賦值

這個特性不論是C#仍是ES6都是從Python那借鑑過來的,特色:

  1. 左右兩邊結構同樣
  2. 定義和賦值同時完成

基礎

簡單版:

let [a,b,c] = [1,2,3];
console.log(a,b,c); // 1 2 3

變化版:

let {a,b,c} = {a:1,b:2,c:3}; // json格式對應也行
console.log(a,b,c); // 1 2 3

PS:把後面改爲{a1:1,b1:2,c1:3}就變成undefined undefined undefined

複雜版:

let [x, { a, b, c }, y] = [4, { a: 1, b: 2, c: 3 }, 5];
console.log(a, b, c, x, y); // 1 2 3 4 5

驗證

  1. 左右兩邊結構須要同樣

    // 這種就不行,格式得對應(左邊3,右邊5個 ==> over)
    let [x, { a, b, c }, y] = { a: 1, b: 2, c: 3, x: 4, y: 5 };
    console.log(a, b, c, x, y); // 未捕獲的TypeError:{...}不可迭代
    
  2. 定義和賦值同時完成

    let [a, b, c];
    [a, b, c] = [1, 2, 3];
    // 未捕獲的SyntaxError:在解構聲明中缺乏初始化程序
    console.log(a, b, c);
    
 

3.函數系

3.1.箭頭函數(匿名函數)

之前寫法:

function (參數,參數){
    函數體
}

簡化寫法:

(參數,參數) => {
    函數體
}

參數 => {
    函數體
}

參數 => 表達式

舉個例子

function add(x, y) {
    return x + y;
}

let add1 = function (x, y) {
    return x + y;
}

let add2 = (x, y) => {
    return x + y;
}

let add3 = (x,y) => x+y;
console.log(add(1, 2)); // 3
console.log(add1(1, 2)); // 3
console.log(add2(1, 2)); // 3
console.log(add3(1, 2)); // 3

小驗證(和Net用起來基本上同樣

  1. 若是隻有一個參數:()能夠省略
    let get_age = age => {
     return age - 2;
    }
    console.log(get_age(18)); // 16
    
  2. 若是函數體只有一句話:{}能夠省略
    • 若是隻有一句return,那麼return也能夠省略
      let get_age = age => age - 2;
      console.log(get_age(18)); // 16
      
    • 沒有return也能夠簡寫
      let print_age = age => console.log(age - 2);
      print_age(18); // 16
      

PS:箭頭函數會改變this(後面會說)


3.2.默認參數

// 原來:
function show(a, b, c) {
    c = c || 7; // 默認參數
    console.log(a, b, c);
}
// 如今:
function show(a, b, c = 7) {
    console.log(a, b, c);
}

show(1, 2); // 1 2 7
show(1, 2, 3); // 1 2 3

3.3.參數展開

基本用法

舉個例子:

let show_args = (a, b, ...args) => console.log(a, b, args);
// `...args`是個數組(Python是元組)
show_args(1, 2, 3, 4, 5, 6);// 1 2 [3, 4, 5, 6]

小驗證

  1. ...args必須是最後一個參數
    let show_args = (a, b, ...args, c) => console.log(a, b, args, c);
    // Uncaught SyntaxError: Rest parameter must be last formal parameter
    show_args(1, 2, 4, 5, 6, c = 3); // ...args必須是最後一個參數
    

PS:Python裏面能夠

def show(a, b, *args, c):
    print(a, b, args, c)

# 1 2 (4, 5, 6) 3
show(1, 2, 4, 5, 6, c=3)

擴展用法

案例1

let nums = [1, 2, 3, 4];
// 解包使用
let nums2 = [0, ...nums, 5, 6];
// [0,1,2,3,4,5,6]
console.log(nums2);

PS:Python用法相似

# 列表換成元組也同樣用
num_list = [1,2,3,4]
# 不論是列表仍是元組,這邊須要加*才能解包
num_list2 = [0,*num_list,5,6]
# [0, 1, 2, 3, 4, 5, 6]
print(num_list2)

案例2

let nums = [1, 2, 3, 4];
let nums2 = [0, 5, 6];
nums.push(...nums2);
// [1, 2, 3, 4, 0, 5, 6]
console.log(nums);

PS:Python用法相似

num_list = [1,2,3,4]
num_list2 = [0,5,6]
# [1, 2, 3, 4, 0, 5, 6]
num_list.extend(num_list2)
print(num_list)

# 若是使用append就是嵌套版列表了
# num_list.append(num_list2)
# [1, 2, 3, 4, [0, 5, 6]]

3.4.特殊的this(重要)

普通函數的this ==> 誰調用就是誰(常常變:誰調用是誰)

function show() {
    alert(this); // 1,2,3,4
    console.log(this); // [1, 2, 3, 4, show: ƒ]
}

let arr = [1, 2, 3, 4];
arr.show = show;
arr.show();

箭頭函數的this ==> 在誰的環境下this就是誰(不變:當前做用域)

let arr = [1, 2, 3, 4];
arr.show = () => {
    alert(this); // [object Window]
    console.log(this); // Window
}
arr.show();

再舉個例子:在document內

document.onclick = function () {
    let arr = [1, 2, 3, 4];
    arr.show = () => {
        console.log(this); // document
    }
    arr.show();
}
 

4.數組方法

下面幾個方法都不會改變原數組

4.1.map

映射,傳幾個參數進去,出來幾個參數。(不改變數組內容,生成新數組

基本用法

scor_arr = [100, 28, 38, 64]
let results = scor_arr.map(item => item >= 60);

// [true, false, false, true]
console.log(results); // 不改變scor_arr內容,生成新數組

// old:
// let results = scor_arr.map(function (item) {
//     return item >= 60;
// });

Python3

Python略有不一樣:(把函數依次做用在list的每一個元素上)

scor_list = [100, 28, 38, 64]
result_list = map(lambda item: item >= 60, scor_list)

# [True, False, False, True] 不改變舊list的值
print(list(result_list))

PS:result_list:PY2直接返回list,PY3返回Iterator


4.2.filter

代言詞:過濾不改變數組內容,生成新數組

基本用法

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
nums2 = nums.filter(item => item % 2 == 0);

// [2, 4, 6, 8, 10]
console.log(nums2) // 不改變舊數組的值

Python3

Python略有不一樣:(把函數依次做用在list的每一個元素上)

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
nums2 = filter(lambda item: item % 2 == 0, nums)

# [2, 4, 6, 8, 10] 不改變舊list的值
print(list(nums2))

PS:nums2:PY2直接返回list,PY3返回Iterator


4.3.forEach

不作任何修改,純粹的遍歷,用法和net裏面的ForEach差很少

forEach沒有返回值的驗證

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let sum = 0;
let temp =nums.forEach(item => {
    sum += item;
});
console.log(sum) // 55
console.log(temp) // 驗證了:forEach 沒有返回值

NetCore

var sum = 0;
var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
list.ForEach(item => sum += item);
Console.WriteLine(sum); // 55

不會改變原數組的驗證

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
nums.forEach(item => {
    item += 1;
});

// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(nums); //不會改變nums,僅僅是遍歷

NetCore

var list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
list.ForEach(item => item += 1);
foreach (var item in list)
{
    // 12345678910
    Console.Write(item); //不會改變list裏面的值
}

4.4.reduce

代言詞:彙總,和map有點相反,進去一堆出來一個

基礎用法

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// x是第一個元素,y是第二個元素
nums.reduce((x, y, index) => {
    console.log(x, y, index);
});

輸出:

1 2 1
undefined 3 2
undefined 4 3
undefined 5 4
undefined 6 5
undefined 7 6
undefined 8 7
undefined 9 8
undefined 10 9

逆推JS執行過程

逆推整個執行過程

  1. x只被賦值一次
  2. y從第二個值開始往下遍歷
  3. 整個過程只遍歷9遍就結束了
    • for循環須要10次遍歷結束
    • y從第二個數開始的,少一次遍歷也正常

簡單說就是按順序依次執行函數,eg:

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
result = nums.reduce((x, y) => x + y);
console.log(result / nums.length) // 5.5

reduce直接求平均值:(return是關鍵)

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result = nums.reduce((temp, item, index) => {
    temp += item;
    if (index < nums.length - 1) {
        return temp;
    } else { // 最後一次,返回平均值便可
        return temp / nums.length;
    }
});
console.log(result) // 5.5

Python3

reduce就兩個參數(有且僅有

PythonReducejs的強大,通常都是對列表作一個累積的‘彙總’操做

import functools
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = functools.reduce(lambda x, y: x + y, nums)
print(result / len(nums)) # 5.5

能夠看看執行過程:

import functools

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = functools.reduce(lambda x, y: print(x, y), nums)
print(result)

輸出:

1 2
None 3
None 4
None 5
None 6
None 7
None 8
None 9
None 10
None

4.5.Array.from

通俗講:把類數組集合轉化成數組

HTML代碼:/BaseCode/javascript/1.ES6/1.array.from.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Array.from的應用</title>
</head>
<body>
    <style type="text/css">
        div {
            width: 200px;
            height: 200px;
            margin-right: 1px;
            float: left;
        }
    </style>
    <div></div>
    <div></div>
    <div></div>
</body>
</html>

JS部分:(collection是沒有forEach方法的,須要轉化成數組)

window.onload = () => {
    let collection = document.getElementsByTagName("div");
    Array.from(collection).forEach(item => item.style.background = "blue");
}
 

5.JSON系

鍵值相同能夠只寫一個

let [a, b] = [1, 2];
json = { a, b, c: 3 };
console.log(json); // {a: 1, b: 2, c: 3}

// 原來寫法
// json = { a: a, b: b, c: 3 };

函數function能夠省略

json = {
    a: 1,
    b: 2,
    show() {
        console.log(this.a, this.b);
    }
};
json.show(); // 1 2

// 原來寫法
// json = {
//     a: 1,
//     b: 2,
//     show: function () {
//         console.log(this.a, this.b);
//     }
// };

基礎複習

Json字符串的標準寫法

  1. 只能用雙引號
  2. 全部名字必須用引號包裹
let str1 = '{ a: 12, b: 5 }'; // 錯誤
let str2 = '{ "a": 12, "b": 5 }';// 正確
let str3 = "{ 'a': 'abc', 'b': 5 }";// 錯誤(單引號)
let str4 = '{ "a": "abc", "b": 5 }';// 正確(雙引號)

// 測試是否爲字符串
[str1, str2, str3, str4].forEach(str => {
    try {
        let json = JSON.parse(str);// 轉換成JSON對象
        console.log(json);
    } catch (ex) {
        console.log(`字符串:${str}轉換髮生異常:${ex}`);
    }
});

輸出:

字符串:{ a: 12, b: 5 }轉換髮生異常:SyntaxError: Unexpected token a in JSON at position 2
1.base.json.html:21 {a: 12, b: 5}
1.base.json.html:23 字符串:{ 'a': 'abc', 'b': 5 }轉換髮生異常:SyntaxError: Unexpected token ' in JSON at position 2
1.base.json.html:21 {a: "abc", b: 5}

字符串和Json相互轉換

  1. 字符串轉換成Json對象:JSON.parse()
  2. Json對象轉換成字符串:JSON.stringify()
let json1 = { name: "小明", age: 23, test: "我X!@#$%^&*(-_-)=+" };
let new_str = JSON.stringify(json1);
console.log(new_str);

// encodeURI對有些特殊符號並不會編碼替換
let urlstr = encodeURIComponent(`https://www.baidu.com/s?wd=${new_str}`);
console.log(urlstr);
console.log(decodeURIComponent(urlstr));

輸出:

{"name":"小明","age":23,"test":"我X!@#$%^&*(-_-)=+"}

https://www.baidu.com/s?wd=%7B%22name%22:%22%E5%B0%8F%E6%98%8E%22,%22age%22:23,%22test%22:%22%E6%88%91X!@#$%25%5E&*(-_-)=+%22%7D

https%3A%2F%2Fwww.baidu.com%2Fs%3Fwd%3D%7B%22name%22%3A%22%E5%B0%8F%E6%98%8E%22%2C%22age%22%3A23%2C%22test%22%3A%22%E6%88%91X!%40%23%24%25%5E%26*(-_-)%3D%2B%22%7D

https://www.baidu.com/s?wd={"name":"小明","age":23,"test":"我X!@#$%^&*(-_-)=+"}
 

5.字符串系

1.字符串模板

渲染變量

省的一個個去拼接了(PS:反單引號

let [name,age]=["小明",23];

// 我叫小明,我今年23
console.log(`我叫${name},我今年${age}`);

Python3用起來差很少

name, age = "小明", 23

# 我叫小明,今年23
print(f"我叫{name},今年{age}")

保持原有格式

注意一點:換行內容若是不想要空格就頂行寫

console.log(`我叫:
小明
今年:
23`);

輸出:

我叫:
小明
今年:
23

Python就換成了"""

print("""我叫:
小明
今年:
23
""")

2.開頭結尾方法

基本用法

let url = "https://www.baidu.com";

if (url.startsWith("http://") || url.startsWith("https://")) {
    console.log("B/S");
}

if (url.endsWith(".com")) {
    console.log(".com")
}

Python3

url = "https://www.baidu.com"

if url.startswith("https://") or url.startswith("http://"):
    print("B/S")

if url.endswith(".com"):
    print(".com")
In [ ]:
 
 

Ⅱ.ES6~OOP

參考文檔:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes

之前JS的OOP嚴格意義上仍是一個個函數,只是人爲給他含義罷了,如今是真的支持了,性能和語法都優化了

1.封裝

// People後面沒有括號
class People {
    // 構造函數
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    show() {
        console.log(`我叫:${this.name},今年${this.age}`);
    }
    // 靜態方法
    static hello() {
        console.log("Hello World!");
    }
}
// new別忘記了
let xiaoming = new People("小明", 23);
xiaoming.show(); //我叫:小明,今年23
// xiaoming.hello(); 這個不能訪問(PY能夠)
People.hello(); //Hello World!

看看Python怎麼定義的:(self每一個都要寫)

class People(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show(self):
        print(f"我叫:{self.name},今年:{self.age}")

    @classmethod
    def hello(cls):
        print("Hello World!")


xiaoming = People("小明", 23)
xiaoming.show()  # 我叫:小明,今年:23
# 這個雖然能夠訪問到,但我一直都不建議這麼用(否則用其餘語言會混亂崩潰的)
xiaoming.hello()  # Hello World!
People.hello()  # Hello World!

PS:JS後來居上,看起來語法比PY更簡潔點了

2.繼承

class Teacher extends People {
    constructor(name, age, work) {
        super(name, age); // 放上面
        this.work = work;
    }
    show_job() {
        console.log(`我是作${this.work}工做的`);
    }
}
let xiaozhang = new Teacher("小張", 25, "思想教育");
xiaozhang.show(); // 我叫:小張,今年25
xiaozhang.show_job(); // 我是作思想教育工做的
Teacher.hello(); // Hello World!

PS:若是子類中存在構造函數,則須要在使用this以前首先調用super()

看看Python語法:

class Teacher(People):
    def __init__(self, name, age, work):
        self.work = work
        super().__init__(name, age)

    def show_job(self):
        print(f"我是作{self.work}工做的")


xiaozhang = Teacher("小張", 25, "思想教育")
xiaozhang.show()  # 我叫:小張,今年:25
xiaozhang.show_job()  # 我是作思想教育工做的
Teacher.hello()  # Hello World!

3.多態

多態這方面和Python同樣,有點後勁不足,只能僞實現,不能像Net、Java這些這麼強大

class Animal {
    constructor(name) {
        this.name = name;
    }
    run() {
        console.log(`${this.name}會跑`);
    }
}
class Dog extends Animal {
    run() {
        console.log(`${this.name}會飛快的跑着`);
    }
}
// 藉助一個方法來實現多態
let run = obj => {
    obj.run()
}
run(new Animal("動物")); // 動物會跑
run(new Dog("小狗")); // 小狗會飛快的跑着

Python也半斤八兩,十分類似

class Animal(object):
    def __init__(self, name):
        self.name = name

    def run(self):
        print(f"{self.name}會跑")

class Dog(Animal):
    def run(self):
        print(f"{self.name}會飛快的跑着")

# 藉助一個方法來實現多態
def run(obj):
    obj.run()

run(Animal("動物"))  # 動物會跑
run(Dog("小狗"))  # 小狗會飛快的跑着
 

業餘拓展

函數中的bind

直接指定函數中this的值,防止改變

若是指定一個事件執行函數的時候,class裏面的this會變化,這時候不想外面套一層方法就可使用bind

class People {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    show() {
        console.log(this);
        console.log(`我叫:${this.name},今年${this.age}`);
    }
}

let p = new People("小明", 23);

// 按照道理應該能夠,可是由於this變了,因此不行
//document.onclick = p.show; // 我叫:undefined,今年undefined

// 原來寫法:外面包裹一層方法
//document.onclick = () => p.show(); // 我叫:小明,今年23

// 簡寫:bind
document.onclick = p.show.bind(p); // 我叫:小明,今年23

幾個驗證

小驗證:直接指定函數中this的值,防止改變

function show() {
    console.log(this);
}
document.onclick = show; // document
document.onclick = show.bind("mmd"); // String {"mmd"}

小驗證箭頭函數的優先級比bind高

document.onclick = function () {
    let arr = [1, 2, 3, 4];
    arr.show = () => {
        console.log(this); // document
    }
    arr.show.bind("mmd"); // 箭頭函數的優先級比bind高
    arr.show();
}

ES6繼承的不足

  1. 只支持靜態方法,不支持靜態屬性
  2. class中不能定義私有變量和函數
    • class中定義的全部方法都會被放倒原型當中,都會被子類繼承,而屬性都會做爲實例屬性掛到this上

課後拓展:https://www.jianshu.com/p/5cb692658704

Python3與NetCore

Python3 與 C# 面向對象之~封裝http://www.javashuo.com/article/p-purcxavn-d.html

Python3 與 C# 面向對象之~繼承與多態http://www.javashuo.com/article/p-ticxscaz-cv.html

 

4.OOP實戰

微信小程序出來後,組件化的概念愈來愈火(能夠理解爲模塊化),結合OOP真的很方便

4.1.React組件引入

先看個React的基礎案例(結合Next.js更爽)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>React組件化</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="./js/react/16.6.3/react.production.min.js"></script>
    <script src="./js/react-dom/16.6.3/react-dom.production.min.js"></script>
    <script src="./js/babel-core/5.8.38/browser.min.js"></script>
    <!-- 注意下類型是"text/babel" -->
    <script type="text/babel">
    window.onload=function () {
        let item = document.getElementById("test");
        ReactDOM.render(
            <strong>公衆號逸鵬說道</strong>,
            item
        );
    };
    </script>
</head>
<body>
    <div id="test"></div>
</body>
</html>

輸出:公衆號:逸鵬說道

擴展說明

業餘擴展:AMDCMDCJSUMDhttps://blog.csdn.net/yikewang2016/article/details/79358563

1.React and babel

PS:React 16.x開始

  1. react.js ==> react.development.js
    • react.min.js ==> react.production.min.js
  2. react-dom.js ==> react-dom.development.js
    • react-dom.min.js ==> react-dom.production.min.js

PS:若是本身找JS,搜索三個包:reactreact-dombabel-core 5.x(JSX)

2.npm and cnpm

npm國內鏡像https://npm.taobao.org

配置一下便可:npm install -g cnpm --registry=https://registry.npm.taobao.org

而後就能夠把cnpm看成npm來用了,好比上面三個js文件:

  1. cnpm install react
  2. cnpm install react-dom
  3. cnpm i babel-core@old

PS:iinstall的簡寫,-g是安裝到全局環境中,不加就只是安裝到當前目錄


4.2.OOP組件

1.OOP改造

OOP來改造一下上面的案例:(ReactDOM在執行render渲染<MyTest>標籤的時候會返回,MyTest類裏面的return值

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>OOP組件</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="./js/react/16.6.3/react.production.min.js"></script>
    <script src="./js/react-dom/16.6.3/react-dom.production.min.js"></script>
    <script src="./js/babel-core/5.8.38/browser.min.js"></script>
    <script type="text/babel">
        class MyTest extends React.Component{
            // 能夠省略
            constructor(...args){
                super(...args);
            }
            // 必須定義的方法
            render(){
                return <strong>公衆號逸鵬說道</strong>;
            }
        }
        window.onload=()=>{
            let test = document.getElementById("test");
            ReactDOM.render(
                <MyTest></MyTest>,
                test
            );
        }
    </script>
</head>
<body>
    <div id="test"></div>
</body>
</html>

輸出:公衆號:逸鵬說道

語法衍生

好處經過這個案例可能還看不出來,可是你想一下:當那些經常使用功能模板成爲一個個本身的組件時,你的每一次前端開發是多麼幸福的事情?

再語法衍生一下,來個稍微動態一點案例:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>OOP組件</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="./js/react/16.6.3/react.production.min.js"></script>
    <script src="./js/react-dom/16.6.3/react-dom.production.min.js"></script>
    <script src="./js/babel-core/5.8.38/browser.min.js"></script>
    <script type="text/babel">
        class Item extends React.Component{
            render(){
                console.log(this);
                return <strong>{this.props.str}</strong>;
            }
        }
        window.onload=()=>{
            ReactDOM.render(<Item str="我叫小明"></Item>,document.getElementById("test"));
        }
    </script>
</head>
<body>
    <div id="test"></div>
</body>
</html>

輸出:(兩種方式傳參:1.字符串,2.{}表達式) 我叫小明

自定義組件

有上面兩個鋪墊,如今作個本身的小組件:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>OOP組件</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="./js/react/16.6.3/react.production.min.js"></script>
    <script src="./js/react-dom/16.6.3/react-dom.production.min.js"></script>
    <script src="./js/babel-core/5.8.38/browser.min.js"></script>
    <script type="text/babel">
        class Item extends React.Component{
            render(){
                console.log(this);
                return <li><strong>{this.props.str}</strong></li>;
            }
        }
        class MyList extends React.Component{            
            render(){
                console.log(this);
                return <ul>
                {this.props.names.map(x=> <Item str={x}></Item>)}
                </ul>
            }
        }
        window.onload=()=>{
            let test = document.getElementById("test");
            ReactDOM.render(
                // 這邊的值能夠從後臺獲取
                <MyList names={["Golang","Python","NetCore","JavaScript"]}></MyList>,
                test
            );
        }
    </script>
</head>

<body>
    <div id="test"></div>
</body>
</html>

輸出:(兩種方式傳參:1.字符串,2.{}表達式) 我叫小明

In [ ]:
 
 

Ⅲ.ES6~EXT

課後拓展:https://www.babeljs.cn/learn-es2015/

1.異步

最後方案和寫法相似於PythonNetCore,都是asyncawait,前面是一步步引入(本質)

1.1.JQ引入

常見情景

基於JQ的異步操做很常見,好比:

console.log("--------------------")
$.ajax({
    url: "./data/user.json",
    dataType: "json",
    success(data) {
        console.log(data);
    }, error(ex) {
        console.log("請求失敗");
    }
});
console.log("--------------------")

輸出:(的確是異步操做,不等結果返回就先執行下面語句了)

--------------------
--------------------
{Name: "小明", Age: 23}

探討本質

那麼它的本質是什麼呢?來看看返回什麼:

let p1 = $.ajax({
    url: "./data/user.json",
    dataType: "json"
});
console.log(p1);

輸出:(其實本質也是一個封裝版的PromiseJQ

用等價寫法改裝一下:(then兩個方法,一個處理成功,一個處理失敗

let p1 = \$.ajax({
    url: "./data/user.json",
    dataType: "json"
});

// 不存在的文件
let p2 = \$.ajax({
    url: "./data/mmd.json",
    dataType: "json"
});

p1.then(data => console.log(data), ex => console.log("請求失敗"));
p2.then(data => console.log(data), ex => console.log("請求失敗"));

輸出:(忽略上面的\個人渲染有的問題,須要轉義一下)

{Name: "小明", Age: 23}
請求失敗

1.2.Promise

簡單的說就是:Promise:用同步的方式去寫異步

語法:Promise(()=>{});

有點相似於NetCoreTask==> Task.Run(()=>{});

上面的那個例子本質上至關於:

let p1 = new Promise((resolve, reject) => {
    $.ajax({
        url: "./data/user.json",
        dataType: "json",
        success(data) {
            resolve(data);
        },
        error(ex) {
            reject(ex);
        }
    });
});
p1.then(data => console.log(data), ex => console.log("請求失敗"));

業務上不免都有相互依賴,之前寫法也只能在sucess回調函數裏面一層層的嵌套

一個是比較麻煩,還有就是看起來特別不方便,一不當心就搞錯了,如今就簡單多了,then裏面直接處理

咋一看,沒啥好處啊?並且還複雜了,其實當任務多的時候好處就來了

好比結合JQ來模擬一個事務性的案例

let p1 = $.ajax({ url: "./data/user.json", dataType: "json" });
let p2 = $.ajax({ url: "./data/list.txt", dataType: "json" });
let p3 = $.ajax({ url: "./data/package.json", dataType: "json" });

// 進行一系列處理(有一個失敗都會直接進入錯誤處理)
Promise.all([p1, p2, p3]).then(arr => {
    // 這時候返回的是一個數組
    console.log(arr);
}, ex => {
    console.error(ex);
});

輸出: Promise

 

2.迭代器

這個簡單過一下,和Python沒有太多不一樣

2.1.引入

function*來定義一個迭代器

function* show() {
    console.log("a");
    yield "1";
    console.log("b");
    yield "2";
    console.log("c");
    return "d";
}

let gen = show();
// 每一次next都執行到下一個yield中止
console.log(gen.next());
// 返回值.value 能夠獲得yield返回的值
console.log(gen.next().value);
// done==true的時候表明迭代結束
console.log(gen.next());

輸出:

a
{value: "1", done: false}
b
2
c
{value: "d", done: true}

2.2.遍歷

JavaScript

經過上面輸出能夠瞬間知道退出條件:done: true,那麼遍歷方式就來了:

function* show() {
    yield "1";
    yield "2";
    return "d";
}
let gen = show();

while (true) {
    let result = gen.next();
    if (result.done) {
        console.log(`返回值:${result.value}`);
        break;
    } else {
        console.log(result.value);
    }
}

輸出:

1
2
返回值:d

JS也提供了for of來遍歷:

for (let item of show()) {
    console.log(item);
}

Python3

大致上差很少,結束條件是觸發StopIteration異常

def show():
    yield "1"
    yield "2"
    return "d"

gen = show()

while True:
    try:
        print(next(gen))
    except StopIteration as ex:
        print(f"返回值:{ex.value}")
        break

for item in show():
    print(item)  # 1 2

輸出:

1
2
返回值:d
1
2

2.3.傳參

JavaScript

function* show2() {
    a = yield "111";
    console.log(a);
    b = yield a;
    console.log(b);
    c = yield b;
    console.log(c);
    return "over";
}

let gen = show2();
// 和Python同樣,第一個不傳參
console.log(gen.next());
console.log(gen.next("aaa"));
console.log(gen.next("bbb"));
console.log(gen.next("ccc"));

輸出:

{value: "111", done: false}
aaa
{value: "aaa", done: false}
bbb
{value: "bbb", done: false}
ccc
{value: "over", done: true}

Python3

傳參Python是使用的send方法,其實next本質也是send,這個以前講過了:

def show():
    a = yield "111"
    print(a)
    b = yield a
    print(b)
    c = yield b
    print(c)
    return "over"

gen = show()
# 第一個不傳參
print(next(gen))  # gen.send(None)
print(gen.send("aaa"))
print(gen.send("bbb"))
try:
    print(gen.send("ccc"))
except StopIteration as ex:
    print(ex.value)

輸出:

111
aaa
bbb
bbb
ccc
over
 

3.async/await

若是你如今尚未用過asyncawait的話...須要好好提高下了,仍是通俗說下吧:

  1. await你能夠理解爲:等待後面異步方法的結果,這時候的結果就是你須要的
  2. async你能夠理解爲:使用了await的方法須要特殊標記一下

3.1.引入

ES6出來前,咱們用異步通常是這麼用的:

  1. 和下文JS不關聯的外部JS,都打個異步標籤來異步加載
  2. <script src="./js/test.js" async></script>

如今能夠正經的使用了,繼續把上面那個例子衍生下:(以前用then(()=>{},()=>{}),如今可使用asyncawait來簡化)

async function show(url) {
    let data = await $.ajax({ url: url, dataType: 'json' });
    console.log(data)
}
show("./data/list.txt")

輸出:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

3.2.批量

就算是批量任務也不用那麼麻煩了:

let show = async (urls) => {
    for (const url of urls) {
        let data = await $.ajax({ url: url, dataType: "json" });
        console.log(data);
    }
}

show(["./data/user.json", "./data/list.txt", "./data/package.json"]);

輸出:

{Name: "小明", Age: 23}
[1, 2, 3, 4, 5, 6, 7, 8, 9]
{name: "data", version: "0.1.0", description: "測試", main: "index.js", scripts: {…}, …}

3.3.匿名

應用常見其實不少,好比執行某個事件、好比引入某個外部JS...,eg:

test.js

(async () => {
    let data = await $.ajax({ url: "./data/list.txt", dataType: 'json' });
    console.log(data);
})();

HTML中引用一下:<script src="./js/test.js" async></script>

輸出:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

3.4.嵌套

NetCore同樣,能夠嵌套使用的,await的對象通常都是Promise或者同是async修飾的方法

舉個例子

test.js

let show = async (urls) => {
    for (const url of urls) {
        let data = await $.ajax({ url: url, dataType: "json" });
        console.log(data);
    }
    return "ok";
}

let test = async () => {
    let result = await show(["./data/user.json", "./data/list.txt", "./data/package.json"]);
    return result;
}

頁面

<script src="./js/test.js"></script>
<script>
    (async () => {
        let data = await test();
        console.log(data);
    })();
</script>

輸出:

{Name: "小明", Age: 23}
[1, 2, 3, 4, 5, 6, 7, 8, 9]
{name: "data", version: "0.1.0", description: "測試", main: "index.js", scripts: {…}, …}
ok

Python3

Python3.7開始,語法纔開始簡潔:

import asyncio

# 模擬一個異步操做
async def show():
    await asyncio.sleep(1)
    return "寫完文章早點睡覺哈~"

# 定義一個異步方法
async def test(msg):
    print(msg)
    return await show()

# Python >= 3.7
result = asyncio.run(test("這是一個測試"))
print(result)

# Python >= 3.4
loop = asyncio.get_event_loop()
result = loop.run_until_complete(test("這是一個測試"))
print(result)
loop.close()

輸出:

這是一個測試
寫完文章早點睡覺哈~
 

4.模塊化

這個ES6裏面有,可是瀏覽器並無徹底支持,因此如今你們仍是用Require.jsSea.js更多點

簡單看看就行:擴展連接 ~ https://www.cnblogs.com/diligenceday/p/5503777.html

模塊定義:

export { a, test, user }

let test = () => {
    console.log("test");
}

let user = () => {    
    console.log("user");
    return "小明";
}

let a = 1;

導入模塊:

import { a, test, user } from "./mod.js"
console.log(a);
test();
console.log(user());
相關文章
相關標籤/搜索