javascript的ES6學習總結(第三部分)

来源:https://www.cnblogs.com/abc-x/archive/2019/05/04/10799583.html
-Advertisement-
Play Games

1.ES6中的面向對象的類 1.1、定義類 在ES5中,我們寫一個類,通常是這麼寫的 在ES6中,我們可以這樣寫 註意: (1).ES6裡面Class沒有提升(例如ES5中的函數有提升到頂部的作用) (2).ES6中的this,首先來看一下ES5中矯正this的幾個方法 (2.1) fn.call( ...


1.ES6中的面向對象的類

1.1、定義類

在ES5中,我們寫一個類,通常是這麼寫的

function Person(name,age){
    this.name = name;
    this.age = age;
}
/**
 * es5中的模擬面向對象的類的方法 寫法1
Person.prototype.showName = function(){
    return "名字為:"+this.name;
}
Person.prototype.showAge = function(){
    return "年齡為:"+this.age;
}*/

/**
 * es5中的模擬面向對象的類的方法 寫法2
 *
 */
Object.assign(Person.prototype,{
    showName(){
        return "名字為:"+this.name;
    },
    showAge(){
        return "年齡為:"+this.age;
    }
});
var p1 = new Person('tom',18);
console.log(p1.showName());//名字為:tom
console.log(p1.showAge());//年齡為:18

在ES6中,我們可以這樣寫

//ES6中的類(類名大小寫都可以,推薦使用規範按照首字母大寫)
class Person{
    constructor(name,age){//構造方法(函數),每new一個新對象,自動執行
        // console.log(`構造函數執行了,${name},${age}`);//構造函數執行了,Lucy,18
        this.name = name;
        this.age = age;
    }
    showName(){
        return `名字為:${this.name}`;
    }
    showAge(){
        return `年齡為:${this.age}`;
    }
}
let p1 = new Person('Lucy',18);
console.log(p1.showName(),p1.showAge());//名字為:Lucy 年齡為:18
//ES6中的類(賦給一個變數或常量,類名大小寫都可以,推薦使用規範首字母大寫)
const Person =  class{
    constructor(name,age){//構造方法(函數),每new一個新對象,自動執行
        // console.log(`構造函數執行了,${name},${age}`);//構造函數執行了,Lucy,18
        this.name = name;
        this.age = age;
    }
    showName(){
        return `名字為:${this.name}`;
    }
    showAge(){
        return `年齡為:${this.age}`;
    }
}
let p1 = new Person('Lucy',18);
console.log(p1.showName(),p1.showAge());//名字為:Lucy 年齡為:18

註意:

1).ES6裡面Class沒有提升(例如ES5中的函數有提升到頂部的作用)

2).ES6中的this,首先來看一下ES5中矯正this的幾個方法

(2.1) fn.call(this指向誰,args1,args2...);

(2.2) fn.apply(this指向誰,[args1,args2...]);

(2.3) fn.bind();(React中經常會用到)

其中,(2.1) fn.call和(2.2) fn.apply都會在矯正this的時候,方法(函數)會調用一次

class Person{
    constructor(){
        this.name = 'jason';
        this.showName = this.showName.bind(this);//矯正this
    }
    showName(){
        console.log('this:',this);//this: Person {name: "jason", showName: function}
        return `名字為:${this.name}`;
    }
}
let p1 = new Person();
let {showName} = p1;
console.log(showName());//名字為:jason

1.2、類裡面的取值函數(getter)和存值函數(setter):

class Person{
    constructor(name){
        this.name = name;
    }
    get aaa(){
        return `獲取aaa的名字,值為${this.name}`;
    }
    set aaa(val){
        console.log(`設置aaa的名字,值為${val}`);
    }
}
let p1 = new Person('jack');
console.log(p1.aaa);//獲取aaa的名字,值為jack
p1.aaa = 'luke';//設置aaa的名字,值為luke

1.3、類裡面的靜態方法(就是類身上的方法)

class Person{
    constructor(){

    }
    showName(){
        return '這是showName方法';
    }
    static aaa(){
        return '這是靜態方法';
    }
}
let p1 = new Person();
console.log(p1.showName());//這是showName方法
console.log(Person.aaa());//這是靜態方法

1.4、類裡面的繼承

先來回顧一下ES6之前的繼承寫法

1.原型鏈繼承

//父類
Animal.prototype.eat = function(food) {
    console.log(this.name + '正在吃' + food);            
}
function Animal(name) {
    this.color = ['green','red','blue'];
    this.name = name || 'animal';
    this.sleep = function() {
        console.log(this.name + "正在睡覺")
    }
}

原型鏈繼承核心: 將父類的實例作為子類的原型。

//子類
function Cat(name) {
    this.name = name
    this.color = ['green','red','blue'];//引用類型值,,所有實例會共用這個屬性。
}
Cat.prototype = new Animal();
var cat = new Cat('cat');
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat instanceof Animal);
console.log(cat.sleep());

缺點:

但是,原型鏈式繼承並沒有實現代碼的復用,一些共同的屬性:如name,在子類中還是得重新寫一遍(即同一套代碼還是得重新寫)。

再者,cat繼承了Animal實例的所有屬性和方法,這些方法並不都是我們需要的,也就是過多的繼承了沒有用的屬性。且如果原型中包含引用類型值,那麼所有的實例會共用這個屬性。

2.構造函數繼承

function Person(name,age,sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
}
function Student(name,age,sex){
    Person.call(this,name,age,sex);
    this.grade = grade;
}
let student = new Student;

優點:

  • 構造函數模式繼承實現了代碼的復用

缺點:

  • 不能繼承借用的構造函數的原型,只能借用構造函數本身的屬性和方法
  • 每次構造函數都要多走一個函數

3.組合繼承

// 父類
function Person(name){
    this.name = name;
}
Person.prototype.showName = function(){
    return `名字是:${this.name}`
};
// 子類
function Student(name,age){
    Person.call(this,name);//繼承屬性,在創建實例時第二次調用Person
    this.age = age;
}
Student.prototype = new Person();//繼承方法,第一次調用Person
Student.prototype.constructor = Student;//矯正constructor
Student.prototype.sayName = function(){
    return '年齡是:'+this.age;
}
// 調用
var stu1 = new Student('jack',20);
console.log(stu1.name);//jack
console.log(stu1.showName);//function (){return `名字是:${this.name}`}
console.log(stu1.showName());//名字是:jack
console.log(stu1.sayName());//年齡是:20

缺點:

  • 父類構造函數被調用2次,子類實例的屬性存在兩份,一份在原型上,一份在實例屬性上。造成記憶體的浪費。

4.寄生組合式繼承

寄生組合式繼承是對組合繼承的進一步優化。我們先看一下為什麼要寫這個語句。

SubType.prototype = new SuperType();

我們無非是想讓SubType繼承SuperType的原型。但是我們為什麼不直接寫成這樣呢?

SubType.prototype = SuperType.prototype

這樣寫確實可以實現子類對象對父類對象原型的繼承。但是這樣寫的話:所有繼承該父類的子類對象的原型都指向同一個了。也就是說SubType不能有自己的原型了。這顯然不是我們想要的。

既然不能直接繼承,那可不可以間接繼承SuperType.prototype呢。這就是最終的解決方案:寄生組合式繼承

我們讓一個函數去指向SuperType.prototype,然後讓SubType.prototype指向這個函數產生的對象不就可以了嘛。

function inherit(Target,Origin) {//實現寄生組合式繼承的核心函數
    function F() {};
    F.prototype = Origin.prototype; //F()的原型指向的是Origin
    Target.prototype = new F(); //Target的原型指向的是F()
    Target.prototype.constructor = Target; 
    SubType.prototype.__proto__ == SuperType.prototype
}

function SuperType(name) {
    this.name = name;
    this.colors = ['red','blue','pink'];
}
SuperType.prototype.sayName = function() {
    console.log(this.name);
}
function SubType(name,age) {
    //繼承屬性
    SuperType.call(this,name);//在創建實例時第二次調用SuperType
    this.age = age;
}

inherit(SubType,SuperType);//實現寄生組合式繼承

我們再來看一下實現寄生組合式繼承的核心函數。F函數其實是通用的,我們沒必要每次進入inherit函數時都聲明一遍。所以我們可以用閉包的形式來寫:

var inherit = (function () {
        var F = function () {};
        return function (Target , Origin) {
            F.prototype = Origin.prototype;//F()的原型指向的是Origin
            Target.prototype = new F();//Target的原型指向的是F()
            Target.prototype.constructor = Target;
            Target.prototype.uber = Origin.prototype;
            SubType.prototype.__proto__ == SuperType.prototype
        }
    })()

再來看看ES6繼承的寫法,相比前面就優雅了許多,代碼量也會少很多!!!

/* ES6繼承 */
// 父類
class Person{
    constructor(name){
        this.name = name;
    }
    showName(){
        return `名字為:${this.name}`;
    }
}
// 子類
class Student extends Person{

}
// 調用
var stu1 = new Student('jack');
console.log(stu1.showName());//名字為:jack

子類在自己的身上加方法:

/* ES6繼承 */
// 父類
class Person{
    constructor(name){
        this.name = name;
    }
    showName(){
        return `名字為:${this.name}`;
    }
}
// 子類
class Student extends Person{
    constructor(name,skill){
        super(name);//子類的構造函數必須有super(),相當於執行一次父級的構造函數
        this.skill = skill;
    }
    showSkill(){
        return `他的名字是${this.name},他的特長是${this.skill}`;
    }
}
// 調用
var stu1 = new Student('jack','跳舞');
console.log(stu1.showSkill());//他的名字是jack,他的特長是跳舞

如果子類的方法和父類的方法同名,然後想調用父類的方法,自己子類的方法也要執行,可以這麼寫

/* ES6繼承 */
// 父類
class Person{
    constructor(name){
        this.name = name;
    }
    showName(){
        console.log('父類的showName');
        return `名字為:${this.name}`;
    }
}
// 子類
class Student extends Person{
    constructor(name,skill){
        super(name);//子類的構造函數必須有super(),相當於執行一次父級的構造函數
        this.skill = skill;
    }
    showName(){
        super.showName();//執行父類的方法
        /* 這裡寫子類自己的要做的事 */
        console.log('子類的showName');
    }
    showSkill(){
        return `他的名字是${this.name},他的特長是${this.skill}`;
    }
}
// 調用
var stu1 = new Student('jack','跳舞');
console.log(stu1.showName());//父類的showName  子類的showName

2.Symbol和Generator

2.1Symbol:ES6新增的一種數據類型

定義方法:let Symbol = Symbol('aaa');

註意:

(1)Symbol不能當new來使用

(2)Symbol()返回是一個唯一值

(3)Symbol是一個單獨數據類型,就叫symbol的基本類型

(4)如果Symbol作為key,用for in迴圈,出不來

let symbol = Symbol('Jack');
let json = {
    a:'apple',
    b:'banana',
    [symbol]:'aaa'
}
console.log(json[symbol]);//aaa
// 遍歷json
for(let key in json){
    console.log(key);//a b
}

2.2Generator生成器函數:解決非同步,深度嵌套的問題

語法:

function * show(){

}
function* show(){

}
function *show(){

}

定義&調用:

function * gen(){//在函數名前面使用*號定義一個
    yield 'hello';
    yield 'javascript';
    return 'generator函數';
}
let g1 = gen();
console.log(g1.next());//Object {value: "hello", done: false}
console.log(g1.next());//Object {value: "javascript", done: false}
console.log(g1.next());//Object {value: "generator函數", done: true}
console.log(g1.next());//Object {value: undefined, done: true}

遍歷generator函數:

function * gen(){//在函數名前面使用*號定義一個
    yield 'hello';
    yield 'javascript';
    yield 'world';
    return 'generator函數';
}
let g1 = gen();
/*遍歷generator函數(註意:return的東西不會被遍歷出來)*/
// 1.用for...of遍歷
for(let val of g1){
    console.log(val);//hello javascript world
}
// 2.使用解構
let [a,b,c,d] = gen();
console.log(a,b,c,d);//hello javascript world undefined
// 3.使用擴展(三個點)運算符
let [f,...g] = gen();
console.log(f,g);//hello ["javascript", "world"]

let [...newArr] = gen();
console.log(newArr);//["hello", "javascript", "world"]
//4.使用Array.from函數
console.log(Array.from(gen()));//["hello", "javascript", "world"]

關於非同步的解決方案:

(1)回調函數

(2)事件監聽

(3)發佈/訂閱

(4)Promise對象

(5)Generator函數

(6)Async/Await

3.async、await函數:解決非同步問題

定義:在函數前面加async,函數內部加await,後面的代碼會等待前面的代碼先執行

語法:

async function fn(){//表示非同步,這個函數裡面有非同步的任務
    let result=await;//表示後面結果需要等待   
}

使用(例如讀取文件):

(1)promise寫法:

const fs = require('fs');

// 用fs封裝一個promise
const readFile = function(fileName){
    return new Promise((resolve,reject)=>{
        fs.readFile(fileName,(err,data)=>{
            if(err) reject(err);
            resolve(data);
        })
    })
}

// promise
readFile('data/1.txt').then(res=>{
    console.log(res.toString());
    return readFile('data/2.txt');
}).then(res=>{
    console.log(res.toString());
});

(2)generator寫法:

const fs = require('fs');

// 用fs封裝一個promise
const readFile = function(fileName){
    return new Promise((resolve,reject)=>{
        fs.readFile(fileName,(err,data)=>{
            if(err) reject(err);
            resolve(data);
        })
    })
}

// generator
function * gen(){
    yield readFile('data/1.txt');
    yield readFile('data/2.txt');
}
let g1 = gen();
g1.next().value.then(res=>{
    console.log(res.toString());
    return g1.next().value;
}).then(res=>{
    console.log(res.toString());
    return g1.next().value;
});

(3)async、await寫法:

// 用async、await做一個文件讀取
const fs = require('fs');

// 用fs封裝一個promise
const readFile = function(fileName){
    return new Promise((resolve,reject)=>{
        fs.readFile(fileName,(err,data)=>{
            if(err) reject(err);
            resolve(data);
        })
    })
}

// async
async function fn(){//表示非同步,函數內有非同步任務
    let f1 = await readFile('data/1.txt');//表示後面的結果需要等待
    console.log(f1.toString());
    let f2 = await readFile('data/2.txt');
    console.log(f2.toString());
}
fn();

async、await特點:

1.await只能放在async函數中

2.相比generator語法更強

3.await後面可以是promise對象,也可以是數字、字元串、布爾類型

4.async函數返回的是一個promise對象

5.只要await語句後面Promise狀態變為reject,那麼整個async函數會中斷執行

如何解決async函數中拋出錯誤,影響後續代碼執行?

1.使用try{}catch(e){}語法

async function fn(){
    try{
        await Promise.reject('出現問題了');
    }catch(e){

    }
    let a = await Promise.resolve('successs');
    console.log(a);
}
fn().then(res=>{
    console.log(res);
}).catch(err=>{
    console.log(err);
});
// 結果
// success undefined

2.promise本身的catch

async function fn(){
    let [a,b] = await Promise.all([
        readFile('data/1.txt'),
        readFile('data/2.txt')
    ]);
    console.log(a.toString());
    console.log(b.toString());
}
fn();

4.Set和WeakSet

4.1、Set數據結構:類似數組,但裡面不能有重覆值。new Set([]),存儲數組

用法:

// Set數據結構
let setArr = new Set(['a','b','a']);
console.log(setArr);//Set(2) {"a", "b"}

方法:

(1)add()方法:向Set數據結構中添加元素

// Set數據結構--add()方法:向數組中添加元素
let setArr = new Set();
setArr.add('aaa');
setArr.add('bbb');
setArr.add('aaa');
console.log(setArr);//Set(2) {"aaa", "bbb"}
// add()方法鏈式添加
let setArr = new Set().add('aaa').add('bbb').add('aaa');
console.log(setArr);//Set(2) {"aaa", "bbb", "ccc"}

(2)delete()方法:刪除Set數據結構中的某一項

let setArr = new Set();
setArr.add('aaa');
setArr.add('bbb');
setArr.add('ccc');
console.log(setArr);//Set(2) {"aaa", "bbb","ccc"}
// Set數據結構--delete()方法:刪除Set數據結構中的某一項
setArr.delete('bbb');
console.log(setArr);//Set(2) {"aaa", "ccc"}

(3)clear()方法:刪除Set數據結構中的所有項

// Set數據結構--add()方法:向Set數據結構中添加元素
let setArr = new Set();
setArr.add('aaa');
setArr.add('bbb');
setArr.add('ccc');
// Set數據結構--clear()方法:刪除Set數據結構中的所有項
setArr.clear();
console.log(setArr);//Set(0) {}

(4)has()方法:檢測Set數據結構中的是否某一項,返回布爾值

let setArr = new Set();
setArr.add('aaa');
setArr.add('bbb');
setArr.add('ccc');
// Set數據結構--has()方法:檢測Set數據結構中的是否某一項,返回布爾值
console.log(setArr.has('bbba'));//false

(5)size屬性:查看Set數據結構有多少個元素

let setArr = new Set();
setArr.add('aaa');
setArr.add('bbb');
setArr.add('ccc');
// Set數據結構--size屬性:查看Set數據結構有多少個元素
console.log(setArr.size);//3

(6)迴圈Set數據結構(註:Set數據結構的key和value是相同的)

for(let val of setArr){//預設迴圈的是values()
    console.log(val);//aaa bbb ccc
}
console.log('-------');
for(let val of setArr.keys()){
    console.log(val);//aaa bbb ccc
}
console.log('-------');
for(let val of setArr.values()){
    console.log(val);//aaa bbb ccc
}
for(let item of setArr.entries()){
    console.log(item);//["aaa", "aaa"] ["bbb", "bbb"] ["ccc", "ccc"]
}
for(let [k,v] of setArr.entries()){
    console.log(k,v);//aaa aaa bbb bbb ccc ccc
}
setArr.forEach((val,index)=>{
    console.log(val,index);//aaa aaa bbb bbb ccc ccc
});

利用Set做數組的去重:

方法1

let arr = [1,2,3,4,5,6,3,4,5,3,2];
let newArr = [...new Set(arr)];//這裡數組去重返回的是一個數組的淺拷貝
arr.push(9,8,7,7,8);
console.log(arr);//[1, 2, 3, 4, 5, 6, 3, 4, 5, 3, 2, 9, 8, 7, 7, 8]
console.log(newArr);//[1, 2, 3, 4, 5, 6]

方法2

let arr2 = [1,2,3,4,5,6,3,4,5,3,2];
let newArr2 = new Set();
arr2.map(x=>newArr2.add(x));
let resArr2 = [...newArr2];
console.log(resArr2);[1, 2, 3, 4, 5, 6]

4.2、WeakSet數據結構:類似數組對象,但裡面不能有重覆值。new WeakSet({}),存儲對象

註意:

1.WeakSet初始化定義時,不能在裡面存值。

2.WeakSet裡面的add()方法只能存json對象,如果存字元串、數字等會報錯!

定義:

let set = new WeakSet();//WeakSet初始化定義時,不能在裡面存值。
let json = {
    a:1,
    b:2
};
let json2 = {
    a:'asp',
    b:2
};
set.add(json);
set.add(json2);//add()方法只能存json對象,如果存字元串、數字等會報錯!
//set.add(true);//Invalid value used in weak set
console.log(set);//WeakSet {Object {a: "asp", b: 2}, Object {a: 1, b: 2}}

方法:Set數據結構提供的方法除了size屬性和clear()方法沒有,別的都有。(例如:add()、has()、delete())

5.Map和WeakMap

5.1Map數據結構:類似json,但是json的鍵(key)只能是字元串,而map的key可以是任意類型

使用:

// Map使用
let map = new Map();
map.set(key,value);

方法:

// Map使用
let map = new Map();
let json = {
    a:1,
    b:2
}

// map.set(key,value);//設置一個值

map.set('abc','123');
map.set(json,'aaa');
map.set('a',json);
console.log(map);//Map(3) {"abc" => "123", Object {a: 1, b: 2} => "aaa", "a" => Object {a: 1, b: 2}}

// map.get(key);//獲取一個值

console.log(map.get(json));//aaa
console.log(map.get('a'));//Object {a: 1, b: 2}

// map.delete(key);//刪除某一項

map.delete('abc');
console.log(map);//Map(2) { Object {a: 1, b: 2} => "aaa", "a" => Object {a: 1, b: 2}}

// map.has(key);//查找某一項,返回布爾值

console.log(map.has('abc'));//false

// map.clear();//刪除所有項

map.clear();
console.log(map);//Map(0) {}

迴圈map數據結構:

let map = new Map();
let json = {
    a:1,
    b:2
}
map.set('abc','123');
map.set(json,'aaa');
map.set('a',json);
// 迴圈map
for(let [key,value] of map){//預設entries
    console.log(key,value);
    /*abc 123
    Object {a: 1, b: 2} "aaa"
    Object {a: 1, b: 2}*/
}
for(let key of map.keys()){}
for(let value of map.values()){}
for(let [key,value] of map.entries()){}
map.forEach((value,key)=>{
    console.log(key,value);
    /*abc 123
    Object {a: 1, b: 2} "aaa"
    Object {a: 1, b: 2}*/
});

5.1WeakMap數據結構:類似json,但是json的鍵(key)只能是字元串,而WeakMap的key只能是對象

使用:

// WeakMap使用
let wmap = new WeakMap();
let json = {
    a:1,
    b:2
}
wmap.set(json,'123');
console.log(wmap);//WeakMap {Object {a: 1, b: 2} => "123"}

總結:

1.Set  裡面是數組,不能重覆,沒有key(下標),沒有get方法

2.Map 對json功能增強,key可以是任意類型值

6.數字變化和Math新增的東西

6.1數字變化(數值變化)

1.進位:

// 二進位:(binary)
let a = 0b010101;
console.log(a);//21
// 八進位:(Octal)
let b = 0o652;
console.log(b);//426
// 十六進位:(Hexadecimal)
let c = 0xabc;
console.log(c);//2748

2.數值判斷

// 數字變化
let a = 12;
// Number.isNaN:判斷是否為NaN
console.log(Number.isNaN(a));//false
// Number.isFinite:判斷是否是數字
let b = 'aaa';
console.log(Number.isFinite(b));//fasle
// Number.isInteger:判斷是否是整數
let c = 12.12;
console.log(Number.isInteger(c));//false
console.log(Number.isInteger(a));//true
// Number.parseInt():將一個數據轉換成整數
console.log(Number.parseInt(2.5));
// Number.parseFloat():將一個數據轉換成浮點數
console.log(Number.parseFloat("13.5526"));//13.5526
// Number.isSafeInteger():判斷是否是安全整數
/* 安全整數:-(2^53-1)到(2^53-1) */
console.log(Number.isSafeInteger(-(2**53)));//false
console.log(Number.isSafeInteger(-(2**53-1)));//true
console.log(Number.isSafeInteger((2**53)));//false
console.log(Number.isSafeInteger((2**53-1)));//true
// Number.MAX_SAFE_INTEGER:最大安全整數
console.log(Number.MAX_SAFE_INTEGER);//9007199254740991
// Number.MIN_SAFE_INTEGER:最小安全整數
console.log(Number.MIN_SAFE_INTEGER);//-9007199254740991

6.2Math新增的東西

// Math新增的東西
// Math.trunc():截取數字整數部分
console.log(Math.trunc(4.6));//4
// Math.sign():判斷一個數是正數、負數、0
console.log(Math.sign(-5));//-1
console.log(Math.sign(5));//1
console.log(Math.sign(0));//0
console.log(Math.sign(-0));//-0
console.log(Math.sign('abc'));//NaN
// Math.cbrt():計算一個數的立方根
console.log(Math.cbrt(27));//3
// ...等等

7.ES2018(ES9)新增的東西

7.1命名捕獲(用於正則匹配)

語法:(?<名字>)

以前寫正則,要把捕獲到的數據賦給變數,都是這麼寫的

let today = "2019-05-03";
let reg = /(\d{4})-(\d{2})-(\d{2})/;
let dateArr = today.match(reg);
let [full,year,month,day,...more] = dateArr;
console.log(year,month,day);//2019 05 03

現在,我們可以這麼寫:

let today = "2019-05-03";
let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;//建議在Chrome瀏覽器下測試,別的瀏覽器可能會報錯。
let {year,month,day} = today.match(reg).groups;
console.log(year,month,day);//2019 05 03

7.2反向引用命名捕獲

1.反向引用以前寫法:

(1)\1 \2(字元串寫法)    (2)$1 $2(str.replace()方法寫法)

語法:\k<名字>

如果要匹配和前面組相同的多個,可以這麼寫

// 匹配:"monday-monday"
// let reg = /^(?<m>monday)-\k<m>$/;
// let str = 'a-a';
// let str2 = 'm-m';
// let str3 = 'monday-monday';
// console.log(reg.test(str));//false
// console.log(reg.test(str2));//false
// console.log(reg.test(str3));//true

// 匹配:"monday-monday-monday"
let reg = /^(?<m>monday)-\k<m>-\1$/;//或者let reg = /^(?<m>monday)-\k<m>-\k<m>$/;
let str = 'a-a';
let str2 = 'm-m';
let str3 = 'monday-monday';
let str4 = 'monday-monday-monday';
console.log(reg.test(str));//false
console.log(reg.test(str2));//false
console.log(reg.test(str3));//false
console.log(reg.test(str4));//true

2.替換:$<名字>

例如:正則轉換日期格式:

let str = '2019-05-03';
let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

let str1 = str.replace(reg,'$<day>/$<month>/$<year>');
console.log(str);//2019-05-03
console.log(str1);//03/05/2019

結合回調函數:

let str = '2019-05-03';
let reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

let str1 = str.replace(reg,(...args)=>{
    // console.log(args);
    let {year,month,day} = args[args.length-1];
    return `${day}/${month}/${year}`;
});
console.log(str1);//03/05/2019

7.3dotAll模式(用s)來表示:匹配任意東西

之前,如果用正則匹配任意東西,用‘.’來匹配,但不包括\n,所以之前如果匹配\n之類的東西,是這麼寫的

let reg = /^\w+.\w+$/m;//註:在結尾處加m表示多行模式
let str = 'turn-\noff';
console.log(reg.test(str));//true

但是如果匹配一些別的文字,比如換行符’\n‘,會匹配失敗

let reg = /^\w+.\w+$/m;
let str = 'turn\noff';
console.log(reg.test(str));//false

現在可以用dotAll模式來匹配(結尾處加s即可):

let reg = /^\w+.\w+$/s;//加s表示為dotAll模式
let str = 'turn\noff';
console.log(reg.test(str));//true

7.3標簽函數

定義:和定義普通函數一樣

function fn(){

}

調用:

fn();//這樣調用就是普通函數
fn`aaa`;//標簽函數的調用

Demo:

function fn(args){
    return args[0].toUpperCase();//將第一個參數轉為大寫
}
console.log(fn`panda`);//調用標簽函數

7.4Proxy代理(擴展或增強對象的一些功能)

作用:比如vue中的攔截,預警、上報、擴展功能、統計、增強對象等等;proxy是設計模式的一種,叫做代理模式。

語法:new Proxy(target,handler),target為被代理的對象,handler對代理的對象做什麼操作

let obj = {//此對象不暴露給外部
    name:'jack'
};
let newObj = new Proxy(obj,{//此對象是暴露給外部的obj
    get(target,property){
        // console.log(target,property);
        // 在訪問屬性之前做一些操作
        console.log(`您訪問了${property}屬性`);
        return target[property];
    }
}
);
console.log(newObj.name);//您訪問了name屬性 jack

proxy對象的get(target,property):簡單封裝創建DOM元素的方法:

/* 使用proxy對象簡單封裝創建DOM元素的方法 */
const DOM = new Proxy({},{
    get(target,property){
        // console.log(target,property);
        return function(attr={},...children){
            // console.log(attr,children);
            let el = document.createElement(property);
            for(key of Object.keys(attr)){
                el.setAttribute(key,attr[key]);
            }
            for(child of Object.values(children)){
                if(typeof child == 'string'){
                    child = document.createTextNode(child);
                }
                el.appendChild(child);
            }
            return el;
        }
    }
});
let oDiv = DOM.div(
    {id:'div1'},'我是div','哈哈哈',
    DOM.a({href:'http://www.baidu.com'},'訪問百度'),
    DOM.ul({},
        DOM.li({},'1111'),
        DOM.li({},'2222'),
        DOM.li({},'3333'),
        DOM.li({},'4444')
    )
);
window.onload = function(){
    document.body.appendChild(oDiv);
}

proxy對象的set(target,prop,value):檢測設置年齡是否達到要求

let obj = new Proxy({},{
    set(target,prop,value){
        // console.log(target,prop,value);
        if(prop == 'age'
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 主引導記錄(Master Boot Record,縮寫:MBR) 主引導記錄又叫做主引導扇區,是電腦開機後啟動操作系統時所必須要讀取的硬碟首個扇區,它在硬碟上的三維地址為(柱面,磁頭,扇區)=(0,0,1)。主引導記錄由3個部分組成,起始446個位元組區域為“主引導記錄”;之後16×4=64字 ...
  • 準備階段 1.首先下載樹莓派安裝鏡像 https://www.raspberrypi.org/ 2.系統燒錄工具,磁碟恢復工具 2.1 Win32DiskImager.exe 系統燒錄工具 2.2 SDFormatter.exe記憶體卡修複工具 3. 記憶體卡建議買32G,64G及以上的,主要看自己需要 ...
  • 一、簡介 蘋果從 OSX El Capitan 10.11 系統開始使用了 Rootless 機制,也稱為 SIP(System Integrity Protection),可以將該機制理解為一個更高等級的內核保護措施,保護系統級別的目錄被修改,主要是以下三個/system、/sbin、/usr 這 ...
  • 打開/etc/inittab 文件會看到以下信息 從中知道想要啟動後就進入完整的多用戶文本模式(命令行模式) 以root許可權執行: 進入圖形化模式,執行: 使用startx或init 5可以進入圖形化界面 進入其他運行級別用:init N (N表示0-6數值) 0: 系統停機(關機)模式,系統預設運 ...
  • GRANT ALL PRIVILEGES ON *.* TO '用戶名'@'%' IDENTIFIED BY '密碼' WITH GRANT OPTION; 這一條是添加全許可權的用戶,用戶名和密碼自行設置 GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, D ...
  • 1.keys pattern 含義:查找所有符合給定模式(pattern)的key keys 遍歷所有key keys he[h l] 遍歷以he開頭,第三個字元為h l之間的所有key keys ph? ?代表一個字元 註意:keys命令一般不在生產環境中使用 生產環境的key比較多,keys這個 ...
  • 文/開源智造聯合創始人老楊 本文來自《OdooERP應用與開發案例教程》的試讀章節。書籍尚未出版,請勿轉載。歡迎您反饋閱讀意見。 PostgreSQL是Odoo支持的資料庫。PostgreSQL是起源於大學的一個歷史很長的開源資料庫系統。包括美國航天局NASA、德國證券交易中心、中國的平安、騰訊的微 ...
  • 前言 今天繼續typescript的學習,開始函數的學習。 函數 函數的定義 和JavaScript一樣,TypeScript函數可以創建有名字的函數和匿名函數。 你可以隨意選擇適合應用程式的方式,不論是定義一系列API函數還是只使用一次的函數。 定義有名字的函數: 定義匿名函數: 函數定義類型 函 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...