js原生面試題

一、es6中的箭頭函數和普通函數有什么區別?

1、普通函數中的?this總是指向調用它的那個對象,

箭頭函數沒有自己的this,他的this永遠指向其定義環境,任何方法都改變不了其指向,如call()、bind()、apply()。(正是因為它沒有this,所以也就不能用作構造函數,也沒有原型對象)

箭頭函數不能當作構造函數,也就是說,不能使用new命令,否則會報錯。

箭頭函數沒有原型屬性。

箭頭函數不可以使用yield命令,因此箭頭函數不能用作Generator函數。

箭頭函數不能使用arguments對象,該對象在函數體內不存在。如果要用,可以用rest參數代替。

變量提升:由于js的內存機制,function的級別最高,而用箭頭函數定義函數的時候,需要var(let、const)關鍵字,而var所定義的變量不能得到變量提升。故箭頭函數一定要定義于調用之前。

拓展:this的指向問題?

? ? 1、普通函數中,this指向其函數的直接調用者;

? ? 2、箭頭函數中,this指向其定義環境,任何方法都改變不了其指向,如call( )、bind()等;

? ? 3、構造函數中,如果不使用new,則this指向window,

?? ?? ? 如果使用new創建了一個實例,則this指向該實例。

? 4、window內置函數中,如setInterval,setTimeout等,其內部的this指向Window。

? ? 5、匿名函數的this指向Window。

? ? 6、apply()、call()、bind()可以改變this的指向


二、談談你對原型鏈的認識?

https://blog.csdn.net/xiaotao_css/article/details/72782416:通俗易懂的介紹(僅供18歲以上成年閱讀)

看下面的東西之前,建議先看上面鏈接的這篇文章

? ? 對象: 1 、 函數對象: 由 function 創造出來的函數,比如 function a(){ } ; 系統內置的函數對象: Function , Object , Array , String , Number


?? ??? ??? ?? ? 2、 普通對象: 除開函數對象之外的對象,都是普通對象

?? ??? ??? ?? ?每個普通對象的__proto__屬性,都指向Object().prototype?,

?? ??? ??? ?? ? var obj = { }? 就等于? var obj = new Object ( ) ;? 即普通對象是? 構造函數( Object ) 的一個實例

?? ??? ??? ?? ? 所以? obj. __proto__? ? ===? Object.prototype? ( 但是老高說的,Object的原型還是object對象, )

?? ??? ??? ??? ??? ??? ?? obj. constructor? ===? Object?

?? ?凡是通過 new Function() 創建的對象都是函數對象,其他的都是普通對象。

? ? 注:所有對象都有 __proto__ 屬性只有函數對象才有 prototype 屬性 ?。。。。。。。。。?!

? ? 原型對象: prototype 屬性也叫原型對象,主要是為了實現繼承;


?? ??指針 __proto__ :? js中,萬物皆對象!所有的對象 obj 都具有 proto 屬性(null 和 undefined除外 ),而且指向創造obj 對象的函數對象(生成實例的構造函數)的prototype屬性 。 如以下例子:


Person 構造函數的原型對象 是 Mother ()。相當于原型是媽媽,Person現在是兒子。

在 p1 和 p2 實例中,__proto__屬性,指向的是 創造他們的構造函數Person 對象的 prototype 屬性,所對應的對象。

也就是 Mother().

一個構造函數對象的原型,就相當于 他媽,這個構造函數對象的實例,就相當于? 他媽不同的孩子。

而 每個 實例中的 __proto__屬性,就指向 他們共同的 媽 !也就是 構造函數對象的 prototype屬性。

當我們輸入?p1.name?的時候,原型鏈的搜索機制是先在實例中搜索相應的值,找不到就通過它的__proto__指針,在原型中找,還找不到就再往上一級原型中搜索……一直到了原型鏈的終點( 就是js自帶的Object,它的原型比較特殊,為null ),就是到null還沒找到的話,就返回一個?undefined。

? ? 構造器constructor : 每一個對象中的constructor 屬性返回創建此對象的函數對象的引用;例如:

? ? ?functon? Dog ( name, color ) {?

?? ?? ? this. name = name;

?? ?? ? this. color = color;

?? ?}

? ? var dog1 = new Dog( "小白" , "白色" );

? ? dog1.constructor == Dog 構造函數本身

在默認情況下,所有的原型對象都會自動獲得一個 constructor(構造函數)屬性,這個屬性(是一個指針)指向 prototype 屬性所在的函數(Person)

上面這句話有點拗口,我們「翻譯」一下:A 有一個默認的 constructor 屬性,這個屬性是一個指針,指向 Person。即:

Person.prototype.constructor == Person

實例的構造函數屬性(constructor)指向構造函數 :person1.constructor == Person

person1 為什么有 constructor 屬性?那是因為 person1 是 Person 的實例。

那 Person.prototype 為什么有 constructor 屬性??同理, Person.prototype (你把它想象成 A) 也是Person 的實例。

也就是在 Person 創建的時候,創建了一個它的實例對象并賦值給它的 prototype,基本過程如下:

var A = new Person();

Person.prototype = A;

結論:原型對象(Person.prototype)是 構造函數(Person)的一個實例。

以下代碼的圖示?

?? ??? ??? ?function Foo ( ) { } ;

var f1 = new Foo;

以下是 深入解答原型是怎么回事 的一篇文章?

1、http://www.lxweimin.com/p/dee9f8b14771

2、http://www.lxweimin.com/p/652991a67186

3、http://www.lxweimin.com/p/a4e1e7b6f4f8? ??

原型鏈的概念

如果問原型鏈是什么,直接把下面的這張圖畫出來就行了。

https://www.cnblogs.com/shuiyi/p/5305435.html

騰訊大學原生JS 視頻 :https://ke.qq.com/course/231577

回答出以下問題,就知道 __proto__和prototype 的什么了

function Person(){? ?} ;

var person1 = new Person( );

person1.__proto__?是什么?

Person.__proto__?是什么?

Person.prototype.__proto__?是什么?

Object.__proto__?是什么?

Object.prototype__proto__?是什么?

答案:

第一題:

因為 person1.__proto__ === person1 的構造函數.prototype

因為 person1的構造函數 === Person

所以person1.__proto__ === Person.prototype

第二題:

因為 Person.__proto__ === Person的構造函數.prototype

因為 Person的構造函數 === Function

所以Person.__proto__ === Function.prototype

第三題:

Person.prototype 是一個普通對象,我們無需關注它有哪些屬性,只要記住它是一個普通對象。

因為一個普通對象的構造函數 === Object

所以Person.prototype.__proto__ === Object.prototype

第四題,參照第二題,因為 Person 和 Object 一樣都是構造函數

?? ??? ??? ?? ?不要把 Object 想的太復雜,它其實也不過是 Function 構造出來的一個 方法 (一個普通的構造函數)

?? ??? ??? ?? ? 所以 Object.__proto__ === Function.prototype

第五題:

Object.prototype 對象也有proto屬性,但它比較特殊,為 null 。因為 null 處于原型鏈的頂端,這個只能記住。

Object.prototype.__proto__ === null

記?。簆rototype是一個普通對象,所有普通對象的__protp__都指向 Object.prototype

三、js跨域問題怎么解決?

? ?1、?JSONP跨域請求

? ? 要理解跨域,先要了解一下”同源策略“。所謂同源是指,協議、域名、端口都相同。所謂”同源策略“,簡單的說,就是基于安全考慮,當前域不能訪問其他域的東西。

http?和?https :協議不同

www.a.com?和www.b.com?:域名不同

www.a.com?: 8080?和www.a.com?: 1000? ?:? ?端口不同

在同源策略下,在某個服務器下的頁面是無法獲取到該服務器以外的數據的。

例如我們在自己的網站通過 ajax?去?獲取豆瓣上的圖書接口:

https://api.douban.com/v2/book/search?q=javascript&count=1

我們通過以上 ajax?去訪問,發現運行時會報錯:

只要出現這個錯誤,就說明服務器接口不支持跨域

//No 'Access-Control-Allow-Origin' header is present on the requested resource

這是因為不同源,所以無法訪問其他服務器的數據

但是<img>?的 src (?獲取圖片 ) ,? <link>?的 href (獲取css),<script>?的?src (獲取js)這三個屬性都不符合同源策略,它們可以跨域獲取數據。JSONP就是利用<script>?的 src?來實現跨域獲取數據。

跨域原理

? ? JSONP實現跨域請求的原理,簡單的說,就說動態創建 <script>標簽,然后利用<script>的?src?不受同源策略的約束來跨域獲取數據。

? ? JSONP?由兩部分組成:回調函數和數據?;卣{函數?是當響應到來時,應該在頁面中調用的函數。回調函數的名字,一般是在請求中指定的。而數據就是傳入回調函數中的 JSON?數據。

注意:JSONP不是真正的?ajax?

ajax是異步的,jsonp是同步的,所以它不是真正的ajax

動態創建 <script>?標簽,設置其?src ,回調函數在 src?中設置:

var script = document.createElement("script");

script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1";

document.body.insertBefore( script, document.body.firstChild );

在頁面中,返回的 JSON?作為參數傳入?回調函數中,我們通過回調函數來?操作數據

function handleResponse(response){

? ? //對 response?數據進行操作代碼

}

?了解了 JSONP?的基本使用方法,我們在實現上面,通過 ajax?調用豆瓣接口的需求,實現代碼如下:

注意:以上代碼中,要記得成功訪問完數據后,要刪除創建的動態 <script>標簽:

document.body.removeChild(script)

其實在接口數據的形式類似:fn( { name: "張三" , age: "20" } ) ,我們傳遞過去一個和這個函數名字相同的回調函數,參數就是訪問到的數據。

假如接口是:http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice

函數名就是 callbanck =?的值:refreshPrice.

JSONP目前還是比較流行的跨域方式,雖然JSONP使用起來方便,但是也存在一些問題:如果其他域不安全,很可能會在響應中夾帶一些惡意代碼。而且要確定 JSONP請求是否失敗并不容易。

JSONP有個限制,只能用GET請求,并且要求返回JavaScript

更多跨域的方法介紹:

https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434499861493e7c35be5e0864769a2c06afb4754acc6000

對axios有更進一步的理解,利用cros進行跨域處理?。?!

2、CROS跨域

3、反向代理

四、閉包

? ? 概念: 閉包就是能夠讀取其他函數內部變量的函數。

? ? 由于函數內部的子函數才能讀取局部變量,因此可以把閉包簡單理解成“定義在一個函數內部的函數”(然后將這個內部的函數 return 返回出來)。

? ? 所以,在本質上,閉包就是將函數內部和函數外部連接起來的一座橋梁。

? ? 閉包的作用:它最大的用處有兩個: 1) 一個是可以讀取函數內部的變量;

?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?? ?2) 另一個就是讓這些變量的值始終保存在內存中。

? ? 使用閉包的注意點:1) 由于閉包會使得函數中的變量都保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄漏。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。

?? ??? ??? ?? ???? ??? ??? ??? ?? ? 內存泄漏:程序的運行需要內存。對于持續運行的服務進程,必須及時釋放不再用到的內存,否則占用越來越高,輕則影響系統性能,重則導致進程崩潰。不再用到的內存,沒有及時釋放,就叫做內存泄漏。

http://www.ruanyifeng.com/blog/2017/04/memory-leak.html


?? ??? ??? ??? ??? ??? ??? ?? ? ?? 2) 閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法,把內部變量當作它的私有屬性,這時一定要小心,不要隨便改變父函數內部變量的值。

五、promise的用法和原理?

基礎https://mengera88.github.io/2017/05/15/promise%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/

原理

https://segmentfault.com/a/1190000009478377

?概念:promise 是異步編程的一種解決方案。它可以把異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。

?Promise 為異步操作提供了統一的接口,使得控制異步操作更加容易,它的強大之處在于它的鏈式調用。

基本用法:


newPromise(function(resolve, reject){

//待處理的異步邏輯

//處理結束后,調用resolve或reject方法

})

新建一個promise很簡單,只需要new 一個 Promise 對象即可。所以promise本質上就是一個函數,它接受一個函數作為參數,并且返回promise對象,這就給鏈式調用提供了基礎。

特點:

1、對象的狀態不受外界影響。

Promise 的實例 有以下三種狀態:

? ? 1)pending : 進行中

? ? 2)resolved : 已成功完成

? ? 3)rejected : 已失敗

只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。

2、一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從pending變為resolved;從pending變為rejected。 只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果。

基本用法:

ES6規定,Promise 對象是一個構造函數,用來生成Promise實例

Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由JavaScript 引擎提供, 不是自己部署。

resolve函數的作用,將Promise對象的狀態從“進行中”變成 “成功”( 即從pending變為resolved ) ,在異步操作成功時調用,并將異步操作的結果,作為參數傳遞出去。

reject函數的作用,在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數傳遞出去。

Promise實例生成以后,可以用then方法分別制定 Resolved狀態和Rejected狀態的回調函數:

then方法可以接受 2 個回調函數作為參數,第二個函數是可選的,不一定要提供。這兩個函數都接受Promise對象傳出的值作為參數。

promise捕獲錯誤? .catch方法:


Promise.prototype.catch方法是Promise.prototype.then(null, rejection)的別名,用于指定發生錯誤時的回調函數。

Promise對象的錯誤具有“ 冒泡 ”性質,會一直向后傳遞,直到被捕獲為止。也就是說,錯誤總是會被下一個catch語句捕獲。

題外話:async 函數是es7 提案出來的語法, async函數是用來取代回調函數的另一種方法。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容