摘要:第一部分請點擊快速掌握面試基礎知識一關鍵字如果使用關鍵字來調用函數式很特別的形式。該對象默認包含了指向原構造函數的屬性。接下來通過例子來幫助理解屬性包含了構造函數以及構造函數中在上定義的屬性。也就是說,的回調函數后執行。
譯者按: 總結了大量JavaScript基本知識點,很有用!
原文: The Definitive JavaScript Handbook for your next developer interview
為了保證可讀性,本文采用意譯而非直譯。另外,本文版權歸原作者所有,翻譯僅用于學習。
根據StackOverflow調查, 自2014年一來,JavaScript是最流行的編程語言。當然,這也在情理之中,畢竟1/3的開發工作都需要一些JavaScript知識。因此,如果你希望在成為一個開發者,你應該學會這門語言。
這篇博客的主要目的是將所有面試中常見的概念總結,方便你快速去了解。(鑒于本文內容過長,方便閱讀,將分為三篇博客來翻譯, 此為第三部分。第一部分請點擊快速掌握JavaScript面試基礎知識(一))
new關鍵字如果使用new關鍵字來調用函數式很特別的形式。我們把那些用new調用的函數叫做構造函數(constructor function)。
使用了new的函數到底做了什么事情呢?
創建一個新的對象
將對象的prototype設置為構造函數的prototype
執行構造函數,this執行新構造的對象
返回該對象。如果構造函數返回對象,那么返回該構造對象。
// 為了更好地理解底層,我們來定義new關鍵字 function myNew(constructor, ...arguments) { var obj = {} Object.setPrototypeOf(obj, constructor.prototype); return constructor.apply(obj, arguments) || obj }
使用new和不使用的區別在哪里呢?
function Bird() { this.wings = 2; } /* 普通的函數調用 */ let fakeBird = Bird(); console.log(fakeBird); // undefined /* 使用new調用 */ let realBird= new Bird(); console.log(realBird) // { wings: 2 }
為了便于對比理解,譯者額外增加了測試了一種情況:
function MBird(){ this.wings =2; return "hello"; } let realMBrid = new MBird(); console.log(realMBird) // { wings: 2 }
你會發現,這一句return "hello"并沒有生效!
原型和繼承原型(Prototype)是JavaScript中最容易搞混的概念,其中一個原因是prototype可以用在兩個不同的情形下。
原型關系
每一個對象都有一個prototype對象,里面包含了所有它的原型的屬性。
.__proto__是一個不正規的機制(ES6中提供),用來獲取一個對象的prototype。你可以理解為它指向對象的parent。
所有普通的對象都繼承.constructor屬性,它指向該對象的構造函數。當一個對象通過構造函數實現的時候,__proto__屬性指向構造函數的構造函數的.prototype。Object.getPrototypeOf()是ES5的標準函數,用來獲取一個對象的原型。
原型屬性
每一個函數都有一個.prototype屬性,它包含了所有可以被繼承的屬性。該對象默認包含了指向原構造函數的.constructor屬性。每一個使用構造函數創建的對象都有一個構造函數屬性。
接下來通過例子來幫助理解:
function Dog(breed, name){ this.breed = breed, this.name = name } Dog.prototype.describe = function() { console.log(`${this.name} is a ${this.breed}`) } const rusty = new Dog("Beagle", "Rusty"); /* .prototype 屬性包含了構造函數以及構造函數中在prototype上定義的屬性。*/ console.log(Dog.prototype) // { describe: ? , constructor: ? } /* 使用Dog構造函數構造的對象 */ console.log(rusty) // { breed: "Beagle", name: "Rusty" } /* 從構造函數的原型中繼承下來的屬性或函數 */ console.log(rusty.describe()) // "Rusty is a Beagle" /* .__proto__ 屬性指向構造函數的.prototype屬性 */ console.log(rusty.__proto__) // { describe: ? , constructor: ? } /* .constructor 屬性指向構造函數 */ console.log(rusty.constructor) // ? Dog(breed, name) { ... }
JavaScript的使用可以說相當靈活,為了避免出bug了不知道,不妨接入Fundebug線上實時監控。
原型鏈原型鏈是指對象之間通過prototype鏈接起來,形成一個有向的鏈條。當訪問一個對象的某個屬性的時候,JavaScript引擎會首先查看該對象是否包含該屬性。如果沒有,就去查找對象的prototype中是否包含。以此類推,直到找到該屬性或則找到最后一個對象。最后一個對象的prototype默認為null。
擁有 vs 繼承一個對象有兩種屬性,分別是它自身定義的和繼承的。
function Car() { } Car.prototype.wheels = 4; Car.prototype.airbags = 1; var myCar = new Car(); myCar.color = "black"; /* 原型鏈中的屬性也可以通過in來查看: */ console.log("airbags" in myCar) // true console.log(myCar.wheels) // 4 console.log(myCar.year) // undefined /* 通過hasOwnProperty來查看是否擁有該屬性: */ console.log(myCar.hasOwnProperty("airbags")) // false — Inherited console.log(myCar.hasOwnProperty("color")) // true
Object.create(obj) 創建一個新的對象,prototype指向obj。
var dog = { legs: 4 }; var myDog = Object.create(dog); console.log(myDog.hasOwnProperty("legs")) // false console.log(myDog.legs) // 4 console.log(myDog.__proto__ === dog) // true繼承是引用傳值
繼承屬性都是通過引用的形式。我們通過例子來形象理解:
var objProt = { text: "original" }; var objAttachedToProt = Object.create(objProt); console.log(objAttachedToProt.text) // original // 我們更改objProt的text屬性,objAttachedToProt的text屬性同樣更改了 objProt.text = "prototype property changed"; console.log(objAttachedToProt.text) // prototype property changed // 但是如果我們講一個新的對象賦值給objProt,那么objAttachedToProt的text屬性不受影響 objProt = { text: "replacing property" }; console.log(objAttachedToProt.text) // prototype property changed經典繼承 vs 原型繼承
Eric Elliott的文章有非常詳細的介紹:Master the JavaScript Interview: What’s the Difference Between Class & Prototypal Inheritance?
作者認為原型繼承是優于經典的繼承的,并提供了一個視頻介紹:https://www.youtube.com/watch...
JavaScript是一個單線程程序語言,也就是說JavaScript引擎一次只能執行某一段代碼。它導致的問題就是:如果有一段代碼需要耗費很長的時間執行,其它的操作就被卡住了。JavaScript使用Call Stack來記錄函數的調用。一個Call Stack可以看成是一摞書。最后一本書放在最上面,也最先被移走。最先放的書在最底層,最后被移走。
為了避免復雜代碼占用CPU太長時間,一個解法就是定義異步回調函數。我們自己來定義一個異步函數看看:
function greetingAsync(name, callback){ let greeting = "hello, " + name ; setTimeout(_ => callback(greeting),0); } greetingAsync("fundebug", console.log); console.log("start greeting");
我們在greetingAsync中構造了greeting語句,然后通過setTimeout定義了異步,callback函數,是為了讓用戶自己去定義greeting的具體方式。為方便起見,我們時候直接使用console.log。
上面代碼執行首先會打印start greeting,然后才是hello, fundebug。也就是說,greetingAsync的回調函數后執行。在網站開發中,和服務器交互的時候需要不斷地發送各種請求,而一個頁面可能有幾十個請求。如果我們一個一個按照順序來請求并等待結果,串行的執行會使得網頁加載很慢。通過異步的方式,我們可以先發請求,然后在回調中處理請求結果,高效低并發處理。
下面通過一個例子來描述整個執行過程:
const first = function () { console.log("First message") } const second = function () { console.log("Second message") } const third = function() { console.log("Third message") } first(); setTimeout(second, 0); third(); // 輸出: // First message // Third message // Second message
初始狀態下,瀏覽器控制臺沒有輸出,并且事件管理器(Event Manager)是空的;
first()被添加到調用棧
將console.log("First message")加到調用棧
console.log("First message")執行并輸出“First message”到控制臺
console.log("First message")從調用棧中移除
first()從調用棧中移除
setTimeout(second, 0)加到調用棧
setTimeout(second, 0)執行,0ms之后,second()被加到回調隊列
setTimeout(second, 0)從調用棧中移除
third()加到調用棧
console.log("Third message")加到調用棧
console.log("Third message")執行并輸出“Third message”到控制臺
console.log("Third message")從調用棧中移除
third()從調用棧中移除
Event Loop 將second()從回調隊列移到調用棧
console.log("Second message")加到調用棧
console.log("Second message")Second message”到控制臺
console.log("Second message")從調用棧中移除
Second()從調用棧中移除
特別注意的是:second()函數在0ms之后并沒有立即執行,你傳入到setTimeout()函數的時間和second()延遲執行的時間并不一定直接相關。事件管理器等到setTimeout()設置的時間到期才會將其加入回調隊列,而回調隊列中它執行的時間和它在隊列中的位置已經它前面的函數的執行時間有關。
更多快速掌握JavaScript面試基礎知識(一)
快速掌握JavaScript面試基礎知識(二)
版權聲明:
轉載時請注明作者Fundebug以及本文地址:
https://blog.fundebug.com/201...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107434.html
摘要:第一部分請點擊快速掌握面試基礎知識一閉包閉包由一個函數以及該函數定義是所在的環境組成。當匿名函數執行的時候,的值為。這個問題可以改用后面會介紹方法來解決,通過對每一個匿名函數構建獨立的外部作用域來實現。 譯者按: 總結了大量JavaScript基本知識點,很有用! 原文: The Definitive JavaScript Handbook for your next develope...
摘要:根據調查,自年一來,是最流行的編程語言。在一個函數體中聲明的變量和函數,周圍的作用域內無法訪問。也就是說被大括號包圍起來的區域聲明的變量外部將不可訪問。一個常見的誤解是使用聲明的變量,其值不可更改。 譯者按: 總結了大量JavaScript基本知識點,很有用! 原文: The Definitive JavaScript Handbook for your next developer ...
摘要:一些知識點有哪些方法方法前端從入門菜鳥到實踐老司機所需要的資料與指南合集前端掘金前端從入門菜鳥到實踐老司機所需要的資料與指南合集歸屬于筆者的前端入門與最佳實踐。 工欲善其事必先利其器-前端實習簡歷篇 - 掘金 有幸認識很多在大廠工作的學長,在春招正式開始前為我提供很多內部推薦的機會,非常感謝他們對我的幫助。現在就要去北京了,對第一份正式的實習工作也充滿期待,也希望把自己遇到的一些問題和...
摘要:個高級多線程面試題及回答后端掘金在任何面試當中多線程和并發方面的問題都是必不可少的一部分。默認為提供了年杭州面試經歷掘金想換個環境試試覺得做的不是自己想要的。源碼網站安居客項目架構演進掘金本文已授權微信公眾號獨家發布。 15 個高級 Java 多線程面試題及回答 - 后端 - 掘金在任何Java面試當中多線程和并發方面的問題都是必不可少的一部分。如果你想獲得任何股票投資銀行的前臺資訊職...
閱讀 3752·2021-08-11 11:16
閱讀 1620·2019-08-30 15:44
閱讀 1995·2019-08-29 18:45
閱讀 2267·2019-08-26 18:18
閱讀 996·2019-08-26 13:37
閱讀 1565·2019-08-26 11:43
閱讀 2109·2019-08-26 11:34
閱讀 372·2019-08-26 10:59