1. 程式人生 > 實用技巧 >Leetcode 24. Swap Nodes in Pairs

Leetcode 24. Swap Nodes in Pairs

一、新增資料型別Symbol。
概念:

Symbol代表獨一無二的

    Symbol型別的值通過Symbol函式來生成,同時Symbol函式生成的值是唯一的

    Symbol函式何以接收字串作為引數,但是即使相同引數返回的值也是唯一的

   作用:

    屬性私有化

    資料保護

//沒有引數的情況
let s1 = Symbol();
let s2 = Symbol();

s1 === s2      //false


//有引數的情況
let s1 = Symbol("fun");
let s2 = Symbol("fun");

s1 === s2      //
false let mySymbol = Symbol(); //第一種寫法 let a = {}; a[mySymbol] = "Hello!"; //第二種寫法 let a = { [mySymbol]: "Hello!" } //第三種寫法 let a = {}; Object.defineProperty(a,mySymbol,{value: "Hello!"}); //列舉Symbol的key值 Object. getOwnPropertySymbols(obj); //注意,Symbol作為物件的key值不能被for in進行遍歷。

二、塊級作用域。

  概念:在ES6中,凡事{}包裹的程式碼都是跨級作用域,凡事在塊級作用域中用let、const宣告的變數都有一個暫時性死區。

{
    let a = 20;  
}
console.log(a);   //報錯

三、var、let、const宣告變數。

  var

    支援變數宣告與解析

    不支援塊級作用域

    可以重複宣告。

  let

    不支援變數宣告與解析

    支援塊級作用域

    不可以重複宣告

    用let宣告的變數或者方法只能在程式碼塊中生效。

{
      let a = 10;
      var b = 20;
}    
console.log(a);     //報錯
console.log(b);     //20

  const

    不支援變數宣告與解析

    支援塊級作用域

    不可以重複宣告

    宣告變數,一旦宣告不可修改

    宣告變數必須賦值,不可以像var一樣先聲明後再定義。  

四、解構賦值。

  概念:允許按照一定格式,從物件和陣列中提取值。

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

//物件解構,物件解構時key值必須要一一對應。
let {name,age} = {name: "張三",age: 20};
console.log(name,age);    //張三   20

//物件解構+別名
let {name: _name, age: _age} = {name: "張三", age: 20};
console.log(_name,_age);      //張三   20

//多重解構
let {obj:{name},arr:[a,b]} = {obj:{name: "張三"},arr: [10,20]};

五、擴充套件運算子

  概念:將陣列或物件轉換成引數序列,使用逗號分割的序列。

  作用:

    1、陣列、物件的合併

    2、函式剩餘引數

    3、替代arguments

//數組合並
let arr1 = [10,20,30];
let arr2 = [40,50,60];
let newArr = [...arr1,...arr2];
console.log(newArr);       //[10,20,30,40,50,60];

//展開陣列
console.log(Math.Max(...arr));

//物件合併
let obj1 = {width: 100, height: 100};
let obj2 = {left: 100, top: 100};
let newObj = {...obj1,...obj2};
console.log(newObj); //{width:100,height:100,left:100,top:100};

六、字串模版。

  1、字串太長需要換行怎麼辦?

//常規解決辦法
var a = "<div>" + 
            "<span>"+num+"</span>"
            "</div>";

//ES6語法
let a = `<div>
             <span>${num}</span>
            </div>`

  2、字串太長怎麼辦?

let phone = 15844423232
let intro = `my name is chj, my phone id ${phone}`;

  3、includes字串搜尋。

//ES6神器,includes方法,str.insludes(內容),找到了返回true,沒找到返回false

let str = "good method!";
str.includes("method");   //true   

4、判斷首尾,startsWith endsWith

/*
    startsWith判斷是否位於頭部
    endsWith判斷是否位於尾部
    這兩個方法是includes的擴充套件
*/

let str = "how are you?";
str.startsWith("how");     //true
str.endsWith("?")            //true

5、repeat字串重複

//str.repeat(n);     將字串重複n次
let str = "abc";
str.repeat(3);       //abcabcabc

七、物件新增方法。

  1、物件的簡寫

let a = 10;
let obj = {a};
//等價於
let obj = {a: 10};
//當key值和value值一樣的時候我們可以寫一個。

  2、Object.is

//判斷兩個物件是否指向同一個記憶體地址
let obj1 = {a: 1, b: 2};
let obj2 = obj1;
Object.is(obj1, obj2);   //true

  3、Object.assign

//合併物件
let obj1 = {name: '曹海傑', age: 20};
let obj2 = {sex: '男'};
let newObj = Object.assign(obj1, obj2);   
console.log(newObj);     //{name: '曹海傑', age: 20, sex: '男'};

八、陣列中新增的方法。

  1、Array.of()

//將一組值轉換為陣列
let arr = Array.of(1,2,3,4);
console.log(arr);     //[1,2,3,4];

  2、Array.from()

//將偽陣列轉換為陣列。
let aLi = Array.from(document.getElementsByTagName("li"));
console.log(aLi instanceof Array);    //instanceof判斷某物件是否屬於某類的例項。

  3、Array.find()

//通過條件查詢資料,返回第一個符合條件的資料。
let arr = [1,2,3,4];
let n = arr.find(function(item, index, array) {
    return item > 3;
})
console.log(n);   //4

  4、Array.findIndex()

//查詢陣列中符合條件的資料的下標,如果沒有找到則返回undefined
let arr = [1,2,3,4];
let n = arr.findIndex(function(item, index , array) {
     return item > 3; 
})    
console.log(n);

  5、Array.fill();

//對陣列進行填充,語法:arr.fill('內容',開始下標,結束下標);
let arr = [1,2,3,4];
arr.fill('qwe', 1, 3);
console.log(arr);       //[1, 'qwe', 'qwe', 4];

九、for of and for in

/*  
    1、for of 是ES6的,for in 是ES5的
    2、for of 遍歷的是值,for in遍歷的是鍵
    3、for of 不能遍歷物件,for in 既可以遍歷物件也可以遍歷陣列
    4、for of 遍歷陣列的時候,如果有未定義的項,遍歷出來的是undefined,for in 則遍歷不到
    5、for of 不能遍歷到原型上定義的屬性(自定義屬性),for in 可以遍歷到
    6、for of 的相容性不是很好,移動端安卓微信瀏覽器不支援,Safari支援
*/
Array.prototype.hehe = '呵呵';
let arr = [1,2,3, ,4];
for (let item of arr) {
     console.log(item);      //1,2,3,undefined,4
}

for (let prop in arr) {
     console.log(prop);      //0,1,2,4,hehe  
}

let obj = {
     name: 'chj',
     age: 20
}    

for (let item of obj) {      //報錯
     console.log(item);      
}

for (let prop in obj) {
     console.log(prop);      //name age
}    

十、函式

  1、函式引數預設值

//ES6之前函式怎麼設定預設值
function fn(x) {
     let x= x || 10;  
}

//ES6函式預設值,等價於上面的寫法,如果沒有傳遞引數,就使用預設值10

function fn(x=10) {

}

  2、剩餘引數

//fn函式中a接收實參1,...rest接收剩餘引數為一個數組。
funciton fn(a, ...rest) {
    console.log(...rest);       //[2,3,4,5];
}
fn(1,2,3,4,5);

  3、箭頭函式

//語法一  function 換成 () => 
let fn = (a) => {
     console.log(a)
}        

//語法二   不寫{}預設表示return,當前函式意思是返回a這個值
let fn = a => a
fn(10);

//語法三   不寫{}預設表示return,當前函式表示返回一個物件
let fn = a => ({a:1});

/*
    箭頭函式特點:
        1、this指向離自己最近的外層作用域的物件
        2、不能當作建構函式使用(箭頭函式是匿名函式,沒有函式名字所以沒有辦法new)
        3、沒有arguments這個引數(ES6已經取消arguments這個引數了)
        4、不能當作generator函式
*/

十一、Set集合

/*
    Set: 集合
        1、類似於陣列,但成員的值是唯一的,沒有重複的值,並且是無序的
        2、Set是一個建構函式
        3、Set每次執行完畢後都會返回一個Set,因此可以進行鏈式呼叫
*/
let s = new Set();
//新增  add()
s.add("a").add("b");
console.log(s);    //Set(2)  {"a","b"};

//刪除  返回值是一個布林值
s.delete("a") ;   //true

//判斷元素是不是Set的成員,返回值是一個布林值
s.has("a");   //true

//清除所有    沒有返回值
s.clear();

//返回所有鍵名
s.keys();

//返回所有value值
s.values();

//返回所有鍵值對
s.entries();

//可以通過for of 遍歷每一個值
for(let item of s) {
    console.log(s);
}    

十二、Map字典型別結構

/*
    1、字典:用來儲存不重複key的hash結構,不同於Set集合,字典使用[鍵,值]的形式來儲存
    2、Map執行完畢後都會返回一個Map,可以進行鏈式呼叫
    3、特點:普通物件只能通過字串來當作key值,但是Map可以使用任何值來當作key值
*/
//建立Map物件
let map = new Map({
     ["a", 1],
     ["b", 2]
})   
console.log(map);     //Map(2)   {"a" => 1, "b" => 2}

//獲取map長度
map.size

//新增陣列
map.set("c",3)

//獲取map值
map.get("a")

//刪除資料 刪除成功返回true
map.delete("a")

//檢測map中是否含有某個值  返回布林值
map.has("a")

//清除所有資料
map.clear();

//獲取所有key值
map.keys();

//獲取所有value值
map.values();

//獲取所有鍵值對
map.entries();

//遍歷map物件     index在前item在後(陣列中item在前)
map.forEach((index, item) => {
      console.log(index, item); 
})

十三、Proxy介紹

  概念:Proixy是ES6中新增的一個特性。

  作用:在目標物件之前架設一層“攔截”,外界對該物件的訪問,都必須想通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫,很類似於設計模式中的代理模式。

  基本用法:

let p = new Proxy(target, handler);

  引數:

    target: 用Proxy包裝被代理的物件(可以是任意型別的物件,包括原生陣列、函式、甚至是另一個代理)

    handler:是一個物件,其聲明瞭代理target的一些操作,其屬性是當執行一個操作時定義代理的行為的函式

  特點:

    1、可以劫持整個物件,並返回一個新物件

    2、有13中劫持操作

    3、handler代理的一些常用方法:

      get 讀取

      set 修改

      has 判斷物件是否有該屬性

      construct 建構函式

      apply 當目標物件是一個函式的時候

      deletePrototy 用於攔截delete操作

十四、get/set方法

let target = {
     name: "chj",
     age: 20,
     sex: "男"
}    
let p  = new Proxy(target, {
       get(obj, attr) {
            console.log("屬性被訪問了");
       },
       set(obj, attr, value) {
            console.log("屬性被設定了");
       }
})
p.name;
p.name = "小王";

  get函式:當訪問target物件身上的一些屬性的時候就會觸發get函式,get函式接收兩個引數

    引數一:代理的物件,也就是target。

    引數二:訪問的屬性。

  set函式:當設定target物件身上的一些屬性的時候就會觸發set函式,set引數接收三個引數

    引數一:代理的物件

    引數二:設定物件的屬性

    引數三:設定物件的屬性的值

  使用場景:

    1、虛擬場景

let target = {
     firstName: "chj",
     lastName: "ls"
}

let p = new Proxy(target, {
        get(obj, attr) {
               if(attr == "fullName") {
                      retrun [obj.firstName, obj.lastName].join(" ");
               }
               return obj[attr]; 
        },
        set(obj, attr, value) {
               if(attr == "fullName") {
                       let fullNameInfo = value.split(" ");
                       obj.firstName = fullNameInfo[0];
                       obj.lastName = fullNameInfo[1];
               }else {
                       obj[attr] = value;
               }
        }
})

console.log(fullName);   //chj
p.fullName = "小 甜甜";
console.log(p.firstName);     //
console.log(p.lastName);     //甜甜

  2、私有屬性

//把_開頭的變數都認為私有變數
let target = {
     name: "張三",
     age: 20,
     _sex: "女"
}    

let p = new Proxy(target, {
       get(obj, attr) {
              if(attr.startWith("_")) {
                    console.log("私有屬性不被允許訪問");
                    return false; 
              }
              return obj[attr];
       },
       set(obj, attr, value) {
              if(attr.startWith("_")) {
                    console.log("私有屬性不允許設定");
                    retrun false;
              }
              obj[attr] = value;
       },
       has(obj, attr) {
              if(atrr.startWith("_")) {
                    return false;
              }
              retrun (attr in obj);
       }
})

十五、函式攔截

  apply:當目標物件是一個函式,且他被呼叫時,就是被apply方法攔截

    引數:apply(target, context, arguments) {}

      target:目標物件

      context:目標物件的上下文(this)

      arguments:目標物件的引數陣列

  construct:用於攔截new命令,意思就是你在new目標物件的時候,會走construct() {}

    引數:construct(target, arguments) {}

      target:目標物件

      arguments:建構函式的引數物件

function fn(a, b) {
       lat handler = {
             apply: function(target, context, args) {
                    console.log(target, context, args)
                    return args[0];
             },

             construct: function(target, args) {
                    return {value: args[1]};
             }
       }
};

let p = new Proxy(fn, handler);

console.log(p(1, 2))           //1
console.log(new p(1, 2))    //{value: 2}