做者:Mark A
譯者:前端小智
來源:dev
點贊再看,養成習慣本文
GitHub
https://github.com/qq44924588... 上已經收錄,更多往期高贊文章的分類,也整理了不少個人文檔,和教程資料。歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。javascript
考題列表
- 1. undefined 和 null 有什麼區別?
- 2. && 運算符能作什麼
- 3. || 運算符能作什麼
- 4. 使用 + 或一元加運算符是將字符串轉換爲數字的最快方法嗎?
- 5. DOM 是什麼?
- 6. 什麼是事件傳播?
- 7. 什麼是事件冒泡?
- 8. 什麼是事件捕獲?
- 9. event.preventDefault() 和 event.stopPropagation()方法之間有什麼區別?
- 10. 如何知道是否在元素中使用了event.preventDefault()方法?
- 11. 爲何此代碼obj.someprop.x會引起錯誤?
- 12. 什麼是event.target?
- 13. 什麼是event.currentTarget?
- 14. == 和 === 有什麼區別?
- 15. 爲何在 JS 中比較兩個類似的對象時返回 false?
- 16. !! 運算符能作什麼?
- 17. 如何在一行中計算多個表達式的值?
- 18. 什麼是提高?
- 19. 什麼是做用域?
- 20. 什麼是閉包?
- 21. JavaScript中的虛值是什麼?
- 22. 如何檢查值是否虛值?
- 23. 'use strict' 是幹嗎用的?
- 24. JavaScript中 this 值是什麼?
- 25. 對象的 prototype 是什麼?
1.undefined 和 null 有什麼區別?
在理解undefined
和null
之間的差別以前,咱們先來看看它們的類似類。html
它們屬於 JavaScript 的 7 種基本類型。前端
let primitiveTypes = ['string','number','null','undefined','boolean','symbol', 'bigint'];
它們是屬於虛值,可使用Boolean(value)
或!!value
將其轉換爲布爾值時,值爲false
。java
console.log(!!null); // false console.log(!!undefined); // false console.log(Boolean(null)); // false console.log(Boolean(undefined)); // false
接着來看看它們的區別。git
undefined
是未指定特定值的變量的默認值,或者沒有顯式返回值的函數,如:console.log(1)
,還包括對象中不存在的屬性,這些 JS 引擎都會爲其分配 undefined
值。github
let _thisIsUndefined; const doNothing = () => {}; const someObj = { a : "ay", b : "bee", c : "si" }; console.log(_thisIsUndefined); // undefined console.log(doNothing()); // undefined console.log(someObj["d"]); // undefined
null
是「不表明任何值的值」。 null
是已明肯定義給變量的值。 在此示例中,當fs.readFile
方法未引起錯誤時,咱們將得到null
值。面試
fs.readFile('path/to/file', (e,data) => { console.log(e); // 當沒有錯誤發生時,打印 null if(e){ console.log(e); } console.log(data); });
在比較null
和undefined
時,咱們使用==
時獲得true
,使用===
時獲得false
:算法
console.log(null == undefined); // true console.log(null === undefined); // false
2. && 運算符能作什麼
&&
也能夠叫邏輯與,在其操做數中找到第一個虛值表達式並返回它,若是沒有找到任何虛值表達式,則返回最後一個真值表達式。它採用短路來防止沒必要要的工做。segmentfault
console.log(false && 1 && []); // false console.log(" " && true && 5); // 5
使用if
語句數組
const router: Router = Router(); router.get('/endpoint', (req: Request, res: Response) => { let conMobile: PoolConnection; try { //do some db operations } catch (e) { if (conMobile) { conMobile.release(); } } });
使用&&
操做符
const router: Router = Router(); router.get('/endpoint', (req: Request, res: Response) => { let conMobile: PoolConnection; try { //do some db operations } catch (e) { conMobile && conMobile.release() } });
3. || 運算符能作什麼
||
也叫或邏輯或
,在其操做數中找到第一個真值表達式並返回它。這也使用了短路來防止沒必要要的工做。在支持 ES6 默認函數參數以前,它用於初始化函數中的默認參數值。
console.log(null || 1 || undefined); // 1 function logName(name) { var n = name || "Mark"; console.log(n); } logName(); // "Mark"
4. 使用 + 或一元加運算符是將字符串轉換爲數字的最快方法嗎?
根據MDN文檔,+
是將字符串轉換爲數字的最快方法,由於若是值已是數字,它不會執行任何操做。
5. DOM 是什麼?
DOM 表明文檔對象模型,是 HTML 和 XML 文檔的接口(API)。當瀏覽器第一次讀取(解析)HTML文檔時,它會建立一個大對象,一個基於 HTM L文檔的很是大的對象,這就是DOM。它是一個從 HTML 文檔中建模的樹狀結構。DOM 用於交互和修改DOM結構或特定元素或節點。
假設咱們有這樣的 HTML 結構:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document Object Model</title> </head> <body> <div> <p> <span></span> </p> <label></label> <input> </div> </body> </html>
等價的DOM是這樣的:
JS 中的document
對象表示DOM。它爲咱們提供了許多方法,咱們可使用這些方法來選擇元素來更新元素內容,等等。
6. 什麼是事件傳播?
當事件發生在DOM元素上時,該事件並不徹底發生在那個元素上。 在「冒泡階段」中,事件冒泡或向上傳播至父級,祖父母,祖父母或父級,直到到達window
爲止;而在「捕獲階段」中,事件從window
開始向下觸發元素 事件或event.target
。
事件傳播有三個階段:
- 捕獲階段–事件從
window
開始,而後向下到每一個元素,直到到達目標元素。 - 目標階段–事件已達到目標元素。
- 冒泡階段–事件從目標元素冒泡,而後上升到每一個元素,直到到達
window
。
7. 什麼是事件冒泡?
當事件發生在DOM元素上時,該事件並不徹底發生在那個元素上。 在冒泡階段,事件冒泡,或者事件發生在它的父代,祖父母,祖父母的父代,直到到達window
爲止。
假設有以下的 HTML 結構:
<div class="grandparent"> <div class="parent"> <div class="child">1</div> </div> </div>
對應的 JS 代碼:
function addEvent(el, event, callback, isCapture = false) { if (!el || !event || !callback || typeof callback !== 'function') return; if (typeof el === 'string') { el = document.querySelector(el); }; el.addEventListener(event, callback, isCapture); } addEvent(document, 'DOMContentLoaded', () => { const child = document.querySelector('.child'); const parent = document.querySelector('.parent'); const grandparent = document.querySelector('.grandparent'); addEvent(child, 'click', function (e) { console.log('child'); }); addEvent(parent, 'click', function (e) { console.log('parent'); }); addEvent(grandparent, 'click', function (e) { console.log('grandparent'); }); addEvent(document, 'click', function (e) { console.log('document'); }); addEvent('html', 'click', function (e) { console.log('html'); }) addEvent(window, 'click', function (e) { console.log('window'); }) });
addEventListener
方法具備第三個可選參數useCapture
,其默認值爲false
,事件將在冒泡階段中發生,若是爲true
,則事件將在捕獲階段中發生。 若是單擊child
元素,它將分別在控制檯上記錄child
,parent
,grandparent
,html
,document
和window
,這就是事件冒泡。
8. 什麼是事件捕獲?
當事件發生在 DOM 元素上時,該事件並不徹底發生在那個元素上。在捕獲階段,事件從window
開始,一直到觸發事件的元素。
假設有以下的 HTML 結構:
<div class="grandparent"> <div class="parent"> <div class="child">1</div> </div> </div>
對應的 JS 代碼:
function addEvent(el, event, callback, isCapture = false) { if (!el || !event || !callback || typeof callback !== 'function') return; if (typeof el === 'string') { el = document.querySelector(el); }; el.addEventListener(event, callback, isCapture); } addEvent(document, 'DOMContentLoaded', () => { const child = document.querySelector('.child'); const parent = document.querySelector('.parent'); const grandparent = document.querySelector('.grandparent'); addEvent(child, 'click', function (e) { console.log('child'); }); addEvent(parent, 'click', function (e) { console.log('parent'); }); addEvent(grandparent, 'click', function (e) { console.log('grandparent'); }); addEvent(document, 'click', function (e) { console.log('document'); }); addEvent('html', 'click', function (e) { console.log('html'); }) addEvent(window, 'click', function (e) { console.log('window'); }) });
addEventListener
方法具備第三個可選參數useCapture
,其默認值爲false
,事件將在冒泡階段中發生,若是爲true
,則事件將在捕獲階段中發生。 若是單擊child
元素,它將分別在控制檯上打印window
,document
,html
,grandparent
和parent
,這就是事件捕獲。
9. event.preventDefault() 和 event.stopPropagation()方法之間有什麼區別?
event.preventDefault()
方法可防止元素的默認行爲。 若是在表單元素中使用,它將阻止其提交。 若是在錨元素中使用,它將阻止其導航。 若是在上下文菜單中使用,它將阻止其顯示或顯示。 event.stopPropagation()
方法用於阻止捕獲和冒泡階段中當前事件的進一步傳播。
10. 如何知道是否在元素中使用了event.preventDefault()
方法?
咱們能夠在事件對象中使用event.defaultPrevented
屬性。 它返回一個布爾值用來代表是否在特定元素中調用了event.preventDefault()
。
11. 爲何此代碼 obj.someprop.x
會引起錯誤?
const obj = {}; console.log(obj.someprop.x);
顯然,因爲咱們嘗試訪問someprop
屬性中的x
屬性,而 someprop 並無在對象中,因此值爲 undefined
。 記住對象自己不存在的屬性,而且其原型的默認值爲undefined
。由於undefined
沒有屬性x
,因此試圖訪問將會報錯。
12. 什麼是 event.target ?
簡單來講,event.target
是發生事件的元素或觸發事件的元素。
假設有以下的 HTML 結構:
<div onclick="clickFunc(event)" style="text-align: center;margin:15px; border:1px solid red;border-radius:3px;"> <div style="margin: 25px; border:1px solid royalblue;border-radius:3px;"> <div style="margin:25px;border:1px solid skyblue;border-radius:3px;"> <button style="margin:10px"> Button </button> </div> </div> </div>
JS 代碼以下:
function clickFunc(event) { console.log(event.target); }
若是單擊 button
,即便咱們將事件附加在最外面的div
上,它也將打印 button
標籤,所以咱們能夠得出結論event.target
是觸發事件的元素。
13. 什麼是 event.currentTarget??
event.currentTarget
是咱們在其上顯式附加事件處理程序的元素。
假設有以下的 HTML 結構:
<div onclick="clickFunc(event)" style="text-align: center;margin:15px; border:1px solid red;border-radius:3px;"> <div style="margin: 25px; border:1px solid royalblue;border-radius:3px;"> <div style="margin:25px;border:1px solid skyblue;border-radius:3px;"> <button style="margin:10px"> Button </button> </div> </div> </div>
JS 代碼以下:
function clickFunc(event) { console.log(event.currentTarget); }
若是單擊 button
,即便咱們單擊該 button
,它也會打印最外面的div
標籤。 在此示例中,咱們能夠得出結論,event.currentTarget
是附加事件處理程序的元素。
14. == 和 === 有什麼區別?
==
用於通常比較,===
用於嚴格比較,==
在比較的時候能夠轉換數據類型,===
嚴格比較,只要類型不匹配就返回flase
。
先來看看 ==
這兄弟:
強制是將值轉換爲另外一種類型的過程。 在這種狀況下,==
會執行隱式強制。 在比較兩個值以前,==
須要執行一些規則。
假設咱們要比較x == y
的值。
- 若是
x
和y
的類型相同,則 JS 會換成===
操做符進行比較。 - 若是
x
爲null
,y
爲undefined
,則返回true
。 - 若是
x
爲undefined
且y
爲null
,則返回true
。 - 若是
x
的類型是number
,y
的類型是string
,那麼返回x == toNumber(y)
。 - 若是
x
的類型是string
,y
的類型是number
,那麼返回toNumber(x) == y
。 - 若是
x
爲類型是boolean
,則返回toNumber(x)== y
。 - 若是
y
爲類型是boolean
,則返回x == toNumber(y)
。 - 若是
x
是string
、symbol
或number
,而y
是object
類型,則返回x == toPrimitive(y)
。 - 若是
x
是object
,y
是string
,symbol
則返回toPrimitive(x) == y
。 - 剩下的 返回
false
注意:toPrimitive
首先在對象中使用valueOf
方法,而後使用toString
方法來獲取該對象的原始值。
舉個例子。
x | y | x == y |
---|---|---|
5 | 5 | true |
1 | '1' | true |
null | undefined | true |
0 | false | true |
'1,2' | [1,2] | true |
'[object Object]' | {} | true |
這些例子都返回true
。
第一個示例符合條件1
,由於x
和y
具備相同的類型和值。
第二個示例符合條件4
,在比較以前將y
轉換爲數字。
第三個例子符合條件2
。
第四個例子符合條件7
,由於y
是boolean
類型。
第五個示例符合條件8
。 使用toString()
方法將數組轉換爲字符串,該方法返回1,2
。
最後一個示例符合條件8
。 使用toString()
方法將對象轉換爲字符串,該方法返回[object Object]
。
x | y | x === y |
---|---|---|
5 | 5 | true |
1 | '1' | false |
null | undefined | false |
0 | false | false |
'1,2' | [1,2] | false |
'[object Object]' | {} | false |
若是使用===
運算符,則第一個示例之外的全部比較將返回false
,由於它們的類型不一樣,而第一個示例將返回true
,由於二者的類型和值相同。
具體更多規則能夠對參考我以前的文章:
我對 JS 中相等和全等操做符轉化過程一直很迷惑,直到有了這份算法
15. 爲何在 JS 中比較兩個類似的對象時返回 false?
先看下面的例子:
let a = { a: 1 }; let b = { a: 1 }; let c = a; console.log(a === b); // 打印 false,即便它們有相同的屬性 console.log(a === c); // true
JS 以不一樣的方式比較對象和基本類型。在基本類型中,JS 經過值對它們進行比較,而在對象中,JS 經過引用或存儲變量的內存中的地址對它們進行比較。這就是爲何第一個console.log
語句返回false
,而第二個console.log
語句返回true
。a
和c
有相同的引用地址,而a
和b
沒有。
16. !! 運算符能作什麼?
!!
運算符能夠將右側的值強制轉換爲布爾值,這也是將值轉換爲布爾值的一種簡單方法。
console.log(!!null); // false console.log(!!undefined); // false console.log(!!''); // false console.log(!!0); // false console.log(!!NaN); // false console.log(!!' '); // true console.log(!!{}); // true console.log(!![]); // true console.log(!!1); // true console.log(!![].length); // false
17. 如何在一行中計算多個表達式的值?
可使用逗號
運算符在一行中計算多個表達式。 它從左到右求值,並返回右邊最後一個項目或最後一個操做數的值。
let x = 5; x = (x++ , x = addFive(x), x *= 2, x -= 5, x += 10); function addFive(num) { return num + 5; }
上面的結果最後獲得x
的值爲27
。首先,咱們將x
的值增長到6
,而後調用函數addFive(6)
並將6
做爲參數傳遞並將結果從新分配給x
,此時x
的值爲11
。以後,將x
的當前值乘以2
並將其分配給x
,x
的更新值爲22
。而後,將x
的當前值減去5
並將結果分配給x
x
更新後的值爲17
。最後,咱們將x
的值增長10
,而後將更新的值分配給x
,最終x
的值爲27
。
18. 什麼是提高?
提高是用來描述變量和函數移動到其(全局或函數)做用域頂部的術語。
爲了理解提高,須要來了解一下執行上下文。執行上下文是當前正在執行的「代碼環境」。執行上下文有兩個階段:編譯
和執行
。
編譯-在此階段,JS 引薦獲取全部函數聲明並將其提高到其做用域的頂部,以便咱們稍後能夠引用它們並獲取全部變量聲明(使用var
關鍵字進行聲明),還會爲它們提供默認值: undefined
。
執行——在這個階段中,它將值賦給以前提高的變量,並執行或調用函數(對象中的方法)。
注意:只有使用var
聲明的變量,或者函數聲明纔會被提高,相反,函數表達式或箭頭函數,let
和const
聲明的變量,這些都不會被提高。
假設在全局使用域,有以下的代碼:
console.log(y); y = 1; console.log(y); console.log(greet("Mark")); function greet(name){ return 'Hello ' + name + '!'; } var y;
上面分別打印:undefined
,1
, Hello Mark!
。
上面代碼在編譯階段實際上是這樣的:
function greet(name) { return 'Hello ' + name + '!'; } var y; // 默認值 undefined // 等待「編譯」階段完成,而後開始「執行」階段 /* console.log(y); y = 1; console.log(y); console.log(greet("Mark")); */
編譯階段完成後,它將啓動執行階段調用方法,並將值分配給變量。
function greet(name) { return 'Hello ' + name + '!'; } var y; //start "execution" phase console.log(y); y = 1; console.log(y); console.log(greet("Mark"));
19. 什麼是做用域?
JavaScript 中的做用域是咱們能夠有效訪問變量或函數的區域。JS 有三種類型的做用域:全局做用域、函數做用域和塊做用域(ES6)。
- 全局做用域——在全局命名空間中聲明的變量或函數位於全局做用域中,所以在代碼中的任何地方均可以訪問它們。
//global namespace var g = "global"; function globalFunc(){ function innerFunc(){ console.log(g); // can access "g" because "g" is a global variable } innerFunc(); }
- 函數做用域——在函數中聲明的變量、函數和參數能夠在函數內部訪問,但不能在函數外部訪問。
function myFavoriteFunc(a) { if (true) { var b = "Hello " + a; } return b; } myFavoriteFunc("World"); console.log(a); // Throws a ReferenceError "a" is not defined console.log(b); // does not continue here
- 塊做用域-在塊
{}
中聲明的變量(let,const
)只能在其中訪問。
function testBlock(){ if(true){ let z = 5; } return z; } testBlock(); // Throws a ReferenceError "z" is not defined
做用域也是一組用於查找變量的規則。 若是變量在當前做用域中不存在,它將向外部做用域中查找並搜索,若是該變量不存在,它將再次查找直到到達全局做用域,若是找到,則可使用它,不然引起錯誤,這種查找過程也稱爲做用域鏈。
/* 做用域鏈 內部做用域->外部做用域-> 全局做用域 */ // 全局做用域 var variable1 = "Comrades"; var variable2 = "Sayonara"; function outer(){ // 外部做用域 var variable1 = "World"; function inner(){ // 內部做用域 var variable2 = "Hello"; console.log(variable2 + " " + variable1); } inner(); } outer(); // Hello World
20. 什麼是閉包?
這多是全部問題中最難的一個問題,由於閉包是一個有爭議的話題,這裏從我的角度來談談,若是不妥,多多海涵。
閉包就是一個函數在聲明時可以記住當前做用域、父函數做用域、及父函數做用域上的變量和參數的引用,直至經過做用域鏈上全局做用域,基本上閉包是在聲明函數時建立的做用域。
看看小例子:
// 全局做用域 var globalVar = "abc"; function a(){ console.log(globalVar); } a(); // "abc"
在此示例中,當咱們聲明a
函數時,全局做用域是a
閉包的一部分。
變量globalVar
在圖中沒有值的緣由是該變量的值能夠根據調用函數a
的位置和時間而改變。可是在上面的示例中,globalVar
變量的值爲abc
。
來看一個更復雜的例子:
var globalVar = "global"; var outerVar = "outer" function outerFunc(outerParam) { function innerFunc(innerParam) { console.log(globalVar, outerParam, innerParam); } return innerFunc; } const x = outerFunc(outerVar); outerVar = "outer-2"; globalVar = "guess" x("inner");
上面打印結果是 guess outer inner
。
當咱們調用outerFunc
函數並將返回值innerFunc
函數分配給變量x
時,即便咱們爲outerVar
變量分配了新值outer-2
,outerParam
也繼續保留outer
值,由於從新分配是在調用outerFunc
以後發生的,而且當咱們調用outerFunc
函數時,它會在做用域鏈中查找outerVar
的值,此時的outerVar
的值將爲 "outer"
。
如今,當咱們調用引用了innerFunc
的x
變量時,innerParam
將具備一個inner
值,由於這是咱們在調用中傳遞的值,而globalVar
變量值爲guess
,由於在調用x
變量以前,咱們將一個新值分配給globalVar
。
下面這個示例演示沒有理解好閉包所犯的錯誤:
const arrFuncs = []; for(var i = 0; i < 5; i++){ arrFuncs.push(function (){ return i; }); } console.log(i); // i is 5 for (let i = 0; i < arrFuncs.length; i++) { console.log(arrFuncs[i]()); // 都打印 5 }
因爲閉包,此代碼沒法正常運行。var
關鍵字建立一個全局變量,當咱們 push 一個函數時,這裏返回的全局變量i
。 所以,當咱們在循環後在該數組中調用其中一個函數時,它會打印5
,由於咱們獲得i
的當前值爲5
,咱們能夠訪問它,由於它是全局變量。
由於閉包在建立變量時會保留該變量的引用而不是其值。 咱們可使用IIFES或使用 let
來代替 var
的聲明。
21. JavaScript 中的虛值是什麼?
const falsyValues = ['', 0, null, undefined, NaN, false];
簡單的來講虛值就是是在轉換爲布爾值時變爲 false
的值。
22. 如何檢查值是否虛值?
使用 Boolean
函數或者 !!
運算符。
23. 'use strict' 是幹嗎用的?
"use strict"
是 ES5 特性,它使咱們的代碼在函數或整個腳本中處於嚴格模式。嚴格模式幫助咱們在代碼的早期避免 bug,併爲其添加限制。
嚴格模式的一些限制:
- 變量必須聲明後再使用
- 函數的參數不能有同名屬性,不然報錯
- 不能使用
with
語句 - 不能對只讀屬性賦值,不然報錯
- 不能使用前綴 0 表示八進制數,不然報錯
- 不能刪除不可刪除的屬性,不然報錯
- 不能刪除變量
delete prop
,會報錯,只能刪除屬性delete global[prop]
-
eval
不能在它的外層做用域引入變量 -
eval
和arguments
不能被從新賦值 -
arguments
不會自動反映函數參數的變化 - 不能使用
arguments.callee
- 不能使用
arguments.caller
- 禁止
this
指向全局對象 - 不能使用
fn.caller
和fn.arguments
獲取函數調用的堆棧 - 增長了保留字(好比
protected
、static
和interface
)
設立」嚴格模式」的目的,主要有如下幾個:
- 消除Javascript語法的一些不合理、不嚴謹之處,減小一些怪異行爲;
- 消除代碼運行的一些不安全之處,保證代碼運行的安全;
- 提升編譯器效率,增長運行速度;
- 爲將來新版本的Javascript作好鋪墊。
24. JavaScript 中 this
值是什麼?
基本上,this
指的是當前正在執行或調用該函數的對象的值。this
值的變化取決於咱們使用它的上下文和咱們在哪裏使用它。
const carDetails = { name: "Ford Mustang", yearBought: 2005, getName(){ return this.name; }, isRegistered: true }; console.log(carDetails.getName()); // Ford Mustang
這一般是咱們指望結果的,由於在getName
方法中咱們返回this.name
,在此上下文中,this
指向的是carDetails
對象,該對象當前是執行函數的「全部者」對象。
接下咱們作些奇怪的事情:
var name = "Ford Ranger"; var getCarName = carDetails.getName; console.log(getCarName()); // Ford Ranger
上面打印Ford Ranger
,這很奇怪,由於在第一個console.log
語句中打印的是Ford Mustang
。這樣作的緣由是getCarName
方法有一個不一樣的「全部者」對象,即window
對象。在全局做用域中使用var
關鍵字聲明變量會在window
對象中附加與變量名稱相同的屬性。請記住,當沒有使用「use strict」
時,在全局做用域中this
指的是window
對象。
console.log(getCarName === window.getCarName); // true console.log(getCarName === this.getCarName); // true
本例中的this
和window
引用同一個對象。
解決這個問題的一種方法是在函數中使用apply
和call
方法。
console.log(getCarName.apply(carDetails)); // Ford Mustang console.log(getCarName.call(carDetails)); // Ford Mustang
apply
和call
方法指望第一個參數是一個對象,該對象是函數內部this
的值。
IIFE
或當即執行的函數表達式,在全局做用域內聲明的函數,對象內部方法中的匿名函數和內部函數的this
具備默認值,該值指向window
對象。
(function (){ console.log(this); })(); // 打印 "window" 對象 function iHateThis(){ console.log(this); } iHateThis(); // 打印 "window" 對象 const myFavoriteObj = { guessThis(){ function getName(){ console.log(this.name); } getName(); }, name: 'Marko Polo', thisIsAnnoying(callback){ callback(); } }; myFavoriteObj.guessThis(); // 打印 "window" 對象 myFavoriteObj.thisIsAnnoying(function (){ console.log(this); // 打印 "window" 對象 });
若是咱們要獲取myFavoriteObj
對象中的name
屬性(即Marko Polo)的值,則有兩種方法能夠解決此問題。
一種是將 this
值保存在變量中。
const myFavoriteObj = { guessThis(){ const self = this; // 把 this 值保存在 self 變量中 function getName(){ console.log(self.name); } getName(); }, name: 'Marko Polo', thisIsAnnoying(callback){ callback(); } };
第二種方式是使用箭頭函數
const myFavoriteObj = { guessThis(){ const getName = () => { console.log(this.name); } getName(); }, name: 'Marko Polo', thisIsAnnoying(callback){ callback(); } };
箭頭函數沒有本身的 this
。它複製了這個封閉的詞法做用域中this
值,在這個例子中,this
值在getName
內部函數以外,也就是myFavoriteObj
對象。
25. 對象的 prototype(原型) 是什麼?
簡單地說,原型就是對象的藍圖。若是它存在當前對象中,則將其用做屬性和方法的回退。它是在對象之間共享屬性和功能的方法,這也是JavaScript實現繼承的核心。
const o = {}; console.log(o.toString()); // logs [object Object]
即便o
對象中不存在o.toString
方法,它也不會引起錯誤,而是返回字符串[object Object]
。 當對象中不存在屬性時,它將查看其原型,若是仍然不存在,則將其查找到原型的原型,依此類推,直到在原型鏈中找到具備相同屬性的屬性爲止。 原型鏈的末尾是Object.prototype
。
console.log(o.toString === Object.prototype.toString); // logs true
因爲篇幅過長,我將此係列分紅上中下三篇,下篇咱們在見。
代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
原文:
https://dev.to/macmacky/70-ja...
交流
乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。
https://github.com/qq44924588...
我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!
關注公衆號,後臺回覆福利,便可看到福利,你懂的。
本文同步分享在 博客「前端小智」(SegmentFault)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。