JavaScript 基礎面試題(1)

1. 圖片優化(懶加載/預加載)

一、使用base_64編碼圖片或SVG圖片代替原始的png與jpeg圖片,再像素要求不高的狀況下使用jpeg圖片代替png圖片vue

二、圖片懶加載,在頁面上的未可視區域能夠添加一個滾動條事件,判斷圖片位置與瀏覽器頂端 的距離與頁面的距離,若是前者小於後者,優先加載。jquery

- 原生JavaScript實現圖片的懶加載

- jQuery插件 jquery.lazy 

- vue中使用 vue-lazyload

- mint-ui 插件內置懶加載組件
複製代碼

三、圖片的預加載,若是爲幻燈片、相冊等,可使用圖片預加載技術,將當前展現圖片的前一張和後一張優先 下載。初始化的時候得到圖片的src以後爲每個元素提早添加圖片的地址路徑。保證再第二張圖片顯示的時候已經加載到頁面當中瀏覽器

實現方法:循環圖片數據,實例化對象的方式建立圖片元素 new image() 動態綁定每個image的src屬性,並追加到DOM流中
複製代碼

2.數據類型種類

  • JS 中分爲七種內置類型,七種內置類型又分爲兩大類型:基本類型和對象(Object)。bash

  • 基本類型有六種: null,undefined,boolean,number,string,symbol。閉包

  • 對象(Object)是引用類型,在使用過程當中會遇到淺拷貝和深拷貝的問題。app

let a = { name: 'FE' }
let b = a
b.name = 'EF'
console.log(a.name) // EF
複製代碼

三、typeof

  • typeof 對於基本類型,除了 null 均可以顯示正確的類型模塊化

  • 想得到一個變量的正確類型,能夠經過 Object.prototype.toString.call(xx)函數

四、 new 操做符的做用

-    新生成了一個對象

-    連接到原型

-    綁定this

-    返回新對象
複製代碼
function create() {
    // 建立一個空的對象
    let obj = new Object()
    // 得到構造函數
    let Con = [].shift.call(arguments)
    // 連接到原型
    obj.__proto__ = Con.prototype
    // 綁定 this,執行構造函數
    let result = Con.apply(obj, arguments)
    // 確保 new 出來的是個對象
    return typeof result === 'object' ? result : obj
}
複製代碼

五、instanceof操做符

判斷對象屬於某一個類,回去查找對象的constructor的prototype
複製代碼

六、this 環境上下文對象

function foo() {
	console.log(this.a)
}
var a = 1
foo()

var obj = {
	a: 2,
	foo: foo
}
obj.foo()
複製代碼

以上二者狀況 this 只依賴於調用函數前的對象,優先級是第二個狀況大於第一個狀況優化

如下狀況是優先級最高的,this 只會綁定在 c 上,不會被任何方式修改 this 指向ui

var c = new foo()
c.a = 3
console.log(c.a)
複製代碼

還有種就是利用 call,apply,bind 改變 this,這個優先級僅次於 new

function a() {
    return () => {
        return () => {
        	console.log(this)
        }
    }
}
console.log(a()()())
複製代碼

箭頭函數實際上是沒有 this 的,這個函數中的 this 只取決於他外面的第一個不是箭頭函數的函數的 this。在這個例子中,由於調用 a 符合前面代碼中的第一個狀況,因此 this 是 window。而且 this 一旦綁定了上下文,就不會被任何代碼改變

7.做用域/做用域鏈

一、做用域

  • 種類:JS中有三種做用域,全局做用域,函數做用域,ES6新推出塊級做用域

  • 概念:一個變量的可訪問規則,再函數建立的時候就已經定義好做用域,整個的JS文件執行有一個最外層的全局做用域(window)

  • 使用: 本做用域內部的全部變量均可已再本做用域內部訪問,外部沒法訪問。內部可訪問上級做用域變量,本做用於內部所用使用var聲明的變量會有一個做用域提高的過程,let與const聲明的變量沒有變量提高

二、做用域鏈

  • 一個變量的訪問規則的鏈式操做

  • 能夠把它理解成包含自身變量對象和上級變量對象的列表,經過 [[Scope]] 屬性查找上級變量

  • 當訪問一個變量的時候,先在本做用域內部進行查找,若是沒有去上級做用域進行查找,直到全局做用域window下面,都沒有,返回undefined

8.閉包(closure)

一、特色:

  • 內層做用域能夠訪問外層做用域的變量

  • 閉包就是可以讀取其餘函數內部變量的函數

  • 函數 A 返回了一個函數 B,而且函數 B 中使用了函數 A 的變量,函數 B 就被稱爲閉包。

  • 閉包函數引用的變量是存儲在堆上的,因此說,當閉包函數彈出調用棧以後,閉包返回的函數依然能調用到閉包函數的變量

二、優勢:

  • 使用閉包能夠造成獨立的空間,延長變量的生命週期,保存中間狀態值

  • 能夠封裝一些私有變量,外部沒法進行直接訪問(例如用戶登錄狀態計數器)建立當即執行函數(閉包)實現JS模塊化封裝

  • 解決var聲明的循環語句變量沒法長久保存的問題

三、缺點:

  • 濫用閉包函數會形成內存泄露,由於閉包中引用到的包裹函數中定義的變量都 永遠不會被釋放,因此咱們應該在必要的時候,及時釋放這個閉包函數,將再也不使用的閉包引用設置爲null;

  • 因爲函數內部的變量都被保存在內存中, 會致使內存消耗大;

四、相關代碼:

for ( var i=1; i<=5; i++) {
	setTimeout( function timer() {
		console.log( i );
	}, i*1000 );
}
// 每次循環都會輸出 5 沒法保存變量
複製代碼
for (var i = 1; i <= 5; i++) {
  (function(j) {
    setTimeout(function timer() {
      console.log(j);
    }, j * 1000);
  })(i);
}
// 建立當即執行函數,造成閉包,保存每一次循環的變量
複製代碼
// 解決下列調用打印每次都是5的問題
var arr = []
for (var i = 0; i < 5; i++) {
    arr.push(function() { console.log(i) })
}

// 使用閉包的方式
for (var i = 0; i < 5; i++) {
    (function(i) {
        arr.push(function() {
            console.log(i)
        })
    })(i)
}

// 使用ES6的let建立塊級做用域
for (let i = 0; i < 5; i++) {
    arr.push(function() {
        console.log(i)
    })
}

// 使用setTimeout的第三個參數
for (let i = 0; i < 5; i++) {
    setTimeout(function() {
        arr.push(function() {
            console.log(i)
        })
    }, 0,i)
}
複製代碼
相關文章
相關標籤/搜索