前端面試之原生js,ajax,jquery,跨域,閉包,面向對象,原型,變量提升

專場:

1. 什么是ajax, 簡述一下 ajax 請求數據的過程

AJAX即“Asynchronous Javascript And XML”(異步 JavaScript 和 XML),是指一種創建交互式網頁應用的網頁開發技術。

通過在后臺與服務器進行少量數據交換,AJAX 可以使網頁實現異步更新。這意味著可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。

Ajax的使用

(1)創建`XMLHttpRequest`對象,也就是創建一個異步調用對象.

(2)創建一個新的`HTTP`請求,并指定該`HTTP`請求的方法、`URL`及驗證信息.

(3)設置響應`HTTP`請求狀態變化的函數.

(4)發送`HTTP`請求.

(5)獲取異步調用返回的數據.

(6)使用JavaScript和DOM實現局部刷新.

getData(url, fn) {

? ? // 實例化XMLHttpRequest對象

? ? var xhr = new XMLHttpRequest();

? ? // 監聽狀態

? ? xhr.onreadystatechange = () => {

? ? // 數據請求完畢? ? ? ? ? ? 判斷狀態碼

? ? if (xhr.readyState === 4&&xhr.status === 200) {

? ? // 將數據轉化成json在、數組

? ? fn && fn(JSON.parse(xhr.responseText))

? ? }

? ? }

? ? // 打開數據請求? 請求方式,路徑,同步false 異步true(默認)

? ? xhr.open('get/post', "路徑", "true/false");

? ? // 發送數據

? ? xhr.send(null)

}

2. 簡述 this 的 四種指向 問題

this指向的形式4種

a.如果是一般函數,this指向全局對象window;

b.在嚴格模式下"use strict",為undefined.

c.對象的方法里調用,this指向調用該方法的對象.

(call,apply,bind會改變this的指向)

.call(),? call(thisScope, arg1, arg2, arg3...)

.apply(), apply(thisScope, [arg1, arg2, arg3...]);兩個參數

Bind(this) 返回的是一個函數

d.構造函數里的this,指向創建出來的實例.

3. jquery 的優點和缺點

JQ的優點:

(1)使用模塊化思想,模塊間保持獨立,不會導致多個開發人員合作時產生沖突

(2)結構清晰,高內聚,低耦合

(3)多態的方式使方法可以重載,提高了代碼的復用率

(4)jQuery 的鏈式調用以及回溯(dom操作的鏈式操作)

(5)jQuery.fn.extend 與 jQuery.extend方法來實現擴展靜態方法或實例方法

JQuery的特點()

(1).一款輕量級的js框架。 JQuery核心js文件才幾十kb,不會影響頁面加載速度

(2).豐富的DOM選擇器(CSS1-3 + XPath) JQuery的選擇器用起來很方便,好比要找到某個dom對象的相鄰元素js可能要寫好幾行代碼,而JQuery一行代碼就搞定了。

(3).鏈式表達式。 JQuery的鏈式操作可以把多個操作寫在一行代碼里,更加簡潔。

(4).事件、樣式、動畫支持。 JQuery還簡化了js操作css的代碼,并且代碼的可讀性也比js要強。

(5).Ajax操作支持。JQuery簡化了AJAX操作,后臺只需返回一個JSON格式的字符串就能完成與前臺的通信。

(6).跨瀏覽器兼容。JQuery基本兼容了現在主流的瀏覽器,不用再為瀏覽器的兼容問題而傷透腦筋。

(7).插件擴展開發。JQuery有著豐富的第三方的插件,例如:樹形菜單、日期控件、圖片切換插件、彈出窗口等等基本前臺頁面上的組件都有對應插件。

(8).可擴展性強。? JQuery提供了擴展接口:JQuery.extend(object),可以在JQuery的命名空間上增加新函數。JQuery的所有插件都是基于這個擴展接口開發的。

JQuery的缺點

<1>.不能向后兼容。每一個新版本不能兼容早期的版本。舉例來說,有些新版本不再支持某些selector,新版jQuery卻沒有保留對它們的支持,而只是簡單的將其移除。這可能會影響到開發者已經編寫好的代碼或插件。

<2>.插件兼容性。與上一點類似,當新版jQuery推出后,如果開發者想升級的話,要看插件作者是否支持。通常情況下,在最新版jQuery版本下,現有插件可能無法正常使用。開發者使用的插件越多,這種情況發生的幾率也越高。我有一次為了升級到jQuery 1.3,不得不自己動手修改了一個第三方插件。

<3>.多個插件沖突。 在同一頁面上使用多個插件時,很容易碰到沖突現象,尤其是這些插件依賴相同事件或selector時最為明顯。這雖然不是jQuery自身的問題,但卻又確實是一個難于調試和解決的問題。

<4>.jQuery的穩定性。 jQuery沒有讓瀏覽器崩潰,這里指的是其版本發布策略。jQuery 1.3版發布后僅過數天,就發布了一個漏洞修正版1.3.1。他們還移除了對某些功能的支持,可能會影響許多代碼的正常運行。我希望類似修改不要再出現。

<5>.對動畫和特效的支持差。 在大型框架中,jQuery核心代碼庫對動畫和特效的支持相對較差。但是實際上這不是一個問題。目前在這方面有一個單獨的jQuery UI項目和眾多插件來彌補此點。

4. 跨域如何產生 如何解決跨域

跨域問題的產生就是瀏覽器的同源策略 只有當協議、端口、和域名都相同的頁面,則兩個頁面 具有相同的源。只要有一個不同,就產生跨域問題

1 使用代理.代理就是用在后端監聽這個端口,只要是這個端口,就轉發到真正的服務器地址,獲取數據后在通過同源的端口返回數據

2.使用jsonp script標簽的src沒有同源限制 jsonp通過script標簽src獲取接口 拼接了一個 callback,回調函數名稱是 cb

3.使用CORS Cross-Origin Resource Sharing(CORS)跨域資源共享是一份瀏覽器技術的規范,提供了 Web 服務從不同域傳來沙 盒腳本的方法,以避開瀏覽器的同源策略,確保安全的跨域數據傳輸。 服務器一般需要增加如下響應頭的一種或幾種:

Access-Control-Allow-Origin: *

Access-Control-Allow-Methods: POST, GET, OPTIONS

Access-Control-Allow-Headers: X-PINGOTHER, Content-Type

Access-Control-Max-Age: 86400

跨域請求默認不會攜帶Cookie信息,如果需要攜帶,請配置下述參數:

"Access-Control-Allow-Credentials": true

// Ajax設置

"withCredentials": true、

瀏覽器從一個域名的網頁去請求另一個域名的資源時,域名、端口、協議任一不同,都是跨域

解決:

1、jsonp跨域

2、nginx反向代理(中間件):

3、PHP端修改header

4、document.domain

5、window.name

6、postMessage

7. call/apply 里面的第一個參數

5. 什么是閉包 項目如何使用閉包 閉包有什么優缺點

解釋:函數套函數。閉包兩個需求:1.必須有兩個函數,并且是嵌套關系,外面的函數必須返回里面的函數;2.在全局中必須接收返回 函數作為變量儲存

缺點:閉包最大缺點就是會造成內存泄漏,存在堆中,不會被垃圾回收;

閉包產生的原因:

Js 最大的缺點就是沒有類,尤其是es5,自身沒有面向對象,變量和函數通常都是寫在同一個空間中,變量重名—污染,函數名重名—污染

而閉包能夠形成一個封閉的空間,可以避免污染,儲存私有變量,存在函數里面 ,這個私有變量不會在函數運行完后被清理 ,可以像全局變量一樣被使用,不會失效。

優點:

1.內容更封閉,保證命名不會沖突;

2.模塊化開發—封閉的模塊化環境

6. 談談你對面向對象的理解 面向對象的特點

類與對象

Array? 類

var obj =new Array()? 變為對象

類:是一個抽象的概念

對象:實際的內容

類就是對某些個體的所有的方法和屬性的集合

實例化過程:

1.先構造概念

2.將概念實例化就形成了對象

面向對象:先構造概念,然后將概念實例化,所有實例化對象都可以使用概念內的方法

通俗的理解就是:萬物皆對象!世界上的任何事和物都可以被視為對象,而我們需要關注的是對象本身可以實現的功能,不需要深入理解構成對象的元素。

js中的面向對象

面向對象在js里有兩個層次的含義,第一種是會使用面向對象函數;第二種是構造面向對象函數。

js也是面向對象中的一種寫法,不過相對于java,js是一種弱數據類型,并不是嚴格意義上的面向對象。但是jq就是使用面向對象的寫法創作出來的js庫。

面向對象的特點

(“抽風機”諧音記憶)

面向對象有四個特點:

1. 抽象:抓住核心問題

2. 封裝:即把能夠實現功能的函數寫成封裝起來,在面向對象里叫做方法。簡單來說就是把實現功能的函數寫成方法。

3. 繼承:繼承的意思是,在實現同一種功能的前提下,新對象可以使用就對象的屬性和方法。

4. 多態:一個變量在引用不同類型的情況下的不同狀態。多態開發在開發組件和模塊化開發的時候能節省很多資源。

原型(prototype)

原型可以用來構造函數的屬性和方法,使這個構造函數的屬性和方法成為公用的。使用原型的優點:在內存中節省資源,提高系統性能。

這是一個用原型構造的數組方法,將求和的sum方法掛在原型上,可以使這個方法被重復使用,當然,重點是節省內存資源。

使用原型還有一個優點,就是優先級:

原型的優先級類似于CSS中的優先級,沒有使用原型的構造函數,就好比CSS中的行內樣式,優先級高,而與原型掛鉤的屬性和方法 ,就像是style的內聯樣式,優先級低于行內樣式。所以在調用同一種方法名的時候,系統會優先調用掛在原型上的方法!

7. 如何深入理解原型鏈

進行方法調用的時候,會先在自身上查找,如果沒有就去該實例的原型鏈上查找,直到找到為止,如果沒找到就返回undefined。

原型鏈就是創建一個構造函數,它會默認生成一個prototype屬性并指向原型對象。使用下一個構造函數的原型對象作為這個構造函數的實例。即 nextFuction.prototype = new thisFuction();

在下下一個構造函數的原型對象 = new nextFuction。這樣下去就會構成一條實例與原型之間的鏈條,這就是原型鏈。

在構造函數中定義的屬性和方法實際上是實例的屬性和方法。即只能出現在實例中。同理因為在構造函數SubType中定義的subProperty屬性是實例屬性,所以存在于instance中。實例中會有一個[[prototype]]內部屬性指向構造函數的原型對象。這樣就形成了一條鏈。

在通過原型鏈實現繼承的情況下,當讀取模式訪問實例中的屬性時,會先搜索實例,然后再搜索實例的原型,在一層一層直到找到或者到達原型鏈的末端停止,返回undefined。

其實我們上面的是少一環的,即Object。因為所有引用類型都是從object繼承來的。

原型鏈就是設置構造函數的屬性時,會向它的父元素上面的原型上查找,如果原型沒有的話就去object上面查找,如果大寫的Object上面沒有的話,就為undefined,自己有的就用自己的

8. setInterval/setTimeout 傳參數 的四種不同寫法 setInterval(()=>,1)

一、采用字符串形式setInterval("foo(id)",1000);

二、匿名函數包裝 window.setInterval(function() { foo (id); }, 1000);

三、定義返回無參函數的函數

function foo(id){

? ? alert(id);

}

function _foo(id){

? ? return function() {

? ? foo(id);

} }

window.setInterval(_foo(id),1000);

四、修改setInterval

var _sto = setInterval;

window.setInterval = function(callback,timeout,param){

? ? var args = Array.prototype.slice.call(arguments,2);

? ? var _cb = function() {

? ? callback.apply(null,args);

? ? }

? ? _sto(_cb,timeout);

}

window.setInterval(hello,3000,userName);

9. 如何區分 宿主對象 內置對象 本地對象 分別有哪些?

宿主對象? window? document? ? 簡單的說就是官方未定義的都是宿主對象

內置對象? 不可以實例化的對象? 例如: Global? Math

本地對象? 可以實例化的對象 例如:? Object Array? Function Number RegExp Date ...

10. url https://www.aliyun.com/node/day?id=1234&price=100#level1

協議 域名 search query path pathname host hostname hash

假設這是一個url地址http://localhost:8080/a/b/c?a=1&b=2#abc,里面包含的部分:

url.parse(urlString[, parseQueryString[, slashesDenoteHost]])

將一個URL解析成一個對象,第2、3個參數都是boolean類型,parseQueryString定義是否將查詢字符串query轉化為object,默認為false不轉換

用到的最多的就是pathname和query兩個屬性了,請注意區分host/hostname、search/query、path/pathname之間的區別

protocol: 'http:',//協議

host: 'localhost:8080',

port: '8080',//端口

hostname: 'localhost',域名

hash: '#abc',

search: '?a=1&b=2',

query: 'a=1&b=2',

pathname: '/a/b/c',

path: '/a/b/c?a=1&b=2',

href: 'http://localhost:8080/a/b/c?a=1&b=2#abc'

11. Query 中,$.data() 和 $(“#aa”).data() 各自是什么作用,有什么區別? 靜態屬性方 法 實例(prototype 原型對象)屬性的方法

$.data()是從 Jquery對象 中取值,靜態屬性方法

$(“#aa”).data() 在頁面元素里找到id為aa對象,從中獲取data值,實例屬性的方法

$.data()是靜態屬性的方法 通過data()函數存取的數據都是臨時數據,一旦頁面刷新,之前存放的數據都將被移除。

$(“#aa”).data()是實例(proto原型對象)屬性的方法

向被選元素附加數據,或者從被選元素獲取數據。

12. jQuery 中 , $.fn ($ = jQuery) 和 $.prototype 三種的區別 $ 和 jQuery 的區別

$是jquery的另一種表現形式;

$.fn是$.prototype的別名;

$.fn是$的原型對象

$拓展的方法是靜態方法,可以使用$直接調用

$.fn拓展的方法是實例方法,必須由“對象”$("")來調用

function jQuery(){

this...

return jQuery = $

}

靜態屬性

jQuery.ajax = func ($.ajax)

jQuery.get = func

jQuer.post = $.psot = func

$.each = func

原型對象屬性 (實例屬性) $("#box").show ==> jQuery 的實例化 尋找DOM

jQuery.prototype.show = func

jQuery.prototype.hide = func

jQuery.prototype.css = func

$.fn = jQuery.fn = $.prototype

jQuery.js

jQuery 變量名

$ == jQuery fn = prototype

$.fn = jQuery.fn = $.prototype = jQuery.prototype = 原型對象

jQuery靜態屬性的擴展 $.getData

$.extend({

getData(){

}

})

jQuery原型對象屬性擴展 $("#box").anmiateFade()

$.fn.extend({

anmiateFade(){

}

})

13. 簡述一下 你對 TCP三次握手 的理解

"傳輸層"的功能,就是建立"端口到端口"的通信。相比之下,"網絡層"的功能是建立"主機到主機"的通信。只要確定主機和端口,我們就能實現程序之間的交流。因此,Unix系統就把主機+端口,叫做"套接字"(socket)。有了它,就可以進行網絡應用程序開發了。

現在,我們必須在數據包中加入端口信息,這就需要新的協議。最簡單的實現叫做UDP協議,它的格式幾乎就是在數據前面,加上端口號。UDP數據包,也是由"標頭"和"數據"兩部分組成。"標頭"部分主要定義了發出端口和接收端口,"數據"部分就是具體的內容。然后,把整個UDP數據包放入IP數據包的"數據"部分,而前面說過,IP數據包又是放在以太網數據包之中的,所以整個以太網數據包現在變成了下面這樣:UDP數據包非常簡單,"標頭"部分一共只有8個字節,總長度不超過65,535字節,正好放進一個IP數據包。

5.3 TCP協議

UDP協議的優點是比較簡單,容易實現,但是缺點是可靠性較差,一旦數據包發出,無法知道對方是否收到。

為了解決這個問題,提高網絡可靠性,TCP協議就誕生了。這個協議非常復雜,但可以近似認為,它就是有確認機制的UDP協議,每發出一個數據包都要求確認。如果有一個數據包遺失,就收不到確認,發出方就知道有必要重發這個數據包了。

因此,TCP協議能夠確保數據不會遺失。它的缺點是過程復雜、實現困難、消耗較多的資源。

TCP數據包和UDP數據包一樣,都是內嵌在IP數據包的"數據"部分。TCP數據包沒有長度限制,理論上可以無限長,但是為了保證網絡的效率,通常TCP數據包的長度不會超過IP數據包的長度,以確保單個TCP數據包不必再分割。

  上圖畫出了TCP建立連接的過程。假定主機A運行的是TCP客戶程序,B運行的是TCP服務器程序。最初兩端的TCP進程都處于CLOSED狀態。圖中在主機下面的是TCP進程所處的狀態。A是主動打開連接,B是被動打開連接。

  B的TCP服務器進程先創建傳輸控制模塊TCB,準備接受客戶進程的連接請求,然后服務器進程就處于LISTEN(監聽)狀態,等待客戶的連接請求

  首先A的TCP客戶進程向B發出連接請求報文段,這時首部中的同步位SYN=1,同時選擇一個初始序號seq=x。TCP規定,SYN報文段(即SYN=1的報文段)不能攜帶數據,但要消耗掉一個序號。這時,A的客戶進程就進入SYN-SENT(同步已發送)狀態。

  B收到連接請求報文段后,向A發送確認。在確認報文段中把SYN和ACK位都置為1,確認號是ack=x+1,同時也為自己選擇一個初始序號seq=y。請注意,這個報文段也不能攜帶數據,但同樣要消耗掉一個序號。這時B的TCP服務器進程就進入SYN-RCVD(同步已收到)狀態。

  A的TCP客戶進程收到B的確認后,還要向B給出確認。確認報文段的ACK置為1,確認號ack=y+1,而自己的序號seq=x+1。這時,TCP連接已經建立,A進入ESTABLISHED(已建立連接)狀態,

  當B收到A的確認后,也會進入ESTABLISHED狀態。

  以上給出的連接建立過程就是常說的TCP三次握手。

  為什么A還要發送一次確認呢?這主要是為了防止已失效的連接請求報文段突然又傳送到了B,因而產生錯誤。

  假定A發出的某一個連接請求報文段在傳輸的過程中并沒有丟失,而是在某個網絡節點長時間滯留了,以致延誤到連接釋放以后的某個時間才到達B。本來這是一個早已失效的報文段。但B收到此失效的連接請求報文段后,就誤以為A又發了一次新的連接請求,于是向A發出確認報文段,同意建立連接。假如不采用三次握手,那么只要B發出確認,新的連接就建立了。

  由于A并未發出建立連接的請求,因此不會理睬B的確認,也不會向B發送數據。但B卻以為新的運輸連接已經建立了,并一直等待A發來數據,因此白白浪費了許多資源。

  采用TCP三次握手的方法可以防止上述現象發生。例如在剛才的情況下,由于A不會向B的確認發出確認,B由于收不到確認,就知道A并沒有要求建立連接。

在TCP/IP協議中,TCP協議提供可靠的連接服務,采用三次握手建立一個連接.

第一次握手:建立連接時,客戶端發送syn包(syn=j)到服務器,并進入等待確認狀態,等待服務器確認;

第二次握手:服務器接收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;

第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手.

14. 如何判斷你當前手機瀏覽器的類型 userAgent (QQ , 微信 ,微博 ,華為)

(1)通過navigator.userAgent獲取瀏覽器的userAgent字符串

(2)然后indexOf去查找各個瀏覽器名稱/瀏覽器內核的名稱,如果返回值不為-1,則該瀏覽器名稱/內核即為你當前手機的手機瀏覽器/瀏覽器內核的類型

以pc端為例:

? var userAgent = navigator.userAgent

? ? if (userAgent.indexOf("Opera")> -1) {

? ? ? ? return "Opera"

? ? };

? ? //判斷是否Firefox瀏覽器

? ? if (userAgent.indexOf("Firefox") > -1) {

? ? ? ? return "FF";

? ? }

? ? //判斷是否chorme瀏覽器

? ? if (userAgent.indexOf("Chrome") > -1){

? return "Chrome";

? ? }

? ? //判斷是否Safari瀏覽器

? ? if (userAgent.indexOf("Safari") > -1) {

? ? ? ? return "Safari";

? ? }

var browser = {

? versions: function() {

? ? var u = navigator.userAgent;

? ? return {

? ? ? ? ? ? trident: u.indexOf('Trident') > -1, //IE內核

? ? ? ? ? ? presto: u.indexOf('Presto') > -1, //opera內核

? ? ? ? ? ? webKit: u.indexOf('AppleWebKit') > -1, //蘋果、谷歌內核

? ? ? ? ? ? gecko: u.indexOf('Firefox') > -1, //火狐內核Gecko

? ? ? ? ? ? mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否為移動終端

? ? ? ? ? ? ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios

? ? ? ? ? ? android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android

? ? ? ? ? ? iPhone: u.indexOf('iPhone') > -1 , //iPhone

? ? ? ? ? ? iPad: u.indexOf('iPad') > -1, //iPad

? ? ? ? ? ? webApp: u.indexOf('Safari') > -1 //Safari

? ? ? ? };

? ? }()

}

15. $.fn.extends $.extends 兩者的區別

jQuery.fn = jQuery.prototype;

jQuery為開發插件提拱了兩個方法,分別是:

jQuery.fn.extend(object):? 給jQuery實例對象添加方法,例如$("#aaa").click()這個jq實例對象所能運用的click()方法

jQuery.extend(object):? ? 為擴展jQuery類本身.為類添加新的方法(添加靜態方法),例如$.ajax()這個jq自帶方法

16. 說一下什么是變量提升 如何解決變量提升

當我們在一個變量定義前調用這個變量會輸出一個undefind,因為我們用var來聲明這個變量的時候會在調用這個變量的前面假設定義了一個沒有被賦值的變量 ,這就是變量提升,當我們用function關鍵字來定義一個函數的時候在任何地方我們都可以調用這個函數,如果我們用變量聲明的方式來定義函數,在函數定義的前面調用函數會報undefind,也是因為變量提升, 用let聲明一個變量就不會存在變量提升

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