標籤:

總結一些前端的知識點 (一)

想學習前端或編程知識歡迎關注專欄:敲代碼,學編程 - 知乎專欄

一、W3C 標準盒模型和 IE 盒模型區別:

1. W3C 標準盒模型:

盒子的高寬是由盒子的內容區僅由 width, height 決定的,不包含邊框,內外邊距。

2. IE 盒模型:

在 IE 盒模型中,盒子寬高不僅包含了元素的寬高,而且包含了元素的邊框以及內邊距。

所以在同樣的設置下,IE 下的元素會看起來相對於標準盒子來的小,如果你想要標準盒子變為像 IE 盒模型,可以對元素樣式進行設置:

.item {n box-sizing: border-box; //IE 盒模型效果n box-sizing: content-box; //默認值,標準盒模型效果n}n

二、querySelectorAll 與 getElementsBy 系列的區別:

根據該問題下的答案 querySelectorAll 方法相比 getElementsBy 系列方法有什麼區別?,我簡單地總結一下:

  • querySelectorAll 屬於 W3C 中 Selectors API 規範, 而 getElementsBy 系列則屬於 W3C DOM 規範。
  • querySelectorAll 方法接受參數是 CSS 選擇符,當傳入的是不符合 CSS 選擇符規範時會拋出異常,而 getElementsBy 系列則接受的參數是單一的 className,tagName 等等。
  • 從返回值角度來看,querySelectorAll 返回的是不變的結點列表,而 getElementsBy 系列返回的是動態的結點列表。

// Demo 1nvar ul = document.querySelectorAll(ul)[0],n lis = ul.querySelectorAll("li");nfor(var i = 0; i < lis.length ; i++){n ul.appendChild(document.createElement("li"));n}nn// Demo 2nvar ul = document.getElementsByTagName(ul)[0], n lis = ul.getElementsByTagName("li"); nfor(var i = 0; i < lis.length ; i++){n ul.appendChild(document.createElement("li")); n}n

因為 Demo 2 中的 lis 是一個動態的結點列表, 每一次調用 lis 都會重新對文檔進行查詢,導致無限循環的問題。

而 Demo 1 中的 lis 是一個靜態的結點列表,是一個 li 集合的快照,對文檔的任何操作都不會對其產生影響。

  • 普遍認為:getElementsBy 系列性能比 querySelectorAll 好
  • querySelectorAll 返回值為一個 NodeList,而 getElementsBy 系列返回值為一個 HTMLCollection

三、NodeList 與 HTMLCollection 區別:

  1. HTMLCollection 是元素集合而 NodeList 是節點集合(即可以包含元素,文本節點,以及注釋等等)。
  2. node.childNodes,querySelectorAll(雖然是靜態的) 返回的是 NodeList,而 node.children 和 node.getElementsByXXX 返回 HTMLCollection。

四、動態作用域和靜態作用域的區別:

  • 靜態作用域又稱之為詞法作用域:即詞法作用域的函數中遇到既不是形參也不是函數內部定義的局部變數的變數時,它會根據函數定義的環境中查詢。

var foo = 1;nnfunction static() {n console.log(foo);n}nn(function() {n var foo = 2;n static();n}());n

JS 的變數是遵循靜態作用域的,在上述代碼中會列印出 1 而非 2,因為 static 函數在作用域創建的時候,記錄的 foo 是 1,如果是動態作用域的話,那麼它應該列印出 2

靜態作用域是產生閉包的關鍵,即它在代碼寫好之後就被靜態決定它的作用域了。

  • 動態域的函數中遇到既不是形參也不是函數內部定義的局部變數的變數時,到函數調用的環境去查詢

在 JS 中,關於 this 的執行是基於動態域查詢的,下面這段代碼列印出 1,如果按靜態作用域的話應該會列印出 2

var foo = 1;nnvar obj = {n foo: 2,n bar: function() {n console.log(this.foo);n }n};nnvar bar = obj.bar;nbar();n

五、數據類型檢測方式:

  • typeof:使用 typeof 檢測數據類型,返回值有:number, string, boolean, undefined, function, object

常見的返回值就不說了,需要注意的是下面的幾種情況:

console.log(typeof NaN); //numbernconsole.log(typeof typeof typeof function(){}) //stringnvar str = abc; nconsole.log(typeof str++); //numbernconsole.log(typeof (abc + 1)); //stringnnnconsole.log(typeof null); //objectnconsole.log(typeof /d/g); //objectnconsole.log(typeof []); //objectnconsole.log(typeof new Date()); //objectnconsole.log(typeof Date()); //stringnconsole.log(typeof Date); //functionn

  • instanceof:只要在當前實例的原型鏈上,用 instanceof 檢測出來的結果都是 true,所以在類的原型繼承中,最後檢測出來的結果未必是正確的。

1. 使用 instanceof 判斷基本類型:

var str1 = abc;nvar str2 = new String(abc);nnconsole.log(str1 instanceof String); //falsenconsole.log(str2 instanceof String); //truennconsole.log(false instanceof Boolean); //falsenconsole.log(new Boolean(false) instanceof Boolean) //truen

判斷基本類型還是用 typeof 吧,instanceof 不適合。

2. 判斷實例:

function Foo(){} nvar foo = new Foo(); nconsole.log(foo instanceof Foo) //truen

3. 判斷繼承關係:

function Parent() {}nfunction Child() {}nnChild.prototype = new Parent();nChild.prototype.constructor = Child;nnvar child = new Child();nconsole.log(child instanceof Child); //truenconsole.log(child instanceof Parent); //truenconsole.log(child instanceof Object); //truenconsole.log(Child instanceof Function); //truenconsole.log(Function instanceof Object); //true nconsole.log(Child instanceof Child); //falsen

如果你對上面輸出的結果感到困惑,那建議你看下這面這篇文章:深入理解javascript原型和閉包(5)--instanceof - 王福朋 - 博客園

  • constructor:檢測數據類型

console.log((1).constructor === Number); //truenconsole.log("a".constructor === String); //truenconsole.log([].constructor === Array); //truenconsole.log({}.constructor === Object); //truen

檢測功能還是挺全面的,不過也有它的局限性:如果我們把類的原型進行重寫了,在重寫的過程中,很有可能把之前 constructor 給覆蓋掉,這樣檢測出的結果就不準確了。

function Fn() {}nFn.prototype = new Array();nvar f = new Fn();nconsole.log(f.constructor === Array); // truen

並且 constructor 檢測不出 null,undefined 的類型,所以判斷類型用 constructor 也不太好用

  • Object.prototype.toStrong.call

Object.prototype.toStrong.call() 是檢測數據類型最準確最常用的方式,

function toString(data) {ntreturn Object.prototype.toString.call(data).slice(8, -1);n}nnconsole.log(toString(abc) === String); nconsole.log(toString(1) === Number);nconsole.log(toString(false) === Boolean);nconsole.log(toString(null) === Null);nconsole.log(toString(undefined) === Undefined);nconsole.log(toString([]) === Array);nconsole.log(toString({}) === Object);nconsole.log(toString(function(){}) === Function)n

六、函數和對象的關係:

首先函數是一種對象:

var fn = function() {}nconsole.log(fn instanceof Object); //truen

對,函數是一種對象,但是函數卻不像數組那樣 ---- 你可以說數組是對象的一種,因為數組就像對象的一個子集一樣,但是函數與對象之間,卻不僅僅是包含和被包含的關係。

對象可以由函數創建:

function Fn() {n this.name = "Lindz";n this.year = 1995;n}nvar fn1 = new Fn(); // {name: "Lindz", year: 1995}n

上面的例子很簡單,它說明了對象可以通過函數重建,但是其實對象都是通過函數創建的,有人可能會反駁,他認為:

var obj = { a: 10, b: 20 };nvar arr = [5, true, "aa"];n

但是這些都是編程中的語法糖,實際上編譯器幫我們做了下面這些事:

var obj = new Object();nobj.a = 10;nobj.b = 20;nnvar arr = new Array();narr[0] = 5;narr[1] = true;narr[2] = "aa";nnconsole.log(typeof (Object)); // functionnconsole.log(typeof (Array)); // functionn

七、JS 如何判斷函數是 new 調用還是普通調用

第一種方式:通過 instanceof 判斷

function Person() {n if(this instanceof arguments.callee) {ntconsole.log(new 調用);n }else {ntconsole.log(普通調用);n }n}nnlet p1 = new Person(); // new 調用nlet p2 = Person();tt // 函數調用 n

第二種方式:通過 constructor

function Person() {n if(this.constructor === arguments.callee) {ntconsole.log(new 調用);n }else {ntconsole.log(普通調用);n }n}nnlet p1 = new Person(); // new 調用nlet p2 = Person();tt // 函數調用 n

未完待續!


推薦閱讀:

如何只用 CSS 完成漂亮的載入
哪個才是最適合你的 Web UI 自動化測試框架
前端工作師都能做什麼?

TAG:前端开发 |