前端知識集錦2

前端學習的摘錄,持續更新中...

1. 數組去重3種方案

使用set去重:set是ES6中提供的數據結構,不一樣於數組,全部的值都是不重複的,Set內部使用===來判斷是否相等,相似'1'和1會兩個都保存,NaN和NaN只會保存一個前端

let unique= [...new Set([1,'1',1,NaN,NaN,undefined,undefined,null,null])];
//[1, "1", NaN, undefined, null]

遍歷,將值添加到新數組,用indexOf()判斷值是否存在,已存在就不添加,達到去重效果。(對NaN去重失敗)數組

let a = [1,'1',1,NaN,NaN,undefined,undefined,null,null];
 let unique = arr =>{
     let newA = [];
     arr.forEach(key => {
         if(newA.indexOf(key)<0){ //遍歷newA是否存在key,若是存在key會大於0就跳過push的那一步
            newA.push(key);
         }
     });
     return newA;
 }
 unique(a); // ["1", 1, NaN, NaN, undefined, null]

遍歷,將數組的值添加到一個對象的屬性名裏,並給屬性賦值。對象不能添加相同屬性名,以這個爲依據能夠實現數組去重,而後用Object.keys(對象)返回這個對象可枚舉屬性組成的數組,這個數組就是去重後的數組。(返回的都是字符串,對於1和'1'都當成'1')數據結構

let a = [1,'1',1,NaN,NaN,undefined,undefined,null,null];
let unique = arr => {
    var obj = {};
    arr.forEach(value => {
        obj[value] = 0; // 隨便賦值,爲了將屬性添加進obj對象
    });
    return Object.keys(obj);
}
unique(a); // ["1", "NaN", "undefined", "null"]

2. 深拷貝

深度遍歷屬性值拷貝app

function deepcopy(obj) {
    var copyObj = Object.create(Object.getPrototypeOf(obj));
    Object.getOwnPropertyNames(obj).forEach((keyName) => {
        if ( typeof obj[keyName] == 'object') {
            copyObj[keyName] = deepcopy(obj[keyName])
        } else {
            copyObj[keyName] = obj[keyName]
        } 
    });
    return copyObj;
}

採用JSON.parse(JSON.stringify(obj))有侷限性函數

function deepcopy(obj){
    return JSON.parse(JSON.stringify(obj));
}

3. 函數length屬性

函數length屬性的含義: 該函數預期傳入的參數個數。指定了默認值之後,length將返回沒有指定默認值的參數個數;指定了默認值後,length屬性將失真。學習

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2

若是設置了默認值的參數不是尾參數,那麼length屬性也再也不計入後面的參數了。this

(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1

4.參數做用域

若是參數默認值是一個變量,則該變量所處的做用域,與其餘變量的做用域規則是樣,即先是當前函數的做用域,而後纔是全局做用域。code

var x = 1;

function f(x, y = x) {
  console.log(y);
}

f(2) // 2

上面代碼中,參數y的默認值等於x。調用時,因爲函數做用域內部的變量x已經生成,因此y等於參數x,而不是全局變量x;若是調用時,函數做用域內部的變量x沒有生成,結果則不一樣。對象

let x = 1;

function f(y = x) {
  let x = 2;
  console.log(y);
}

f() // 1

上面代碼中,函數調用時,y的默認值變量x還沒有在函數內部生成,因此x指向全局變量。若是此時,全局變量x不存在,就會報錯:ReferenceError: x is not defined
一個複雜的例子:繼承

var x = 1;

function foo(x, y = function() { x = 2; }) {
  var x = 3;
  y();
  console.log(x);
}

foo() // 3

上面代碼中,函數foo的參數y的默認值是一個匿名函數。函數foo調用時,它的參數x的值爲undefined,因此y函數內部的x一開始是undefined,後來被從新賦值2。函數foo內部從新聲明瞭一個x,值爲3,這兩個x是不同的,互相不產生影響,所以最後輸出3。

若是將var x = 3的var去除,兩個x就是同樣的,最後輸出的就是2。

5. call方法實現繼承(apply相同)

call的簡單使用:obj1.method.call(obj2,argument1,argument2,...), 用對象obj2替換當前對象obj1,若是obj2爲空,則爲全局對象。簡單使用:

function add(a, b) { return a+b; }

function sub(a, b) { return a-b; }

add.call(sub, 3, 1);  // 4

繼承:

function Parent() {
    this.showMsg = function(msg) {
        return msg;
    }
}

function Child() {
    Parent.call(this);    // this.super()意味
}

const chi = new Child();
chi.showMsg('hello world');   // 'hello world'

多重繼承:

function Parent1() {
    this.add = function(a, b) {
        return a + b;
    }
}

function Parent2() {
    this.sub = function(a, b) {
        return a - b;
    }
}

function Child() {
    Parent1.call(this);
    Parent2.call(this);
}

6. Javascript 詞法做用域

JavaScript是詞法做用域不是動態做用域,詞法做用域是寫代碼或說定義時肯定的,動態做用域是在運行時肯定的,詞法做用域關注函數在何處申明,動態做用域關注在何處調用。可是,JS中的this關注的也是函數的調用。

function foo() {
    console.log(a);   // 2
}
function bar () {
    var a = 3;
    foo();
}
var a = 2;
bar()

若是按照動態做用域理論運行結果是:3

相關文章
相關標籤/搜索