【面試官】| 要不說說,JavaScript中的new操做符(別走)

文章第一時間發在筆者githubgit

什麼是箭頭函數

  • 語法簡潔
  • 沒有本身的this
  • 不能用做構造函數。
const agesArr = [12,13,7,8 ]

const res = agesArr.map(item=>`${item}歲`)
console.log(res) // [ '12歲', '13歲', '7歲', '8歲' ]
複製代碼
const fn  = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
const res1 = fn()
console.log(res1) // 6
複製代碼

優點

  • 關於函數的參數默認值面試

    • 以前
    function log(x, y) {
      y = y || 'World';
      console.log(x, y);
    }
    
    if (typeof y === 'undefined') {
      y = 'World';
    }
    複製代碼
    • 如今
    function Point(x = 0, y = 0) {
      this.x = x;
      this.y = y;
    }
    複製代碼
  • 寫起來更短數組

  • 沒有單獨的this瀏覽器

  • 箭頭函數使得表達更加簡潔。bash

沒有箭頭函數

函數是根據如何被調用來定義這個函數的thisapp

  • 若是是該函數是一個構造函數,this指針指向一個新的對象
  • 在嚴格模式下的函數調用下,this指向undefined
function Person() {
        // Person() 構造函數定義 `this`做爲它本身的實例.
        this.age = 0;

        setInterval(function growUp() {
          console.log(this);
          // 在非嚴格模式, growUp()函數定義 `this`做爲全局對象,
          // 與在 Person()構造函數中定義的 `this`並不相同.
            // 此時的this是window 對象(瀏覽器環境)
          this.age++;
        }, 1000);
      }
複製代碼

用箭頭函數

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| 正確地指向 p 實例
  }, 1000);
}

var p = new Person();
複製代碼

箭頭函數不會建立本身的this,它只會從本身的做用域鏈的上一層繼承this函數

普通函數與箭頭函數有什麼不一樣

  • 函數體內的 this 對象,就是定義時所在的對象,而不是使用時所在的對象
let obj = {
  name: "張三",
  sayHi() {
    console.log(this); // obj 這個對象
    function sayName() { 
      console.log(this); // 是一個函數 this 指向window
    }
    sayName()
    const foo = ()=>{
      console.log(this) // obj 這個對象
    }
    foo()
  },
};
console.log(obj.name);
obj.sayHi();

複製代碼
  • ES6 引入 rest 參數(形式爲...變量名),用於獲取函數的多餘參數,這樣就不須要使用arguments對象了。rest 參數搭配的變量是一個數組,該變量將多餘的參數放入數組中。
// arguments變量的寫法 相似數組的對象
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// rest參數的寫法 真正的數組
const sortNumbers = (...numbers) => numbers.sort();
複製代碼
  • 不可使用yield命令,所以箭頭函數不能用做 Generator 函數。

面試題

根據new操做符相關的知識點通常會 延伸出如下的面試題 ,面試官你是否有不少問號測試

  • 問題一:new 以後都作了些什麼??
  • 問題二:可否手寫new操做符原理??

mdn關於new運算符關鍵字的描述

  1. 建立一個空的簡單JavaScript對象(即{});
  2. 連接該對象(即設置該對象的構造函數)到另外一個對象 ;
  3. 將步驟1新建立的對象做爲this的上下文 ;
  4. 若是該函數沒有返回對象,則返回this

以上4條是MDN 上關於new 操做符(或者說關鍵字)的面試,簡單的來體驗下利用構造函數來new 一個對象

var self;

function Person(name) {
  console.log(this);
  self = this;
  this.name = name;
}
let p = new Person("張三");
console.log(p);
console.log(self === p); // true 構造函數中的this 綁定在了p這個對象上
console.log(p.__proto__ === Person.prototype); // 對象p的原型屬性指向構造函數的原型,這樣也就保證了實例可以訪問在構造函數原型中定義的屬性和方法。
複製代碼

而後在構造函數添加原型方法

function Persion(name){
    this.name = name
}
console.log(Persion.prototype)
Persion.prototype.sayHello = function(){
    console.log(this) // 指向構造出的對象
    console.log(this.name) // 小明
}

let xiaoMing = new Persion('小明')
xiaoMing.sayHello()
複製代碼

通過上文的簡單案例咱們能夠得知,

  • new 一個構造函數獲得一個對象,它的原型屬性(也就是__ proto __)與該構造函數的原型是全等

  • new 經過構造函數 Persion 建立出來的實例能夠訪問到構造函數中的屬性,就行這樣

    console.log(xiaoMing.name) // 小明
    複製代碼
  • 言簡意賅:new出來的實例對象經過原型鏈和構造函數聯繫起來

構造函數說白了也是一個函數,那是函數就能夠有返回值

function Person(name) {
  this.name = name;
  // return 1; // 返回內部新建立的對象
  // return "1"; // 返回內部新建立的對象
  // return null; // 返回內部新建立的對象
  // return undefined; // 返回內部新建立的對象
  // return {}; // {} // 直接返回
  return function () {}; // 直接返回
  return [1]; // [1] // 直接返回
}
let p = new Person("李四");
console.log(p);
複製代碼

有了給構造函數返回一個值得想法,那就經過不一樣的數據類型 進行測試得出結論

  • 不一樣的數據類型返回的效果是不同的,像數字1 字符串」1「 ,返回的依然是內部建立的對象
  • 那若是返回一個對象({})或者說數組(【】) 都會直接返回回去

小結

也就是說,構造函數通常不須要return

  • 返回通常的數據類型吧,不起做用
  • 返回對象吧, new 的意義又何在呢

手寫一個本身的myNew

若是本身實現一個new 的話,首先要知足它的幾點效果

  1. 一個構造函數會返回一個對象,那函數裏就應該有對象

    let obj ={}
    複製代碼
  2. 並將其__proto__屬性指向構造函數的prototype屬性

    obj.__proto__ = constructor.prototype;
    複製代碼
  3. 調用構造函數,綁定this

    constructor.apply(obj, args)
    複製代碼
  4. 返回原始值須要忽略,返回對象須要正常處理

    res instanceof Object ? res : obj
    複製代碼

測試成果

function myNew() {
  let [constructor, ...args] = [...arguments];
  let obj = {};
  obj.__proto__ = constructor.prototype;

  let res = constructor.apply(obj, args);
  return res instanceof Object ? res : obj;
}

function Person(name) {
  this.name = name;
//   return {};
}

Person.prototype.sayHi = function () {
  console.log(`原型方法中的函數--${this.name}`);
};
let p1 = myNew(Person, "測試");
// console.log(p1)
p1.sayHi();
console.log(p1.name);
複製代碼

箭頭函數使用new

var Foo = () => {};
      var foo = new Foo(); // TypeError: Foo is not a constructor
複製代碼
  • 不能夠看成構造函數,也就是說,不可使用new命令,不然會拋出一個錯誤

this指向的固定化,並非由於箭頭函數內部有綁定this的機制,實際緣由是箭頭函數根本沒有本身的this,致使內部的this就是外層代碼塊的this。正是由於它沒有this,因此也就不能用做構造函數。

相關文章
相關標籤/搜索