js前端面試

JavaScript 的組成

JavaScript 由如下三部分組成:javascript

  • ECMAScript(核心):JavaScript 語言基礎
  • DOM(文檔對象模型):規定了訪問 HTML 和 XML 的接口
  • BOM(瀏覽器對象模型):提供了瀏覽器窗口之間進行交互的對象和方法

JS 的基本數據類型和引用數據類型

  • 基本數據類型:undefined、null、boolean、number、string、symbol
  • 引用數據類型:object、array、function

檢測瀏覽器版本版本有哪些方式?

  • 根據 navigator.userAgent // UA.toLowerCase().indexOf('chrome')
  • 根據 window 對象的成員 // 'ActiveXObject' in window

介紹 JS 有哪些內置對象?

  • 數據封裝類對象:Object、Array、Boolean、Number、String
  • 其餘對象:Function、Arguments、Math、Date、RegExp、Error
  • ES6 新增對象:Symbol、Map、Set、Promises、Proxy、Reflect

說幾條寫 JavaScript 的基本規範?

  • 代碼縮進,建議使用「四個空格」縮進
  • 代碼段使用花括號{}包裹
  • 語句結束使用分號;
  • 變量和函數在使用前進行聲明
  • 以大寫字母開頭命名構造函數,全大寫命名常量
  • 規範定義 JSON 對象,補全雙引號
  • 用{}和[]聲明對象和數組

如何編寫高性能的 JavaScript?

  • 遵循嚴格模式:"use strict";
  • 將 js 腳本放在頁面底部,加快渲染頁面
  • 將 js 腳本將腳本成組打包,減小請求
  • 使用非阻塞方式下載 js 腳本
  • 儘可能使用局部變量來保存全局變量
  • 儘可能減小使用閉包
  • 使用 window 對象屬性方法時,省略 window
  • 儘可能減小對象成員嵌套
  • 緩存 DOM 節點的訪問
  • 經過避免使用 eval() 和 Function() 構造器
  • 給 setTimeout() 和 setInterval() 傳遞函數而不是字符串做爲參數
  • 儘可能使用直接量建立對象和數組
  • 最小化重繪(repaint)和迴流(reflow)

DOM 元素 e 的 e.getAttribute(propName)和 e.propName 有什麼區別和聯繫

  • e.getAttribute(),是標準 DOM 操做文檔元素屬性的方法,具備通用性可在任意文檔上使用,返回元素在源文件中設置的屬性
  • e.propName 一般是在 HTML 文檔中訪問特定元素的特性,瀏覽器解析元素後生成對應對象(如 a 標籤生成 HTMLAnchorElement),這些對象的特性會根據特定規則結合屬性設置獲得,對於沒有對應特性的屬性,只能使用 getAttribute 進行訪問
  • e.getAttribute()返回值是源文件中設置的值,類型是字符串或者 null(有的實現返回"")
  • e.propName 返回值多是字符串、布爾值、對象、undefined 等
  • 大部分 attribute 與 property 是一一對應關係,修改其中一個會影響另外一個,如 id,title 等屬性
  • 一些布爾屬性<input hidden/>的檢測設置須要 hasAttribute 和 removeAttribute 來完成,或者設置對應 property
  • <a href="../index.html">link</a>中 href 屬性,轉換成 property 的時候須要經過轉換獲得完整 URL
  • 一些 attribute 和 property 不是一一對應如:form 控件中<input value="hello"/>對應的是 defaultValue,修改或設置 value property 修改的是控件當前值,setAttribute 修改 value 屬性不會改變 value property

offsetWidth/offsetHeight,clientWidth/clientHeight 與 scrollWidth/scrollHeight 的區別

  • offsetWidth/offsetHeight 返回值包含 content + padding + border,效果與 e.getBoundingClientRect()相同
  • clientWidth/clientHeight 返回值只包含 content + padding,若是有滾動條,也不包含滾動條
  • scrollWidth/scrollHeight 返回值包含 content + padding + 溢出內容的尺寸

描述瀏覽器的渲染過程,DOM 樹和渲染樹的區別?

瀏覽器的渲染過程:php

  • 解析 HTML 構建 DOM(DOM 樹),並行請求 css/image/js
  • CSS 文件下載完成,開始構建 CSSOM(CSS 樹)
  • CSSOM 構建結束後,和 DOM 一塊兒生成 Render Tree(渲染樹)
  • 佈局(Layout):計算出每一個節點在屏幕中的位置
  • 顯示(Painting):經過顯卡把頁面畫到屏幕上

DOM 樹 和 渲染樹 的區別:css

  • DOM 樹與 HTML 標籤一一對應,包括 head 和隱藏元素
  • 渲染樹不包括 head 和隱藏元素,大段文本的每個行都是獨立節點,每個節點都有對應的 css 屬性

重繪和迴流(重排)的區別和關係?

  • 重繪:當渲染樹中的元素外觀(如:顏色)發生改變,不影響佈局時,產生重繪
  • 迴流:當渲染樹中的元素的佈局(如:尺寸、位置、隱藏/狀態狀態)發生改變時,產生重繪迴流
  • 注意:JS 獲取 Layout 屬性值(如:offsetLeft、scrollTop、getComputedStyle 等)也會引發迴流。由於瀏覽器須要經過迴流計算最新值
  • 迴流必將引發重繪,而重繪不必定會引發迴流

如何最小化重繪(repaint)和迴流(reflow)?

  • 須要要對元素進行復雜的操做時,能夠先隱藏(display:"none"),操做完成後再顯示
  • 須要建立多個 DOM 節點時,使用 DocumentFragment 建立完後一次性的加入 document
  • 緩存 Layout 屬性值,如:var left = elem.offsetLeft; 這樣,屢次使用 left 只產生一次迴流
  • 儘可能避免用 table 佈局(table 元素一旦觸發迴流就會致使 table 裏全部的其它元素迴流)
  • 避免使用 css 表達式(expression),由於每次調用都會從新計算值(包括加載頁面)
  • 儘可能使用 css 屬性簡寫,如:用 border 代替 border-width, border-style, border-color
    批量修改元素樣式:elem.className 和 elem.style.cssText 代替 elem.style.xxx

script 的位置是否會影響首屏顯示時間?

  • 在解析 HTML 生成 DOM 過程當中,js 文件的下載是並行的,不須要 DOM 處理到 script 節點。所以,script 的位置不影響首屏顯示的開始時間。
  • 瀏覽器解析 HTML 是自上而下的線性過程,script 做爲 HTML 的一部分一樣遵循這個原則
  • 所以,script 會延遲 DomContentLoad,只顯示其上部分首屏內容,從而影響首屏顯示的完成時間

解釋 JavaScript 中的做用域與變量聲明提高?

JavaScript 做用域:html

  • 在 Java、C 等語言中,做用域爲 for 語句、if 語句或{}內的一塊區域,稱爲做用域;
  • 而在 JavaScript 中,做用域爲 function(){}內的區域,稱爲函數做用域。

JavaScript 變量聲明提高:前端

  • 在 JavaScript 中,函數聲明與變量聲明常常被 JavaScript 引擎隱式地提高到當前做用域的頂部。
  • 聲明語句中的賦值部分並不會被提高,只有名稱被提高
  • 函數聲明的優先級高於變量,若是變量名跟函數名相同且未賦值,則函數聲明會覆蓋變量聲明
  • 若是函數有多個同名參數,那麼最後一個參數(即便沒有定義)會覆蓋前面的同名參數

介紹 JavaScript 的原型,原型鏈?有什麼特色?

原型:java

  • JavaScript 的全部對象中都包含了一個 [proto] 內部屬性,這個屬性所對應的就是該對象的原型
  • JavaScript 的函數對象,除了原型 [proto] 以外,還預置了 prototype 屬性
  • 當函數對象做爲構造函數建立實例時,該 prototype 屬性值將被做爲實例對象的原型 [proto]。

原型鏈:node

  • 當一個對象調用的屬性/方法自身不存在時,就會去本身 [proto] 關聯的前輩 prototype 對象上去找
  • 若是沒找到,就會去該 prototype 原型 [proto] 關聯的前輩 prototype 去找。依次類推,直到找到屬性/方法或 undefined 爲止。從而造成了所謂的「原型鏈」

原型特色:程序員

  • JavaScript 對象是經過引用來傳遞的,當修改原型時,與之相關的對象也會繼承這一改變

JavaScript 有幾種類型的值?,你能畫一下他們的內存圖嗎

  • 原始數據類型(Undefined,Null,Boolean,Number、String)-- 棧
  • 引用數據類型(對象、數組和函數)-- 堆
  • 兩種類型的區別是:存儲位置不一樣:
  • 原始數據類型是直接存儲在棧(stack)中的簡單數據段,佔據空間小、大小固定,屬於被頻繁使用數據;
  • 引用數據類型存儲在堆(heap)中的對象,佔據空間大、大小不固定,若是存儲在棧中,將會影響程序運行的性能;
  • 引用數據類型在棧中存儲了指針,該指針指向堆中該實體的起始地址。
  • 當解釋器尋找引用值時,會首先檢索其在棧中的地址,取得地址後從堆中得到實體。

JavaScript 如何實現一個類,怎麼實例化這個類?

  1. 構造函數法(this + prototype) -- 用 new 關鍵字 生成實例對象web

    • 缺點:用到了 this 和 prototype,編寫複雜,可讀性差
function Mobile(name, price){ this.name = name; this.price = price; } Mobile.prototype.sell = function(){ alert(this.name + ",售價 $" + this.price); } var iPhone7 = new Mobile("iPhone7", 1000); iPhone7.sell();
  1. Object.create 法 -- 用 Object.create() 生成實例對象ajax

    • 缺點:不能實現私有屬性和私有方法,實例對象之間也不能共享數據
var Person = { firstname: "Mark", lastname: "Yun", age: 25, introduce: function(){ alert('I am ' + Person.firstname + ' ' + Person.lastname); } }; var person = Object.create(Person); person.introduce(); // Object.create 要求 IE9+,低版本瀏覽器能夠自行部署: if (!Object.create) {   Object.create = function (o) {     function F() {}     F.prototype = o;     return new F();   };  }
  1. 極簡主義法(消除 this 和 prototype) -- 調用 createNew() 獲得實例對象

    • 優勢:容易理解,結構清晰優雅,符合傳統的"面向對象編程"的構造
var Cat = { age: 3, // 共享數據 -- 定義在類對象內,createNew() 外 createNew: function () { var cat = {}; // var cat = Animal.createNew(); // 繼承 Animal 類 cat.name = "小咪"; var sound = "喵喵喵"; // 私有屬性--定義在 createNew() 內,輸出對象外 cat.makeSound = function () { alert(sound); // 暴露私有屬性 }; cat.changeAge = function(num){ Cat.age = num; // 修改共享數據 }; return cat; // 輸出對象 } }; var cat = Cat.createNew(); cat.makeSound();
  1. ES6 語法糖 class -- 用 new 關鍵字 生成實例對象
class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } } var point = new Point(2, 3);

Javascript 如何實現繼承?

  1. 構造函數綁定:使用 call 或 apply 方法,將父對象的構造函數綁定在子對象上
function Cat(name,color){  Animal.apply(this, arguments);  this.name = name;  this.color = color; }
  1. 實例繼承:將子對象的 prototype 指向父對象的一個實例
Cat.prototype = new Animal(); Cat.prototype.constructor = Cat;
  1. 拷貝繼承:若是把父對象的全部屬性和方法,拷貝進子對象
function extend(Child, Parent) {    var p = Parent.prototype;    var c = Child.prototype;    for (var i in p) {     c[i] = p[i];    }    c.uber = p; }
  1. 原型繼承:將子對象的 prototype 指向父對象的 prototype
function extend(Child, Parent) { var F = function(){};  F.prototype = Parent.prototype;  Child.prototype = new F();  Child.prototype.constructor = Child;  Child.uber = Parent.prototype; }
  1. ES6 語法糖 extends:class ColorPoint extends Point {}
class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // 調用父類的constructor(x, y) this.color = color; } toString() { return this.color + ' ' + super.toString(); // 調用父類的toString() } }

js 繼承方式及其優缺點

原型鏈繼承的缺點

  • 一是字面量重寫原型會中斷關係,使用引用類型的原型,而且子類型還沒法給超類型傳遞參數。

借用構造函數(類式繼承)

  • 借用構造函數雖然解決了剛纔兩種問題,但沒有原型,則複用無從談起。因此咱們須要原型鏈+借用構造函數的模式,這種模式稱爲組合繼承

組合式繼承

  • 組合式繼承是比較經常使用的一種繼承方法,其背後的思路是使用原型鏈實現對原型屬性和方法的繼承,而經過借用構造函數來實現對實例屬性的繼承。這樣,既經過在原型上定義方法實現了函數複用,又保證每一個實例都有它本身的屬性。

javascript 建立對象的幾種方式?

javascript 建立對象簡單的說,無非就是使用內置對象或各類自定義對象,固然還能夠用 JSON;但寫法有不少種,也能混合使用

  1. 對象字面量的方式
person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
  1. 用 function 來模擬無參的構造函數
function Person(){} var person=new Person();//定義一個function,若是使用new"實例化",該function能夠看做是一個Class person.name="Mark"; person.age="25"; person.work=function(){ alert(person.name+" hello..."); } person.work();
  1. 用 function 來模擬參構造函數來實現(用 this 關鍵字定義構造的上下文屬性)
function Pet(name,age,hobby){ this.name=name;//this做用域:當前對象 this.age=age; this.hobby=hobby; this.eat=function(){ alert("我叫"+this.name+",我喜歡"+this.hobby+",是個程序員"); } } var maidou =new Pet("麥兜",25,"coding");//實例化、建立對象 maidou.eat();//調用eat方法
  1. 用工廠方式來建立(內置對象)
var wcDog =new Object(); wcDog.name="旺財"; wcDog.age=3; wcDog.work=function(){ alert("我是"+wcDog.name+",汪汪汪......"); } wcDog.work();
  1. 用原型方式來建立
function Dog(){ } Dog.prototype.name="旺財"; Dog.prototype.eat=function(){ alert(this.name+"是個吃貨"); } var wangcai =new Dog(); wangcai.eat();
  1. 用混合方式來建立
function Car(name,price){ this.name=name; this.price=price; } Car.prototype.sell=function(){ alert("我是"+this.name+",我如今賣"+this.price+"萬元"); } var camry =new Car("凱美瑞",27); camry.sell();

Javascript 做用鏈域?

  • 全局函數沒法查看局部函數的內部細節,但局部函數能夠查看其上層的函數細節,直至全局細節
  • 若是當前做用域沒有找到屬性或方法,會向上層做用域查找,直至全局函數,這種形式就是做用域鏈

談談 this 對象的理解

  • this 老是指向函數的直接調用者
  • 若是有 new 關鍵字,this 指向 new 出來的實例對象
  • 在事件中,this 指向觸發這個事件的對象
  • IE 下 attachEvent 中的 this 老是指向全局對象 Window

eval 是作什麼的?

eval 的功能是把對應的字符串解析成 JS 代碼並運行

  • 應該避免使用 eval,不安全,很是耗性能(先解析成 js 語句,再執行)
  • 由 JSON 字符串轉換爲 JSON 對象的時候能夠用 eval('('+ str +')');

什麼是 Window 對象? 什麼是 Document 對象?

  • Window 對象表示當前瀏覽器的窗口,是 JavaScript 的頂級對象。
  • 咱們建立的全部對象、函數、變量都是 Window 對象的成員。
  • Window 對象的方法和屬性是在全局範圍內有效的。
  • Document 對象是 HTML 文檔的根節點與全部其餘節點(元素節點,文本節點,屬性節點, 註釋節點)
  • Document 對象使咱們能夠經過腳本對 HTML 頁面中的全部元素進行訪問
  • Document 對象是 Window 對象的一部分,可經過 window.document 屬性對其進行訪問

介紹 DOM 的發展

  • DOM:文檔對象模型(Document Object Model),定義了訪問 HTML 和 XML 文檔的標準,與編程語言及平臺無關
  • DOM0:提供了查詢和操做 Web 文檔的內容 API。未造成標準,實現混亂。如:document.forms['login']
  • DOM1:W3C 提出標準化的 DOM,簡化了對文檔中任意部分的訪問和操做。如:JavaScript 中的 Document 對象
  • DOM2:原來 DOM 基礎上擴充了鼠標事件等細分模塊,增長了對 CSS 的支持。如:getComputedStyle(elem, pseudo)
  • DOM3:增長了 XPath 模塊和加載與保存(Load and Save)模塊。如:XPathEvaluator

介紹 DOM0,DOM2,DOM3 事件處理方式區別

DOM0 級事件處理方式:

  • btn.onclick = func;
  • btn.onclick = null;

DOM2 級事件處理方式:

  • btn.addEventListener('click', func, false);
  • btn.removeEventListener('click', func, false);
  • btn.attachEvent("onclick", func);
  • btn.detachEvent("onclick", func);

DOM3 級事件處理方式:

  • eventUtil.addListener(input, "textInput", func);
  • eventUtil 是自定義對象,textInput 是 DOM3 級事件

事件的三個階段

捕獲、目標、冒泡

介紹事件「捕獲」和「冒泡」執行順序和事件的執行次數?

按照 W3C 標準的事件:首是進入捕獲階段,直到達到目標元素,再進入冒泡階段

事件執行次數(DOM2-addEventListener):元素上綁定事件的個數

  • 注意 1:前提是事件被確實觸發
  • 注意 2:事件綁定幾回就算幾個事件,即便類型和功能徹底同樣也不會「覆蓋」

事件執行順序:判斷的關鍵是否目標元素

  • 非目標元素:根據 W3C 的標準執行:捕獲->目標元素->冒泡(不依據事件綁定順序)
  • 目標元素:依據事件綁定順序:先綁定的事件先執行(不依據捕獲冒泡標準)
  • 最終順序:父元素捕獲->目標元素事件 1->目標元素事件 2->子元素捕獲->子元素冒泡->父元素冒泡
  • 注意:子元素事件執行前提 事件確實「落」到子元素佈局區域上,而不是簡單的具備嵌套關係

在一個 DOM 上同時綁定兩個點擊事件:一個用捕獲,一個用冒泡。事件會執行幾回,先執行冒泡仍是捕獲?

  • 該 DOM 上的事件若是被觸發,會執行兩次(執行次數等於綁定次數)
  • 若是該 DOM 是目標元素,則按事件綁定順序執行,不區分冒泡/捕獲
  • 若是該 DOM 是處於事件流中的非目標元素,則先執行捕獲,後執行冒泡

事件的代理/委託

事件委託是指將事件綁定目標元素的到父元素上,利用冒泡機制觸發該事件

優勢:

  • 能夠減小事件註冊,節省大量內存佔用
  • 能夠將事件應用於動態添加的子元素上

缺點: 使用不當會形成事件在不該該觸發時觸發

示例:

ulEl.addEventListener('click', function(e){ var target = event.target || event.srcElement; if(!!target && target.nodeName.toUpperCase() === "LI"){ console.log(target.innerHTML); } }, false);

IE 與火狐的事件機制有什麼區別? 如何阻止冒泡?

IE 只事件冒泡,不支持事件捕獲;火狐同時支持件冒泡和事件捕獲。

阻止冒泡:

  • 取消默認操做: w3c 的方法是 e.preventDefault(),IE 則是使用 e.returnValue = false;
  • return false javascript 的 return false 只會阻止默認行爲,而是用 jQuery 的話則既阻止默認行爲又防止對象冒泡。
  • 阻止冒泡 w3c 的方法是 e.stopPropagation(),IE 則是使用 e.cancelBubble = true
[js] view plaincopy function stopHandler(event) window.event?window.event.cancelBubble=true:event.stopPropagation(); }

參考連接:淺談 javascript 事件取消和阻止冒泡-開源中國 2015

IE 的事件處理和 W3C 的事件處理有哪些區別?(必考)

綁定事件

  • W3C: targetEl.addEventListener('click', handler, false);
  • IE: targetEl.attachEvent('onclick', handler);

刪除事件

  • W3C: targetEl.removeEventListener('click', handler, false);
  • IE: targetEl.detachEvent(event, handler);

事件對象

  • W3C: var e = arguments.callee.caller.arguments[0]
  • IE: window.event

事件目標

  • W3C: e.target
  • IE: window.event.srcElement

阻止事件默認行爲

  • W3C: e.preventDefault()
  • IE: window.event.returnValue = false'

阻止事件傳播

  • W3C: e.stopPropagation()
  • IE: window.event.cancelBubble = true

W3C 事件的 target 與 currentTarget 的區別?

  • target 只會出如今事件流的目標階段
  • currentTarget 可能出如今事件流的任何階段
  • 當事件流處在目標階段時,兩者的指向相同
  • 當事件流處於捕獲或冒泡階段時:currentTarget 指向當前事件活動的對象(通常爲父級)

如何派發事件(dispatchEvent)?(如何進行事件廣播?)

  • W3C: 使用 dispatchEvent 方法
  • IE: 使用 fireEvent 方法
var fireEvent = function(element, event){ if (document.createEventObject){ var mockEvent = document.createEventObject(); return element.fireEvent('on' + event, mockEvent) }else{ var mockEvent = document.createEvent('HTMLEvents'); mockEvent.initEvent(event, true, true); return !element.dispatchEvent(mockEvent); } }

什麼是函數節流?介紹一下應用場景和原理?

  • 函數節流(throttle)是指阻止一個函數在很短期間隔內連續調用。 只有當上一次函數執行後達到規定的時間間隔,才能進行下一次調用。 但要保證一個累計最小調用間隔(不然拖拽類的節流都將無連續效果)
  • 函數節流用於 onresize, onscroll 等短期內會屢次觸發的事件
  • 函數節流的原理:使用定時器作時間節流。 當觸發一個事件時,先用 setTimout 讓這個事件延遲一小段時間再執行。 若是在這個時間間隔內又觸發了事件,就 clearTimeout 原來的定時器, 再 setTimeout 一個新的定時器重複以上流程。

函數節流簡單實現:

function throttle(method, context) { clearTimeout(methor.tId); method.tId = setTimeout(function(){ method.call(context); }, 100); // 兩次調用至少間隔 100ms } // 調用 window.onresize = function(){ throttle(myFunc, window); }

區分什麼是「客戶區座標」、「頁面座標」、「屏幕座標」?

  • 客戶區座標:鼠標指針在可視區中的水平座標(clientX)和垂直座標(clientY)
  • 頁面座標:鼠標指針在頁面佈局中的水平座標(pageX)和垂直座標(pageY)
  • 屏幕座標:設備物理屏幕的水平座標(screenX)和垂直座標(screenY)

如何得到一個 DOM 元素的絕對位置?

  • elem.offsetLeft:返回元素相對於其定位父級左側的距離
  • elem.offsetTop:返回元素相對於其定位父級頂部的距離
  • elem.getBoundingClientRect():返回一個 DOMRect 對象,包含一組描述邊框的只讀屬性,單位像素

分析 ['1', '2', '3'].map(parseInt) 答案是多少?(常考)

答案:[1, NaN, NaN]

parseInt(string, radix) 第 2 個參數 radix 表示進制。省略 radix 或 radix = 0,則數字將以十進制解析

map 每次爲 parseInt 傳 3 個參數(elem, index, array),其中 index 爲數組索引

所以,map 遍歷 ["1", "2", "3"],相應 parseInt 接收參數以下

parseInt('1', 0); // 1 parseInt('2', 1); // NaN parseInt('3', 2); // NaN

因此,parseInt 參數 radix 不合法,致使返回值爲 NaN

new 操做符具體幹了什麼?

  • 建立實例對象,this 變量引用該對象,同時還繼承了構造函數的原型
  • 屬性和方法被加入到 this 引用的對象中
  • 新建立的對象由 this 所引用,而且最後隱式的返回 this

用原生 JavaScript 的實現過什麼功能嗎?

封裝選擇器、調用第三方 API、設置和獲取樣式(自由回答)

解釋一下這段代碼的意思嗎?

[].forEach.call($$("*"), function(el){ el.style.outline = "1px solid #" + (~~(Math.random()*(1<<24))).toString(16); })

解釋:獲取頁面全部的元素,遍歷這些元素,爲它們添加 1 像素隨機顏色的輪廓(outline)

  • 函數被許多現代瀏覽器命令行支持,等價於 document.querySelectorAll(sel)
  • [].forEach.call(NodeLists) // 使用 call 函數將數組遍歷函數 forEach 應到節點元素列表
  • el.style.outline = "1px solid #333" // 樣式 outline 位於盒模型以外,不影響元素佈局位置
  • (1<<24) // parseInt("ffffff", 16) == 16777215 == 2^24 - 1 // 1<<24 == 2^24 == 16777216
  • Math.random()*(1<<24) // 表示一個位於 0 到 16777216 之間的隨機浮點數
  • Math.random()*(1<<24) // 做用至關於 parseInt 取整
  • (~~(Math.random()*(1<<24))).toString(16) // 轉換爲一個十六進制-

JavaScript 實現異步編程的方法?

  • 回調函數
  • 事件監聽
  • 發佈/訂閱
  • Promises 對象
  • Async 函數[ES7]

web 開發中會話跟蹤的方法有哪些

  • cookie
  • session
  • url 重寫
  • 隱藏 input
  • ip 地址

什麼是閉包(closure),爲何要用它?

閉包是指有權訪問另外一個函數做用域中變量的函數,建立閉包的最多見的方式就是在一個函數內建立另外一個函數,經過另外一個函數訪問這個函數的局部變量,利用閉包能夠突破做用鏈域

閉包的特性:

  • 函數內再嵌套函數
  • 內部函數能夠引用外層的參數和變量
  • 參數和變量不會被垃圾回收機制回收

javascript 代碼中的"use strict";是什麼意思 ? 使用它區別是什麼?

use strict 是一種 ECMAscript 5 添加的(嚴格)運行模式,這種模式使得 Javascript 在更嚴格的條件下運行,使 JS 編碼更加規範化的模式,消除 Javascript 語法的一些不合理、不嚴謹之處,減小一些怪異行爲

如何判斷一個對象是否屬於某個類?

// 使用instanceof (待完善) if(a instanceof Person){ alert('yes'); }

js 延遲加載的方式有哪些?

defer 和 async、動態建立 DOM 方式(用得最多)、按需異步載入 js

defer 和 async

defer 並行加載 js 文件,會按照頁面上 script 標籤的順序執行 async 並行加載 js 文件,下載完成當即執行,不會按照頁面上 script 標籤的順序執行

Ajax 是什麼? 如何建立一個 Ajax?

ajax 的全稱:Asynchronous Javascript And XML

異步傳輸+js+xml

所謂異步,在這裏簡單地解釋就是:向服務器發送請求的時候,咱們沒必要等待結果,而是能夠同時作其餘的事情,等到有告終果它本身會根據設定進行後續操做,與此同時,頁面是不會發生整頁刷新的,提升了用戶體驗

  • 建立 XMLHttpRequest 對象,也就是建立一個異步調用對象
  • 建一個新的 HTTP 請求,並指定該 HTTP 請求的方法、URL 及驗證信息
  • 設置響應 HTTP 請求狀態變化的函數
  • 發送 HTTP 請求
  • 獲取異步調用返回的數據
  • 用 JavaScript 和 DOM 實現局部刷新

同步和異步的區別?

  • 同步:瀏覽器訪問服務器請求,用戶看獲得頁面刷新,從新發請求,等請求完,頁面刷新,新內容出現,用戶看到新內容,進行下一步操做
  • 異步:瀏覽器訪問服務器請求,用戶正常操做,瀏覽器後端進行請求。等請求完,頁面不刷新,新內容也會出現,用戶看到新內容

documen.write 和 innerHTML 的區別

  • document.write 只能重繪整個頁面
  • innerHTML 能夠重繪頁面的一部分

DOM 操做——怎樣添加、移除、移動、複製、建立和查找節點?

建立新節點

  • createDocumentFragment() //建立一個 DOM 片斷
  • createElement() //建立一個具體的元素
  • createTextNode() //建立一個文本節點

添加、移除、替換、插入

  • appendChild()
  • removeChild()
  • replaceChild()
  • insertBefore() //在已有的子節點前插入一個新的子節點

查找

  • getElementsByTagName() //經過標籤名稱
  • getElementsByName() // 經過元素的 Name 屬性的值(IE 容錯能力較強,會獲得一個數組,其中包括 id 等於 name 值的) * getElementById() //經過元素 Id,惟一性

那些操做會形成內存泄漏?

  • 內存泄漏指任何對象在您再也不擁有或須要它以後仍然存在
  • 垃圾回收器按期掃描對象,並計算引用了每一個對象的其餘對象的數量。若是一個對象的引用數量爲 0(沒有其餘對象引用過該對象),或對該對象的唯一引用是循環的,那麼該對象的內存便可回收
  • setTimeout 的第一個參數使用字符串而非函數的話,會引起內存泄漏
  • 閉包、控制檯日誌、循環(在兩個對象彼此引用且彼此保留時,就會產生一個循環)

漸進加強和優雅降級

  • 漸進加強 :針對低版本瀏覽器進行構建頁面,保證最基本的功能,而後再針對高級瀏覽器進行效果、交互等改進和追加功能達到更好的用戶體驗。
  • 優雅降級 :一開始就構建完整的功能,而後再針對低版本瀏覽器進行兼容

Javascript 垃圾回收方法

標記清除(mark and sweep)

  • 這是 JavaScript 最多見的垃圾回收方式,當變量進入執行環境的時候,好比函數中聲明一個變量,垃圾回收器將其標記爲「進入環境」,當變量離開環境的時候(函數執行結束)將其標記爲「離開環境」
  • 垃圾回收器會在運行的時候給存儲在內存中的全部變量加上標記,而後去掉環境中的變量以及被環境中變量所引用的變量(閉包),在這些完成以後仍存在標記的就是要刪除的變量了

引用計數(reference counting)

  • 在低版本 IE 中常常會出現內存泄露,不少時候就是由於其採用引用計數方式進行垃圾回收。引用計數的策略是跟蹤記錄每一個值被使用的次數,當聲明瞭一個 變量並將一個引用類型賦值給該變量的時候這個值的引用次數就加 1,若是該變量的值變成了另一個,則這個值得引用次數減 1,當這個值的引用次數變爲 0 的時 候,說明沒有變量在使用,這個值無法被訪問了,所以能夠將其佔用的空間回收,這樣垃圾回收器會在運行的時候清理掉引用次數爲 0 的值佔用的空間

參考連接 內存管理-MDN

用過哪些設計模式?

  1. 工廠模式:
  • 主要好處就是能夠消除對象間的耦合,經過使用工程方法而不是 new 關鍵字。將全部實例化的代碼集中在一個位置防止代碼重複
  • 工廠模式解決了重複實例化的問題 ,但還有一個問題,那就是識別問題,由於根本沒法 搞清楚他們究竟是哪一個對象的實例
function createObject(name,age,profession){//集中實例化的函數var obj = new Object(); obj.name = name; obj.age = age; obj.profession = profession; obj.move = function () { return this.name + ' at ' + this.age + ' engaged in ' + this.profession; }; return obj; } var test1 = createObject('trigkit4',22,'programmer');//第一個實例var test2 = createObject('mike',25,'engineer');//第二個實例
  1. 構造函數模式
  • 使用構造函數的方法 ,即解決了重複實例化的問題 ,又解決了對象識別的問題,該模式與工廠模式的不一樣之處在於
  • 構造函數方法沒有顯示的建立對象 (new Object());
  • 直接將屬性和方法賦值給 this 對象;
  • 沒有 renturn 語句

說說你對閉包的理解

使用閉包主要是爲了設計私有的方法和變量。閉包的優勢是能夠避免全局變量的污染,缺點是閉包會常駐內存,會增大內存使用量,使用不當很容易形成內存泄露。在 js 中,函數即閉包,只有函數纔會產生做用域的概念

閉包有三個特性:

  • 函數嵌套函數
  • 函數內部能夠引用外部的參數和變量
  • 參數和變量不會被垃圾回收機制回收

請解釋一下 JavaScript 的同源策略

  • 概念:同源策略是客戶端腳本(尤爲是 Javascript)的重要的安全度量標準。它最先出自 Netscape Navigator2.0,其目的是防止某個文檔或腳本從多個不一樣源裝載。這裏的同源策略指的是:協議,域名,端口相同,同源策略是一種安全協議
  • 指一段腳本只能讀取來自同一來源的窗口和文檔的屬性

爲何要有同源限制?

咱們舉例說明:好比一個黑客程序,他利用 Iframe 把真正的銀行登陸頁面嵌到他的頁面上,當你使用真實的用戶名,密碼登陸時,他的頁面就能夠經過 Javascript 讀取到你的表單中 input 中的內容,這樣用戶名,密碼就輕鬆到手了。]

缺點: 如今網站的 JS 都會進行壓縮,一些文件用了嚴格模式,而另外一些沒有。這時這些原本是嚴格模式的文件,被 merge 後,這個串就到了文件的中間,不只沒有指示嚴格模式,反而在壓縮後浪費了字節

實現一個函數 clone,能夠對 JavaScript 中的 5 種主要的數據類型(包括 Number、String、Object、Array、Boolean)進行值複製(常考)

function deepClone(obj) { if (!isObject(obj)) { throw new Error('obj 不是一個對象!') } let isArray = Array.isArray(obj) let cloneObj = isArray ? [] : {} for (let key in obj) { cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key] } return cloneObj }

注意:for...in 法不支持拷貝 func、date、reg 和 err

// 代理法 function deepClone(obj) { if (!isObject(obj)) { throw new Error('obj 不是一個對象!') } let isArray = Array.isArray(obj) let cloneObj = isArray ? [...obj] : { ...obj } Reflect.ownKeys(cloneObj).forEach(key => { cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key] }) return cloneObj }

說說嚴格模式的限制

  • 嚴格模式主要有如下限制:
  • 變量必須聲明後再使用
  • 函數的參數不能有同名屬性,不然報錯
  • 不能使用 with 語句
  • 不能對只讀屬性賦值,不然報錯
  • 不能使用前綴 0 表示八進制數,不然報錯
  • 不能刪除不可刪除的屬性,不然報錯
  • 不能刪除變量 delete prop,會報錯,只能刪除屬性 delete global[prop]
  • eval 不會在它的外層做用域引入變量
  • eval 和 arguments 不能被從新賦值
  • arguments 不會自動反映函數參數的變化
  • 不能使用 arguments.callee
  • 不能使用 arguments.caller
  • 禁止 this 指向全局對象
  • 不能使用 fn.caller 和 fn.arguments 獲取函數調用的堆棧
  • 增長了保留字(好比 protected、static 和 interface)

如何刪除一個 cookie

將時間設爲當前時間往前一點

var date = new Date(); date.setDate(date.getDate() - 1);//真正的刪除

setDate()方法用於設置一個月的某一天

expires 的設置

document.cookie = 'user='+ encodeURIComponent('name') + ';expires = ' + new Date(0)

編寫一個方法 求一個字符串的字節長度

假設:一個英文字符佔用一個字節,一箇中文字符佔用兩個字節

function GetBytes(str){ var len = str.length; var bytes = len; for(var i=0; i<len; i++){ if (str.charCodeAt(i) > 255) bytes++; } return bytes; } alert(GetBytes("你好,as"));

請解釋什麼是事件代理

事件代理(Event Delegation),又稱之爲事件委託。是 JavaScript 中經常使用綁定事件的經常使用技巧。顧名思義,「事件代理」便是把本來須要綁定的事件委託給父元素,讓父元素擔當事件監聽的職務。事件代理的原理是 DOM 元素的事件冒泡。使用事件代理的好處是能夠提升性能

attribute 和 property 的區別是什麼?

  • attribute 是 dom 元素在文檔中做爲 html 標籤擁有的屬性;
  • property 就是 dom 元素在 js 中做爲對象擁有的屬性。
  • 對於 html 的標準屬性來講,attribute 和 property 是同步的,是會自動更新的
  • 可是對於自定義的屬性來講,他們是不一樣步的

頁面編碼和被請求的資源編碼若是不一致如何處理?

  • 後端響應頭設置 charset
  • 前端頁面<meta>設置 charset

把 <script> 放在 </body> 以前和以後有什麼區別?瀏覽器會如何解析它們?

按照 HTML 標準,在</body>結束後出現<script>或任何元素的開始標籤,都是解析錯誤
雖然不符合 HTML 標準,但瀏覽器會自動容錯,使實際效果與寫在</body>以前沒有區別
瀏覽器的容錯機制會忽略<script>以前的</body>,視做<script>仍在 body 體內。省略</body></html>閉合標籤符合 HTML 標準,服務器能夠利用這一標準

異步加載 JS 的方式有哪些?

  • 設置<script>屬性 async="async" (一旦腳本可用,則會異步執行)
  • 動態建立 script DOM:document.createElement('script');
  • XmlHttpRequest 腳本注入
  • 異步加載庫 LABjs
  • 模塊加載器 Sea.js

JavaScript 中,調用函數有哪幾種方式?

  • 方法調用模式 Foo.foo(arg1, arg2);
  • 函數調用模式 foo(arg1, arg2);
  • 構造器調用模式 (new Foo())(arg1, arg2);
  • call/applay 調用模式 Foo.foo.call(that, arg1, arg2);
  • bind 調用模式 Foo.foo.bind(that)(arg1, arg2)();

簡單實現 Function.bind 函數?

if (!Function.prototype.bind) { Function.prototype.bind = function(that) { var func = this, args = arguments; return function() { return func.apply(that, Array.prototype.slice.call(args, 1)); } } } // 只支持 bind 階段的默認參數: func.bind(that, arg1, arg2)(); // 不支持如下調用階段傳入的參數: func.bind(that)(arg1, arg2);

列舉一下 JavaScript 數組和對象有哪些原生方法

  • 數組:

    • arr.concat(arr1, arr2, arrn);
    • arr.join(",");
    • arr.sort(func);
    • arr.pop();
    • arr.push(e1, e2, en);
    • arr.shift();
    • unshift(e1, e2, en);
    • arr.reverse();
    • arr.slice(start, end);
    • arr.splice(index, count, e1, e2, en);
    • arr.indexOf(el);
    • arr.includes(el); // ES6
  • 對象:

    • object.hasOwnProperty(prop);
    • object.propertyIsEnumerable(prop);
    • object.valueOf();
    • object.toString();
    • object.toLocaleString();
    • Class.prototype.isPropertyOf(object);

Array.splice() 與 Array.splice() 的區別?

  • slice -- 「讀取」數組指定的元素,不會對原數組進行修改

    • 語法:arr.slice(start, end)
    • start 指定選取開始位置(含)
    • end 指定選取結束位置(不含)
  • splice

    • 「操做」數組指定的元素,會修改原數組,返回被刪除的元素
    • 語法:arr.splice(index, count, [insert Elements])
    • index 是操做的起始位置
    • count = 0 插入元素,count > 0 刪除元素
    • [insert Elements] 向數組新插入的元素

JavaScript 對象生命週期的理解?

  • 當建立一個對象時,JavaScript 會自動爲該對象分配適當的內存
  • 垃圾回收器按期掃描對象,並計算引用了該對象的其餘對象的數量
  • 若是被引用數量爲 0,或唯一引用是循環的,那麼該對象的內存便可回收

哪些操做會形成內存泄漏?

  • JavaScript 內存泄露指對象在不須要使用它時仍然存在,致使佔用的內存不能使用或回收
  • 未使用 var 聲明的全局變量
  • 閉包函數(Closures)
  • 循環引用(兩個對象相互引用)
  • 控制檯日誌(console.log)
  • 移除存在綁定事件的 DOM 元素(IE)
相關文章
相關標籤/搜索