js的一些基礎概念和方法

前言

收集了一些實際中常常用的方法和技巧,也包括一些常常看到的技術題目。es6

判斷數據類型

typeof 和 Object.prototype.toString.call()

這種方法幾乎對於全部基本的數據類型都能進行判斷。json

但在判斷具體對象類型時只能爲object數組

且typeof 會將空類型判斷爲object數據結構

instanceof

instanceof 的內部機制是經過判斷對象的原型鏈中是否是能找到類型的 prototype。app

但 instanceof 只能用來判斷對象類型,原始類型不能夠。而且全部對象類型 instanceof Object 都是 true。函數

json序列化爲url

function serializeUrl(url,data) {
  let params = '';
  for (let k in data) {
      let value;
      if((data[k] != null) && (typeof data[k] == 'object')){
            value = JSON.stringify(data[k]);
      }else {
            value = data[k] != undefined ? data[k] : "";
      }
        params += `&${k}=${encodeURIComponent(value)}`;
  }
  return `${url}?${params}`
}
複製代碼

for循環

for in

其在遍歷數組時獲得的是數組索引值,遍歷對象時獲得的是對象key值。post

使用for in會遍歷數組全部的可枚舉屬性,包括原型。例如上慄的原型方法method和name屬性。因此for in更適合遍歷對象,不要使用for in遍歷數組。ui

若是不想遍歷原型方法和屬性的話,可使用hasOwnPropery方法能夠判斷某屬性是不是該對象的實例屬性。this

for (var key in myObject) {
    if(myObject.hasOwnProperty(key)){
        console.log(key);
    }
}
複製代碼

一樣能夠經過ES5的Object.keys(myObject)獲取對象的實例屬性組成的數組,不包括原型方法和屬性url

for of

for..of適用遍歷數/數組對象/字符串/map/set等擁有迭代器對象的集合.可是不能遍歷對象。

原生具有 Iterator 接口的數據結構以下。
Array
Map
Set
String
TypedArray
函數的 arguments 對象
NodeList 對象

如果想要遍歷類數組對象,能夠爲對象添加myObject[Symbol.iterator]方法,就能夠遍歷這個對象了。但普通對象是不能夠的。

let iterable = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
  console.log(item); // 'a', 'b', 'c'
}

let iterable = {
  a: 'a',
  b: 'b',
  c: 'c',
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
  console.log(item); // undefined, undefined, undefined
}
複製代碼

數據分組

function getGroupData(arr,groupName) {
        let newArry = [];
        let tempMap = {};
        for (let i = 0; i < arr.length; i++) {
          if (!tempMap[arr[i][groupName]]) {
            tempMap[arr[i][groupName]].push(arr[i])
            let objData = {
                name:arr[i][groupName],
                data:[arr[i]]
            }
            newArry.push(objData)
          }
          else {
               for(var j = 0; j < newArry.length; j++){
                if(arr[i][groupName] == newArry[j]["name"]){ 
                     newArry[j]["data"].push(arr[i]);
                    break;
                }
            }
          }
        }
        return  newArry
      }
複製代碼

深拷貝和淺拷貝

對於複雜數據類型,只拷貝數據引用就爲淺拷貝,拷貝數據的值就是深拷貝。

淺拷貝可使用 for in、 Object.assign、擴展運算符... 、Array.prototype.slice()、Array.prototype.concat()進行數據拷貝

深拷貝

function deepClone(obj,hash = new WeakMap()){
    if(obj instanceof RegExp) return new RegExp(obj);
    if(obj instanceof Date) return new Date(obj);
    if(obj === null || typeof obj !== 'object'){
        return obj;
    }
    if(hash.has(obj)){
        return hash.get(obj);
    }

    let t = new obj.constructor();
    hash.set(obj,t);
    for(let key in obj){
        if(obj.hasOwnproper(key)){
            t[key] = deepClone(obj[key],hash);
        }
    }
    return t;
}
複製代碼

CommonJs module 規範和 ES6 module 規範

1、ES6規範

1.export 能夠輸出任何數據類型,但import時必需要有{ },一個模塊裏可使用屢次

2.export default 能夠輸出默認值,import時不須要{ },一個模塊裏只能使用一次

3.import的{ } 和export對應

2、CommonJs規範

1.module.export 只能輸出一個值,且後者會覆蓋前者

2.exports 能夠輸出多個值

3、二者區別

1.ES6是解析階段生成接口,CommonJs是運行階段生成接口,加載模塊

2.ES6的模塊不是對象,加載的不是對象,CommonJs的模塊是對象,加載的是該對象

3.ES6輸出的是值的引用,值改變,引用也改變,即原來模塊中的值改變則該加載的值也改變。CommonJs輸出的是值的拷貝,即原來模塊中的值改變不會影響已經加載的該值。

4.ES6的this指向undefined,CommonJs的this指向當前模塊。

Call、apply、bind的區別

callapply 使用於徹底相同的目的。 它們工做方式之間的惟一區別是 call 指望全部參數都單獨傳遞,而 apply 須要全部參數的數組。

bind不支持接受其餘參數,當它被調用的時候,不會當即執行函數。

ES6新增了雙冒號運算符,用來取代以往的bind,call,和apply。

foo::bar;
// 等同於
bar.bind(foo);

foo::bar(...arguments);
// 等同於
bar.apply(foo, arguments);
複製代碼

call、apply、bind的實現

Function.prototype.__call = function(){
    let [thisArg,...args] = [...arguments];
    if(!thisArg){
        thisArg = typeof window === 'undefined' ? global : window;
    }

    thisArg.func = this;
    let result = thisArg.func(...args);
    delete thisArg.func;
    return result;
}

Function.prototype.__apply = function(thisArg,rest){
    let result;
    if(!thisArg){
        thisArg = typeof window === 'undefined' ? global : window;
    }
    thisArg.func = this;
    if(!rest){
        result = thisArg.func();
    }else {
        result = this.thisArg.func(...rest)
    }
    delete thisArg.func;
    return result;
}
複製代碼

new的實現原理

一、建立一個空對象,構造函數中的this指向這個空對象
二、這個新對象被執行 [[原型]]鏈接
三、執行構造函數方法,屬性和方法被添加到this引用的對象中
四、若是構造函數中沒有返回其它對象,那麼返回this,即建立的這個的新對象,不然,返回構造函數中返回的對象。

function __new(){
    let target = {};
    let [constructor, ...args] = [...arguments];
    target.__proto__ = constructor.prototype;
    let res = constructor.apply(this,args) ;
    if(typeof(res) == "object" || typeof(res) == 'function'){
        return res;
    }
    return target;
}
複製代碼

宏任務跟微任務

macro-task(宏任務):包括總體代碼script,setTimeout,setInterval

micro-task(微任務):Promise,process.nextTick

微任務先執行,以後是宏任務。

this的指向

Promise、Generator、Async

參考文章:
20道大廠題目
ECMAScript 6 入門

相關文章
相關標籤/搜索