Ⅰ.ES6~POP¶
代碼示例:https://github.com/lotapp/BaseCode/tree/master/javascript/1.ES6
在線演示:https://github.lesschina.com/js/1.base/ES6與PY3.html
ES6現在瀏覽器基本上都支持了,可以收一波韭菜了~(關鍵移動端都支持了)
1.變量¶
驗證¶
var
:可以重復定義,不能限制修改,沒有塊級作用域(和Python差不多)let
:不可以重復定義,相當於C#的變量,塊級作用域(以后var全部換成let)const
:不可以重復定義,相當於C#的常量,塊級作用域
可以重復定義的驗證¶
1.var可以重復定義
var a1 = 12; // 定義了一個a變量
// ...寫了若干代碼
var a1 = 5; // 然后又重新定義了一個a,這時候可能就有潛在bug了
console.log(a1); // 5
2.let不可以重復定義,相當於C#的變量(以后var全部換成let)
let a2 = 12;
let a2 = 5;
// 標識符a已經被聲明
console.log(a2); // Identifier 'a2' has already been declared
3.const:不可以重復定義,相當於C#的常量
const a3 = 12;
const a3 = 5;
// 標識符a已經被聲明
console.log(a3); // Identifier 'a3' has already been declared
可以被修改的驗證¶
1.var
可以修改
var a = 2;
a = 3;
// var 可以修改
console.log(a); //3
2.let
可以修改
let b = 2;
b = 3;
// let可以修改
console.log(b);
3.const
不可以修改
const c = 12;
c = 5;
// 不能賦值給常量變量
console.log(c); // Assignment to constant variable.
驗證作用域¶
1.var沒有塊級作用域
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
)¶
var
:可以重復定義,不能限制修改,沒有塊級作用域(和Python差不多)let
:不可以重復定義,相當於C#的變量,塊級作用域(以后var全部換成let)const
:不可以重復定義,相當於C#的常量,塊級作用域
2.解構賦值¶
這個特性不管是C#
還是ES6
都是從Python
那借鑒過來的,特點:
- 左右兩邊結構一樣
- 定義和賦值同時完成
基礎¶
簡單版:
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
驗證¶
-
左右兩邊結構需要一樣
// 這種就不行,格式得對應(左邊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:{...}不可迭代
-
定義和賦值同時完成
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用起來基本上一樣
)¶
- 如果只有一個參數:
()
可以省略let get_age = age => { return age - 2; } console.log(get_age(18)); // 16
- 如果函數體只有一句話:
{}
可以省略- 如果只有一句
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]
小驗證¶
...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執行過程¶
逆推整個執行過程:
- x只被賦值一次
- y從第二個值開始往下遍歷
- 整個過程只遍歷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就兩個參數(有且僅有
)
Python
的Reduce
沒js
的強大,一般都是對列表做一個累積的‘匯總’操作
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
字符串的標准寫法:
- 只能用雙引號
- 所有名字必須用引號包裹
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相互轉換:
- 字符串轉換成Json對象:
JSON.parse()
- 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")
Ⅱ.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繼承的不足¶
- 只支持靜態方法,不支持靜態屬性
- class中不能定義私有變量和函數
- class中定義的所有方法都會被放倒原型當中,都會被子類繼承,而屬性都會作為實例屬性掛到this上
課后拓展:https://www.jianshu.com/p/5cb692658704
Python3與NetCore¶
Python3 與 C# 面向對象之~封裝: https://www.cnblogs.com/dotnetcrazy/p/9202988.html
Python3 與 C# 面向對象之~繼承與多態: https://www.cnblogs.com/dotnetcrazy/p/9219226.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>
輸出:公眾號:逸鵬說道
擴展說明¶
業余擴展:AMD
、CMD
、CJS
、UMD
: https://blog.csdn.net/yikewang2016/article/details/79358563
1.React and babel¶
PS:React 16.x
開始:
react.js
==>react.development.js
react.min.js
==>react.production.min.js
react-dom.js
==>react-dom.development.js
react-dom.min.js
==>react-dom.production.min.js
PS:如果自己找JS,搜索三個包:react
、react-dom
、babel-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文件:
cnpm install react
cnpm install react-dom
cnpm i babel-core@old
PS:i
是install
的簡寫,-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.{}表達式)
Ⅲ.ES6~EXT¶
課后拓展:https://www.babeljs.cn/learn-es2015/
1.異步¶
最后方案和寫法類似於Python
、NetCore
,都是async
和await
,前面是一步步引入(本質)
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);
輸出:(其實本質也是一個封裝版的Promise
)
用等價寫法改裝一下:(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(()=>{});
有點類似於NetCore
的Task
==> 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);
});
輸出:
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
¶
如果你現在還沒有用過async
和await
的話...需要好好提升下了,還是通俗說下吧:
- await你可以理解為:等待后面異步方法的結果,這時候的結果就是你需要的
- async你可以理解為:使用了await的方法需要特殊標記一下
3.1.引入¶
ES6出來前,我們用異步一般是這么用的:
- 和下文JS不關聯的外部JS,都打個異步標簽來異步加載
<script src="./js/test.js" async></script>
現在可以正經的使用了,繼續把上面那個例子衍生下:(之前用then(()=>{},()=>{})
,現在可以使用async
和await
來簡化)
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.js
和Sea.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());