2019前端面試題記錄(雜文)

session和redis


目前session直接是js變量,放到nodejs的進程內存中,存在問題
問題一:進程內存有限,訪問量過大,內存爆增怎麼辦?(有可能進程崩潰)
問題二:正式上線後運行的是多進程,進程之間內存無法共享(不同進程間的session不能共享數據)
1 redis是web server最常用的一個緩存庫,數據存放在內存中 (內存讀寫特比快,但是比較昂貴)
2 相比mysql,訪問速度快 (mysql放在磁盤中,而redis放在內存中,兩者)
3 但是成本高,可儲存的數據量更小 (內存的硬傷)

具體方案

1 將web server和redis拆分爲兩個單獨的服務
2 雙方都是獨立的,都是可擴展的(例如都擴展成集羣)
3 包括mysql,也是一個單獨的服務可以擴展

vue同步

Vue.config.async = false

vue2的Object.defineProperty和vue3的Proxy

我們只監聽了一個屬性,一個對象不可能只有一個屬性,我們需要對對象每個屬性進行監聽
Vue的操作就是加入了發佈訂閱模式,結合Object.defineProperty的劫持能力,實現了可用性很高的雙向綁定。
是的,Object.defineProperty的第一個缺陷,無法監聽數組變化。 
第二個缺陷,只能劫持對象的屬性,因此我們需要對每個對象的每個屬性進行遍歷,如果屬性值也是對象那麼需要深度遍歷,顯然能劫持一個完整的對象是更好的選擇。
 Proxy可以直接監聽對象而非屬性
Proxy可以直接監聽數組的變化

基本類型和引用類型的區別

區別

一、 基本類型: string,number,boolean,null,undefined,symbol,BigInt

二、 引用類型: Function,Array,Object

判斷

最常見的判斷方法:typeof
返回的是數據類型(number,boolean,string,function,object,undefined)

判斷已知對象類型的方法: instanceof
返回的是布爾值 某個對象的實例

根據對象的constructor判斷: constructor

 

var

var不能用於定義常量
var可以重複聲明變量
var是全局的
var存在變量提升

let 和 const

let和const不存在變量提升(暫時性死區) var存在(var在創建時就被初始化,並且賦值爲undefined)
let 局部作用域
const如果是對象的話不能改變它的內存地址,即不能重新賦值另一個對象 const一旦聲明變量,就必須立即初始化,不能留到以後賦值。如const a這樣會報錯
如果是基本類型則不能改變類型 如 const a = 123 ,不能賦值a ="123",會報錯

 

基本類型的比較是值的比較:

任何方法都無法改變一個基本類型的值,比如一個字符串,引用類型則反之。
只有在它們的值相等的時候它們才相等。但你可能會這樣:
var a = 1;
var b = true;
console.log(a == b);//true   ==會進行類型轉換   ===不會進行類型轉換
但是當兩個值的類型相同的時候,即使是==也相當於是===。
兩個變量可以參加任何操作而相互不受影響。也就是說基本類型在賦值操作後,兩個變量是相互不受影響的。
因爲基礎類型的變量相互賦值相當於在內存中開闢新的地址
而引用類型的賦值其實是對象保存在棧區地址指針的賦值,因此兩個變量指向同一個對象即指向相同的地址,任何的操作都會相互影響。

比較的區別
基礎類型之間的對比直接比較值  即使值如果 == 結果就是 true

引用類型之間的對比直接比較內存地址  即使值如果 == 結果是 false 因爲內存地址不一樣 

圖片說明

由上文就有了深拷貝和淺拷貝的概念
基礎變量的賦值屬於深拷貝 即不會相互影響 因爲內存地址不一樣

引用類型的賦值屬於淺拷貝 會相互影響  因爲內存地址一樣

深拷貝的解決辦法

let obj2=JSON.parse(JSON.stringify(obj))

prototype、__proto__、constructor

 我們需要牢記兩點: ①__proto__和constructor屬性是對象所獨有的; ② prototype屬性是函數所獨有的,因爲函數也是一種對象,所以函數也擁有__proto__和constructor屬性。 __proto__屬性的作用就是當訪問一個對象的屬性時,如果該對象內部不存在這個屬性,那麼就會去它的__proto__屬性所指向的那個對象(父對象)裏找,一直找,直到__proto__屬性的終點null,然後返回undefined,再往上找就相當於在null上取值,會報錯。通過__proto__屬性將對象連接起來的這條鏈路即我們所謂的原型鏈。 prototype屬性的作用就是讓該函數所實例化的對象們都可以找到公用的屬性和方法,即f1.__proto__ === Foo.prototype。 constructor屬性的含義就是指向該對象的構造函數,所有函數(此時看成對象了)最終的構造函數都指向Function。 另外 __proto__ 屬性是瀏覽器對es5的實現,而不是es標準。

get 和 post 的區別

get,通過拼接url進行傳遞參數;
post,通過body體傳輸參數
get用來獲取數據,post用來提交數據
get在瀏覽器回退時是無影響的,post會再次提交請求
get效率高   (比post高一點)
get安全性低 (比post低一點)

Session 登陸與 Token 登陸的區別 

1、Session 登陸是在服務器端生成用戶相關 session 數據,發給客戶端 session_id 存放到 cookie 中,這樣在客戶端請求時帶上 session_id 就可以驗證服務器端是否存在 session 數據,以此完成用戶認證。這種認證方式,可以更好的在服務端對會話進行控制,安全性比較高(session_id 隨機),但是服務端需要存儲 session 數據(如內存或數據庫),這樣無疑增加維護成本和減弱可擴展性(多臺服務器)。 CSRF 攻擊一般基於 cookie。另外,如果是原生 app 使用這種服務接口,因爲沒有瀏覽器 cookie 功能,所以接入會相對麻煩。 
2、基於 token 的用戶認證是一種服務端無狀態的認證方式,服務端不用存放 token 數據。用戶驗證後,服務端生成一個 token(hash 或 encrypt)發給客戶端,客戶端可以放到 cookie 或 localStorage 中,每次請求時在 Header 中帶上 token,服務端收到 token,通過驗證後即可確認用戶身份。這種方式相對 cookie 的認證方式就簡單一些,服務端不用存儲認證數據,易維護擴展性強,token 存在 localStorage 可避免 CSRF,web 和 app 應用都比較簡單。不過這種方式在加密或解密的時候會有一些性能開銷(好像也不是很大),有些對稱加密存在安全隱患(aes cbc 字節翻轉攻擊)。

vue-router


vue-router頁面刷新保存頁碼信息 
方案一
vue router 更改地址url 不刷新頁面 不存在history記錄裏面
this.$router.push()  改爲 this.$router.replace() 
replace 的url不會被添加到history記錄裏面
當調用  this.$router.go(-1) 或者 this.$router.back() 
不會回退到replace添加的頁面裏,而是會回到replace之前進入的頁面中
類似於添加一個標記一樣
方案二
vue項目中路由跳轉默認採用hash的方式,而hash的變化不會導致瀏覽器發送請求到服務器;
將獲取數據的的函數的執行放在了Vue生命週期函數 mounted() 中,組件初次加載時執行了 mounted() 函數中的內容,但是再次點擊時只有參數變化,組件已經掛載結束而且不會重新加載,mounted()  中的內容當然也就不會重新執行了。
所以你可以在點擊頁碼的時候改變hash的變化不會重新渲染頁面
然後去監聽頁面的$route的變化 在裏面操作請求數據
watch: {
    '$route' (to, from) {
        this.getData(this.$route.query.id,this.$route.query.pageNo)
    }
}

如果提供了path,params會被忽略。
//$router : 是路由操作對象,只寫對象 即跳轉用 因爲可寫
//$route : 路由信息對象,只讀對象 即讀取信息用 因爲可讀


//query傳參,使用name跳轉
this.$router.push({
    name:'second',
    query: {
        queryId:'20180822',
        queryName: 'query'
    }
})

//query傳參,使用path跳轉
this.$router.push({
    path:'second',
    query: {
        queryId:'20180822',
        queryName: 'query'
    }
})

//query傳參接收
this.queryName = this.$route.query.queryName;
this.queryId = this.$route.query.queryId;

//params傳參 使用name
this.$router.push({
  name:'second',
  params: {
    id:'20180822',
     name: 'query'
  }
})

//params接收參數
this.id = this.$route.params.id ;
this.name = this.$route.params.name ;

//路由
{
path: '/second/:id/:name',
name: 'second',
component: () => import('@/view/second')
}

A、query類似於ajax中get傳參,即在瀏覽器地址欄中顯示參數。
B、params則類似於post,即在瀏覽器地址欄中不顯示參數。
params傳參,以隱藏參數,做好安全保密。 不過使用params傳值的話,頁面一刷新params 的值就消失了。
query相反,建議使用query,一般在地址欄的信息不會是什麼敏感信息

Json Web Token

Json Web Token是怎麼做的?
      1、客戶端通過用戶名和密碼登錄服務器;
      2、服務端對客戶端身份進行驗證;
      3、服務端對該用戶生成Token,返回給客戶端;
      4、客戶端將Token保存到本地瀏覽器,一般保存到cookie中;
      5、客戶端發起請求,需要攜帶該Token;
      6、服務端收到請求後,首先驗證Token,之後返回數據。
      服務端不需要保存Token,只需要對Token中攜帶的信息進行驗證即可;
      無論客戶端訪問後臺的那臺服務器,只要可以通過用戶信息的驗證即可。

前端優化

儘量不操作dom 用虛擬dom
懶加載
使用異步 同步會堵塞頁面
減少cookie傳輸 http請求會攜帶cookie
減少 HTTP請求數
打包css文件 樣式用外部樣式,最好不要用行間樣式,內嵌樣式

爲什麼使用webpack

 模塊化開發(import,require)
 打包(不打包就像html裏面可能有上百個js即瀏覽器需要三次http 請求來獲取這三個文件,打包後就會變成幾 
 個一般是一個js文件來維護上百個文件的依賴關係)
 預處理(Less,Sass,ES6,TypeScript……)
 主流框架腳手架支持(Vue,React,Angular)
 龐大的社區(資源豐富,降低學習成本)
 webpack是當下最流行最前沿的
 熱更新

export 、export default、module.exports、require

es6規範
1.export與export default均可用於導出常量、函數、文件、模塊等
2.在一個文件或模塊中,export、import可以有多個,export default僅有一個
3.通過export方式導出,在導入時要加{ },export default則不需要
4. 
(1) 輸出單個值,使用export default
(2) 輸出多個值,使用export
(3) export default與普通的export不要同時使用

var info = {
    name: 'zs',
    age: 20
}
export default info
 
export var title = '小星星'
 
export var content = '哈哈哈'
CommonJS規範
module.exports = {};
var req=require("./app.js");

exports.fn = function(){}
module.exports = function(){ } 

exports只是module.exports的引用

總結:只要不是直接導出對象,使用module.exports和exports沒有區別,要是導出的對象只能使用module.exports
推薦使用module.exports

 

await、async、prosime、setTimeout執行順序

說明
async 執行順序和普通的上下文一樣 到了就執行

prosime 裏面的代碼是同步的  執行順序和普通的上下文一樣 到了就執行,then裏面的代碼是異步的

await 先阻塞執行完await右邊的代碼然後執行  此時的await會讓出線程,阻塞async內後續的代碼,先去執行async外的代碼。等外面的同步代碼執行完畢,纔會執行裏面的後續代碼。就算await的不是promise對象,是一個同步函數,也會等這樣操作 即 async外的代碼同步完之後的異步執行await 後面的代碼

setTimeout 是等所有異步代碼執行完 並且主進程是空閒的時候 再執行

iconfont 使用 

第一步:引入項目下面生成的fontclass代碼:

<link rel="stylesheet" type="text/css" href="./iconfont.css">
第二步:挑選相應圖標並獲取類名,應用於頁面:

<i class="iconfont icon-xxx"></i>

階乘函數

遞歸

function num(n){

if(n<=0) return 1;return  n*arguments.callee(n-1) 

}
num(5)//120
如何快速寫一個通用的死循環函數
function sb(){console.log(arguments.callee())}
sb();

尾遞歸

function factorial(n, total) {
 if (n === 1) return total;
 return factorial(n - 1, n * total); 
}
 factorial(5, 1) // 120

//避免函數賦值而報錯
function fact(num){ 
    if (num<=1){ 
        return 1; 
    }else{ 
        return num*arguments.callee(num-1); //此處更改了。 
    } 
} 
var anotherFact = fact; 
fact = null; 
alert(anotherFact(4)); //結果爲24. 

less簡單記錄

變量
@color: #999;
@mySelector: #wrap;
@borderStyle: border-style;
@Soild:solid;
@images: "../img";//需要加引號
@{mySelector}{ //變量名 必須使用大括號包裹
  color: @color;
  @{borderStyle}: @Soild;//變量名 必須使用大括號包裹
  background: url("@{images}/dog.png");//變量名 必須使用大括號包裹
}
變量作用域
一句話理解就是:就近原則


運算
加減法時 以第一個數據的單位爲基準
乘除法時 注意單位一定要統一


媒體查詢
#main{
    //something...
    @media screen{
        @media (max-width:768px){
          width:100px;
        }
    }
    @media tv {
      width:2000px;
    }
}


混合(加不加括號區別在於加括號在代碼裏面會隱藏)
#card(){
    background: #723232;
    .d(@w:300px){
        width: @w;   
    }
}
#wrap{
    #card > .d(); // 父元素不能加 括號
}



判斷 and=>&   ,=>|  not=>!
 .border(@width,@color,@style) when (@width>100px) and(@color=#999){
        border:@style @color @width;
    }
 .background(@color) when not (@color>=#222){
        background:@color;
    }
 .font(@size:180px) when (@size>50px) , (@size<100px){
        font-size: @size;
    }

div{
    .border(99px,#999,solid);
    .background(#000);
    .font();
}
/*css*/
div {
  background: #000;
  font-size: 180px;
}


導入
import "main"; 


reference
Less 中 最強大的特性 使用 引入的 Less 文件,但不會 編譯它。
@import (reference) "bootstrap.less"; 
#wrap:extend(.navbar all){}


避免編譯
/* Less */
#main{
  width:~'calc(300px-30px)';
}
/* 生成後的 CSS */
#main{
  width:calc(300px-30px);
}


複製代碼結構: ~"字符@{變量}字符";
變量拼串
在平時工作中,這種需求 太常見了。 transtion-delay、animation、@keyframes
@size:15px;
@i:1;
  .loopAnimation(@i) when (@i<16) { 
    .circle:nth-child(@{i}){
        border-radius:@size @size 0 0;
        transition-delay:~"@{i}ms";
    }
  }
  .loopAnimation(@i + 10);
/*css*/
.circle:nth-child(11) {
  border-radius: 15px 15px 0 0;
  transition-delay: 11ms;
}



因爲 Less 是由 JS 編寫,所以 Less 有一得天獨厚的特性:代碼中使用 Javascript 。
/* Less */
#wrap{
  width: ~"`Math.round(Math.random() * 100)`px";
//  height: ~"`window.innerHeight`px";
}
/* 生成後的 CSS */
#wrap{
  width: 隨機值(0~100)px;
}
//很雞肋 如果用less編譯完的css那將不是動態的 如果用直接less就編譯錯誤
//不過less還是css window.innerHeight都報錯了 無語 資料太少了

extend 關鍵字的使用
/* Less */
.animation{
    transition: all .3s ease-out;
}
#main{
    &:extend(.animation);
}
/* 生成後的 CSS */
.animation,#main{
  transition: all .3s ease-out;
}



less版本適配

 //定義一個變量和一個mixin
 @baseFontSize: 100;//基於視覺稿橫屏尺寸/100得出的基準font-size
 .px2rem(@name, @px){
     @{name}: @px / @baseFontSize * 1rem;
 }
 .container {
     .px2rem(height, 240);
      background-color: #888;
      .px2rem( font-size, 18);
 }



隨機數十以內

Math.floor(Math.random()*10);

js 通過value找到key

function findKey (obj,value, compare = (a, b) => a === b) {
  return Object.keys(obj).find(k => compare(obj[k], value))
//  if(compare(obj[k], value)){return k} 箭頭函數簡寫
}

var  people = {
       'name':'zhang',
        "age":19
}
findKey(people,'zhang'); //返回結果爲:name
findKey(people,19); //返回結果爲:age

閉包

當一個內部函數被其外部函數之外的變量引用時,就形成了一個閉包。
能夠訪問另一個函數作用域的變量的函數
function A(){
    function B(){
       console.log('Hello Closure!');
    }
    return B;
}
var C = A();
C();// Hello Closure!

排序

/*compare函數*/
  function compare(value1, value2){
    return value2 - value1;
  }
            
        var values = [0, 1, 10, 15, 5];
        values.sort(compare);  
        console.log(values);  //0, 1, 5, 10, 15

js 防抖和節流

函數節流: 頻繁觸發,但只在特定的時間內才執行一次代碼  多次 比如搜索框
//每300 ms 執行一次  
函數防抖: 頻繁觸發,但只在特定的時間內沒有觸發執行條件才執行一次代碼  一次  比如驗證框
//300ms之內重複進去的話不執行 最後一次300ms後才執行

// 函數節流 300ms執行一次   
var canRun = true;
document.getElementById("throttle").onscroll = function(){
    if(!canRun){
        // 判斷是否已空閒,如果在執行中,則直接return
        return;
    }
    canRun = false;
    setTimeout(function(){
        console.log("函數節流");
        canRun = true;
    }, 300);
};
// 函數節流的要點是,聲明一個變量當標誌位,記錄當前代碼是否在執行。
// 如果空閒,則可以正常觸發方法執行。
// 如果代碼正在執行,則取消這次方法執行,直接return。


// 函數防抖 執行最後一次 300ms觸發
var timer = false;
document.getElementById("debounce").onscroll = function(){
    clearTimeout(timer); // 清除未執行的代碼,重置回初始化狀態

    timer = setTimeout(function(){
        console.log("函數防抖");
    }, 300);
};
// 函數節流的要點,也是需要一個setTimeout來輔助實現。延遲執行需要跑的代碼。
// 如果方法多次觸發,則把上次記錄的延遲執行代碼用clearTimeout清掉,重新開始。
// 如果計時完畢,沒有方法進來訪問觸發,則執行代碼。

SSL、ws、wss、http、htts

SSL 是基礎, 在 SSL 上運行 WebSocket 協議就是 WSS; 在 SSL 上運行 HTTP 協議就是 HTTPS.

ws和wss是在http和相應的https上的進一步改進升級版本.wss首先還是https協議, 只是增加了和websocket相應的頭和二進封包等處理.簡單地說就是WS on HTTP, WSS on HTTPS

另一個問題是在http頁面裏能不能打開wss連接.可以, 但不夠安全.
在https能打開ws連接麼? 答案是不能, 因爲瀏覽器不允許.( 但也不是所有瀏覽器都不允許, 象國內的qq等瀏覽器就是允許的. 當然, 也就不安全了.)

HTTP協議傳輸的數據都是未加密的,也就是明文的;
HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全。
採用HTTPS加密的網站在搜索結果中的排名將會更高
HTTPS協議握手階段比較費時,對網站的相應速度有負面影響,如非必要,沒有理由犧牲用戶體驗。
總結
https協議需要到ca申請證書,一般免費證書較少,因而需要一定費用。
http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協議。
http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,後者是443。
http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

簡單講一下wss使用

const ws = new WebSocket('wss://api.test.com/wss');
let frist = 0 ;//緩存

//監聽連接開啓事件  開啓後纔可以發送給服務端
ws.onopen = function () {
  console.log('@open');

  ws.send('Hello Server!');
//發送給服務端 服務端發送給客戶端 客戶端通過onmessage接受
//一般應該不會是 ws.send發送數據 因爲數據不僅僅是個文本 服務端會給接口代替

};
let that = this
//監聽連接消息事件
ws.onmessage = function (e) {
  console.log('@message');

//首次接受消息的時候綁定處理
//判斷是不是第一次登錄 看實際需求
//that.bind()

//這裏看你服務端給返回的數據格式 
  console.log(e)
  that.clientId = JSON.parse(e.data).data
//一般在接受消息後觸發全局事件 
  that.$emit("appEmitMessage","e")
  console.error(JSON.parse(e.data).data)
};
//監聽連接關閉事件
ws.onclose = function (e) {
  console.log('@close');
};
//監聽連接錯誤事件
ws.onerror = function () {
  console.log('@error');
  //   ws.close();
};
一般流程思路:
我這邊是通過用戶登錄後獲取token以及首次連接服務器即new WebSocket的時候會給客戶端發送消息即onmessage事件中接收帶有唯一標識的信息,在通過唯一標識和token發送請求給服務器綁定即可建立通信連接
一般通信必須放在全局的地方 因爲如果爲進去通信或者未觸發WebSocket的話是沒辦法監聽消息事件的
如果使用的框架是vue的話那就是在main.js中引入

原生js 

事件傳播——冒泡與捕獲和 事件——阻止冒泡捕獲

默認情況下,事件使用冒泡事件流,不使用捕獲事件流。
dom.addEventListener('click', function() {
            console.log('click');
        }, false);
//false爲冒泡獲取【目標元素先觸發】   true爲捕獲獲取【父級元素先觸發】
防止冒泡和捕獲
w3c的方法是e.stopPropagation(),IE則是使用e.cancelBubble = true
//比如點擊裏層div不會觸發外層父級div的點擊事件

取消默認事件

w3c的方法是e.preventDefault(),IE則是使用e.returnValue = false;
//如果元素本身就沒有默認行爲,調用當然就無效了 只有如鏈接<a> 提交按鈕<input type=”submit”>等。
return false
javascript的return false只會阻止默認行爲,而是用jQuery的話則既阻止默認行爲又防止對象冒泡。

js事件執行類型

js中的事件執行主要分爲兩個任務類型 macro task以及micro task 也就是宏仁務和微任務
宏仁務:script(全局任務),setTimeout ,setInterval ,setImmediate ,I/O ,UI rendering
微任務:process.nextTick,promise,Object.observer,MutationObserver
執行順序爲 script先進入函數調用棧,然後執行遇到任何其他宏仁務,比如遇到了setTimeout,就把setTimeout放進宏仁務隊列中,遇到了微任務就放入微任務隊列中,等到函數調用棧的所有內容出棧後 然後執行微任務隊列,然後再回頭執行宏仁務隊列再進入函數調用棧再執行微任務隊列,知道宏仁務隊列執行完畢
例子:
//遇到setTimeout,放入宏仁務隊列
setTimeout(function () {
  console.log(1);
}, 0);
//遇到promise,放入微任務隊列   resolve只會在then()裏面輸出
Promise.resolve(function () {
  console.log(2);
})
//這裏雖然遇到了promise,但是是用new聲明的,也就是立即執行,所以會先輸出3
new Promise(function (resolve) {
  console.log(3);
});
//第二輸出4
console.log(4);
//需要注意的是那個undefined並不是微任務輸出的,而是console.log(4)輸出的,具體可以控制檯測試
//然後執行微任務,這個微任務並沒有調用,所以也不會執行,然後執行宏仁務隊列中的setTimeout,輸出1
//控制檯==》   3  4 undefined 1    
//實際是 3 4 1
//undefined只是console.log(4)沒有返回值返回的undfined

事件委託

事件委託
利用冒泡原理,把時間加到父級上,觸發執行效果
可以大量節省內存佔用,減少事件註冊
可以方便地動態添加和修改元素,不需要因爲元素的改動而修改時間綁定
var ul = document.querySelector('ul'); 
var list = document.querySelectorAll('ul li'); 

ul.addEventListener('click', function(ev){ 
    var ev = ev || window.event; 
    var target = ev.target || ev.srcElemnt; 

    for(var i = 0, len = list.length; i < len; i++){ 
        if(list[i] == target){ 
            alert(i + "----" + target.innerHTML); 
        } 
    } 
});

圖片懶加載

 當頁面滾動的時間被觸發->執行加載圖片操作->判斷圖片是否在可視區域內->在,則動態將data-src的值賦予該圖片

柯里化

假如一個函數只能接受一個參數,那麼這個函數怎麼實現;因爲高階函數是可以當做參數傳遞和返回值的;所以問題就簡化了:寫一個只有一個參數的函數;而這個函數返回一個帶參數的函數;這樣就實現了能寫連個參數的函數;這就是函數柯里化;(其實就是函數的封裝複用)

例如
function add(a,d){
return a+d;
};
function curry(a){
return function(d){
  return a+d;
 }
};
var add2=curry(2);
console.log(add2(3));//5
改成
const curry = (fn, ...arg) => {
    let all = arg;
    return (...rest) => {
        all.push(...rest);
        return fn.apply(null, all);
    }
}
let add2 = curry(add, 2)
console.log(add2(8));    //10
add2 = curry(add);
console.log(add2(2,8)); //10

this指向

var a = 123;//不能使用let 因爲let 是塊級作用域
var obj ={a:789}
function m(){
   console.log(this.a)
   return  this.a
}
m()
//VM9804:4 123
//123
m.call()
//VM9804:4 123
//123
m.call(this)
//VM9804:4 123
//123
m.call(obj)
//VM9804:4 789
//789
m()
//VM9804:4 123
//123
let aa =m.call(obj)
//VM9804:4 789
//undefined
aa
//789


 function add(a, b) {
        console.log(a + b);
    }

 add.call(this, 1, 2); //3
 add.apply(this, [1, 2]); //3


 var a = [2, 4, 5, 7, 8, 10];

console.log(Math.max.apply(null, a)); //10
console.log(Math.max.call(null,2, 4, 5, 7, 8, 10)); //10




說明
var add= {
        a: 1,
        count: function() {
            console.log(this.a++);
        }
    };

    add.count(); //1
如果賦值的話會報錯 因爲this指向了add 賦值的時候是指向了window
var add= {
        a: 1,
        count: function() {
            console.log(this.a++);
        }
    };

    var f = add.count;
    f(); //NaN

解決方案
 var f = add.count.bind(keith);
     f(); //1
     f(); //2
bind方法返回的仍然是一個函數,因此後面還需要()來進行調用纔可以 而call,apply不用


例如
dog.use.call(cat)//我是貓
dog.use.apply(cat)//我是貓
dog.use.bind(cat)()//我是貓

性能優化

請說出三種減低頁面加載時間的方法
壓縮css、js文件
減少http請求
減少dom操作,儘可能用變量替代不必要的dom操作
api請求接口緩存

 

es6方面

let和const 塊級作用域的區別:const的類型是不可變的 let可以

箭頭函數作用域:箭頭函數的this指向父級(本身箭頭函數沒有this作用域)
字符串新增
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
s.includes('Hello', 6) // false
'x'.repeat(3) // "xxx"
'x'.padStart(5, 'ab') // 'ababx'
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
Number.isInteger(25) // true
Number.isInteger(25.1) // false
0.1 + 0.2 === 0.3 // false  因爲浮點值
//2 的-50 次方(即Number.EPSILON * Math.pow(2, 2)),即如果兩個浮點數的差小於這個值,我們就認爲這兩個浮點數相等。
2 ** 3 ** 2  // 相當於 2 ** (3 ** 2)   // 512

[...new Set([1, 2, 3, 4, 4])]
[...new Set('ababbc')].join(',').split(",")

es6  async/await 來處理異步
async它作爲一個關鍵字放到函數前面,用於表示函數是一個異步函數,該函數的執行不會阻塞後面代碼的執行。
async function timeout() {
    return 'hello world'
}
timeout().then(result => {
    console.log(result);
}).catch(err => {
    console.log(err)
})
console.log('雖然在後面,但是我先執行');
//控制檯:  雖然在後面,但是我先執行
//         VM83:5 hello world
await它後面可以放任何表達式,更多的是放一個返回promise對象的表達式。await只能放到async 函數裏面
例子:
function doubleAfter2seconds(num) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(2 * num)
        }, 2000);
    } )
}
async function testResult() {
    let result = await doubleAfter2seconds(30);
    console.log(result);
    console.log('等待wait 函數執行完畢')
}
testResult()
//控制檯:60
//         VM118:3 等待wait 函數執行完畢


將數組扁平化並去除其中重複數據,最終得到一個升序且不重複的數組 
let arr =[1,2,5,4,[3,8,99,8]]
Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})
or
[...new Set(arr.toString().split(',').sort((a, b) => { return b - a }).map(Number))]
//控制檯:[1, 2, 3, 4, 5, 8, 99] 
//b-a是降序  小於0則 升序 大於0 則降序

 

js 數組對象

數組
array.some(function(item,index,array){
               return item>1; 
            })

只要有一個滿足的就返回true,沒有滿足的返回false

every:驗證數組中是否每個元素都滿足指定的條件
驗證全部的結果,當全部的值都爲 true 時,則最終會得到 true;只要其中之一爲 false,則返回 false。

let people = [ { name: '馬雲', money: 2000 }, { name: '馬化騰', money: 1800 }, { name: '我', money: Infinity } ];

var ans = people.every(function(item, index, array){
  return item.money > 1800;
});
console.log(ans); // false: 只要有部分不符合,則爲 false

var ans2 = people.every(function(item, index, array){
  return item.money > 500;
});
console.log(ans2); // true: 大家錢都超過 500


forEach 沒有返回值,可以不知道數組長度

arr.forEach(function(res,index){ })

const obj= { boss: 'xx', boss1: 'zz' };

 

map函數,返回值組成新數組,原數組不變;

var newarr=[1,2,3].map(function(res,index){

  return  res+1;

});

console.log(newarr)

//[2,3,4]

filter函數:過濾通過條件的元素組成一個新數組,原數組不變;

var newarr=[1,2,3].filter(function(res){

  return  res == 2

});

console.log(newarr)

//[2]


join(separator): 將數組的元素組起一個字符串,省略的話則用默認用逗號爲分隔符(separator爲分隔符)

var arr = [1,2,3];

console.log(arr.join()); // 1,2,3


shift:刪除原數組第一項,並返回刪除元素的值;如果數組爲空則返回undefined 

var a = [1,2,3,4,5];   

var b = a.shift(); //a:[2,3,4,5] b:1  
 

unshift:將參數添加到原數組開頭,並返回數組的長度 

var a = [1,2,3,4,5];   

var b = a.unshift(-2,-1); //a:[-2,-1,1,2,3,4,5] b:7   


pop:刪除原數組最後一項,並返回刪除元素的值;如果數組爲空則返回undefined 

var a = [1,2,3,4,5]; 

 var b = a.pop(); //a:[1,2,3,4] b:5  
 

push:將參數添加到原數組末尾,並返回數組的長度

var a = [1,2,3,4,5];   

var b = a.push(6,7); //a:[1,2,3,4,5,6,7] b:7 
 

concat:返回一個新數組,是將參數添加到原數組中構成的 

var a = [1,2,3,4,5];   

var b = a.concat(6,7);    //  a:[1,2,3,4,5] b:[1,2,3,4,5,6,7]  


splice(start,deleteCount,val1,val2,...):從start位置開始刪除deleteCount項,並從該位置起插入val1,val2,... 

 

var a = [1,2,3,4,5];   

var b = a.splice(2,2,7,8,9); //a:[1,2,7,8,9,5] b:[3,4]   

var b = a.splice(0,1); //同shift   

a.splice(0,0,-2,-1); var b = a.length; //同unshift   

var b = a.splice(a.length-1,1); //同pop   

a.splice(a.length,0,6,7); var b = a.length; //同push 

 

reverse:將數組反序 

 

var a = [1,2,3,4,5];   

var b = a.reverse(); //a:[5,4,3,2,1] b:[5,4,3,2,1]  



sort(orderfunction):按指定的參數對數組進行排序 

var a = [1,2,3,4,5];   

var b = a.sort(); //a:[1,2,3,4,5] b:[1,2,3,4,5]  



slice(start,end):返回從原數組中指定開始下標到結束下標之間的項組成的新數組 

 var a = [1,2,3,4,5];   

     var b = a.slice(2,5); //a:[1,2,3,4,5] b:[3,4,5]  

 

 

 

對象
Object.keys() 會創建一個包含對象鍵的數組。

Object.keys() 迭代對象的鍵和值。

 
Object.keys(obj).forEach(key => { let value = obj[key]; console.log(`${key}: ${value}`); });

Output
boss: zz
boss1: xx
const length = Object.keys(obj).length; // 4
 

Object.values() 創建一個包含對象值的數組。

const values = Object.values(obj);
["xx","zz"]
 

Object.entries() 創建對象的 鍵/值 對的嵌套數組。

const entries = Object.entries(obj);

// [ ["boss", "xx"] ["boss1", "zz"] ]

 

 

Object.assign() 用於把一個對象的值複製到另一個對象。 or  展開語法(...)

//前面的值會覆蓋後面的值

const character1= Object.assign(aa, bb);
const aa= { a: 'a', b: 'b' };

const bb= { b: 'bb', c: 'c' };

const character = {...aa, ...bb}

character1 == character2     //   {a:'a',b:'bb',c:'c'}

 

 

補充一個數組去重的方法
function dedupe(array) {
  return [...new Set(array)]
}
var arr = [1,2,2,3,3,4,4,5,5]

 

 js對象

prototype __proto__   constructor
所有的構造器包括Object和Function都繼承了Function.prototype的方法,所有的構造器都是對象,即js中一切皆爲對象。
prorotype的主要作用簡單來說就是“便於方法或者屬性的重用”,可以利用prototype添加擴展屬性和方法
每個函數都有一個默認的屬性prototype,而這個prototype的constructor默認指向這個函數
__proto__最終的指向都是Object.prototype,這也就是js中的原型鏈。
constructor屬性指向的是創建當前對象的構造函數 即本身。
某個對象的constructor屬性返回該對象構造函數,其__proto__屬性是個對象,值和其構造函數的prototype屬性值一致。

 

淺談session,cookie,sessionStorage,localStorage的區別及應用場景 

區別:
保持狀態:cookie保存在瀏覽器端,session保存在服務器端
Cookie通過在客戶端記錄信息確定用戶身份,Session通過在服務器端記錄信息確定用戶身份。
//axios允許攜帶cookie axios.defaults.withCredentials=true
使用方式:
(1)cookie機制:如果不在瀏覽器中設置過期時間,cookie被保存在內存中,生命週期隨瀏覽器的關閉而結束,這種cookie簡稱會話cookie。如果在瀏覽器中設置了cookie的過期時間,cookie被保存在硬盤中,關閉瀏覽器後,cookie數據仍然存在,直到過期時間結束才消失。
Cookie是服務器發給客戶端的特殊信息,cookie是以文本的方式保存在客戶端,每次請求時都帶上它
(2)session機制:當服務器收到請求需要創建session對象時,首先會檢查客戶端請求中是否包含sessionid。如果有sessionid,服務器將根據該id返回對應session對象。如果客戶端請求中沒有sessionid,服務器會創建新的session對象,並把sessionid在本次響應中返回給客戶端。通常使用cookie方式存儲sessionid到客戶端,在交互中瀏覽器按照規則將sessionid發送給服務器。如果用戶禁用cookie,則要使用URL重寫,可以通過response.encodeURL(url) 進行實現;API對encodeURL的結束爲,當瀏覽器支持Cookie時,url不做任何處理;當瀏覽器不支持Cookie的時候,將會重寫URL將SessionID拼接到訪問地址後。
3、存儲內容:cookie只能保存字符串類型,以文本的方式;session通過類似與Hashtable的數據結構來保存,能支持任何類型的對象(session中可含有多個對象)
4、存儲的大小:cookie:單個cookie保存的數據不能超過4kb;session大小沒有限制。
5、安全性:cookie:針對cookie所存在的攻擊:Cookie欺騙,Cookie截獲;session的安全性大於cookie。
原因如下:(1)sessionID存儲在cookie中,若要攻破session首先要攻破cookie;
          (2)sessionID是要有人登錄,或者啓動session_start纔會有,所以攻破cookie也不一定能得到sessionID;

      (3)第二次啓動session_start後,前一次的sessionID就是失效了,session過期後,sessionID也隨之失效。
           (4)sessionID是加密的
           (5)綜上所述,攻擊者必須在短時間內攻破加密的sessionID,這很難。

6、應用場景:

cookie:(1)判斷用戶是否登陸過網站,以便下次登錄時能夠實現自動登錄(或者記住密碼)。如果我們刪除cookie,則每次登錄必須從新填寫登錄的相關信息。

    (2)保存上次登錄的時間等信息。

    (3)保存上次查看的頁面

    (4)瀏覽計數



session:Session用於保存每個用戶的專用信息,變量的值保存在服務器端,通過SessionID來區分不同的客戶。
  (1)網上商城中的購物車
  (2)保存用戶登錄信息
  (3)將某些數據放入session中,供同一用戶的不同頁面使用
  (4)防止用戶非法登錄
 7、缺點:cookie:(1)大小受限
        (2)用戶可以操作(禁用)cookie,使功能受限
        (3)安全性較低
        (4)有些狀態不可能保存在客戶端。
        (5)每次訪問都要傳送cookie給服務器,浪費帶寬。
        (6)cookie數據有路徑(path)的概念,可以限制cookie只屬於某個路徑下。
     session:(1)Session保存的東西越多,就越佔用服務器內存,對於用戶在線人數較多的網站,服務器的內存壓力會比較大。
        (2)依賴於cookie(sessionID保存在cookie),如果禁用cookie,則要使用URL重寫,不安全
        (3)創建Session變量有很大的隨意性,可隨時調用,不需要開發者做精確地處理,所以,過度使用session變量將會導致代碼不可讀而且不好維護。

Session是在服務器端保存用戶數據。瀏覽器第一次發送請求時,服務器自動生成了Session ID來唯一標識這個並將其通過響應發送到瀏覽器。瀏覽器第二次發送請求會將前一次服務器響應中的Session ID放在請求中一併發送到服務器上,服務器從請求中提取出Session ID,並和保存的所有Session ID進行對比,找到這個用戶的信息。一般這個Session ID會有個時間限制,默認30分鐘超時後毀掉這次Session ID。

 Session和Cookie有一定關係,Session id存在Cookie中,每次訪問的時候將Session id傳到服務器進行對比。
Cookie 在客戶端(瀏覽器、易僞造、不安全),Session 在服務器端(會消耗服務器資源)。
Cookie 只能保存ASCII字符串,如果是Unicode字符或者二進制數據需要先進行編碼。Cookie中也不能直接存取Java對象。 Session能夠存取很多類型的數據,包括String、Integer、List、Map等,Session中也可以保存JJava對象。

domain表示的是cookie所在的域,默認爲請求的地址,如網址爲www.study.com/study,那麼domain默認爲www.study.com。而跨域訪問,如域A爲t1.study.com,域B爲t2.study.com,那麼在域A生產一個令域A和域B都能訪問的cookie就要將該cookie的domain設置爲.study.com;如果要在域A生產一個令域A不能訪問而域B能訪問的cookie就要將該cookie的domain設置爲t2.study.com。注意:一般在域名前是需要加一個"."的,如"domain=.study.com"。




二、WebStorage

WebStorage的目的是克服由cookie所帶來的一些限制,當數據需要被嚴格控制在客戶端時,不需要持續的將數據發回服務器。

WebStorage兩個主要目標:(1)提供一種在cookie之外存儲會話數據的路徑。(2)提供一種存儲大量可以跨會話存在的數據的機制。

HTML5的WebStorage提供了兩種API:localStorage(本地存儲)和sessionStorage(會話存儲)。

1、生命週期:localStorage:localStorage的生命週期是永久的,關閉頁面或瀏覽器之後localStorage中的數據也不會消失。localStorage除非主動刪除數據,否則數據永遠不會消失。

sessionStorage的生命週期是在僅在當前會話下有效。sessionStorage引入了一個“瀏覽器窗口”的概念,sessionStorage是在同源的窗口中始終存在的數據。只要這個瀏覽器窗口沒有關閉,即使刷新頁面或者進入同源另一個頁面,數據依然存在。但是sessionStorage在關閉了瀏覽器窗口後就會被銷燬。同時獨立的打開同一個窗口同一個頁面,sessionStorage也是不一樣的。

2、存儲大小:localStorage和sessionStorage的存儲數據大小一般都是:5MB

3、存儲位置:localStorage和sessionStorage都保存在客戶端,不與服務器進行交互通信。

4、存儲內容類型:localStorage和sessionStorage只能存儲字符串類型,對於複雜的對象可以使用ECMAScript提供的JSON對象的stringify和parse來處理

5、獲取方式:localStorage:window.localStorage;;sessionStorage:window.sessionStorage;。

6、應用場景:localStoragese:常用於長期登錄(+判斷用戶是否已登錄),適合長期保存在本地的數據。sessionStorage:敏感賬號一次性登錄;

WebStorage的優點:

(1)存儲空間更大:cookie爲4KB,而WebStorage是5MB;

(2)節省網絡流量:WebStorage不會傳送到服務器,存儲在本地的數據可以直接獲取,也不會像cookie一樣美詞請求都會傳送到服務器,所以減少了客戶端和服務器端的交互,節省了網絡流量;

(3)對於那種只需要在用戶瀏覽一組頁面期間保存而關閉瀏覽器後就可以丟棄的數據,sessionStorage會非常方便;

(4)快速顯示:有的數據存儲在WebStorage上,再加上瀏覽器本身的緩存。獲取數據時可以從本地獲取會比從服務器端獲取快得多,所以速度更快;

(5)安全性:WebStorage不會隨着HTTP header發送到服務器端,所以安全性相對於cookie來說比較高一些,不會擔心截獲,但是仍然存在僞造問題;

(6)WebStorage提供了一些方法,數據操作比cookie方便;

   setItem (key, value) ——  保存數據,以鍵值對的方式儲存信息。

      getItem (key) ——  獲取數據,將鍵值傳入,即可獲取到對應的value值。

      removeItem (key) ——  刪除單個數據,根據鍵值移除對應的信息。

      clear () ——  刪除所有的數據

      key (index) —— 獲取某個索引的key


 

ajax

ajax後退解決方案
1、直接的方法,點擊某一項數據的時候跳轉的是新頁面
2.1、點擊頁碼,異步請求數據,同時改變地址欄的值
2.2、頁面刷新,取到地址欄的值,加載對應頁碼的數據。
/*
    * 替換當前url 並不導致瀏覽器頁面刷新
    * name 參數名
    * value 參數值
    */
     function replaceUrl  (name, value) {        
        var obj = new Object();
        obj[name] = value;
        obj.rand = Math.random();
        History.replaceState(obj, '', '?' + name + '=' + value);
    }

css

0.5px的線條
.setOnePx{
    position: relative;
  }
  .setOnePx::after{
      position: absolute;
      content: '';
      background-color: #e5e5e5;
      display: block;
      width: 100%;
      height: 1px; /*no*/
      transform: scale(1, 0.5);
      top: 0;
      left: 0;
    }

1px的線條 
.setBorderAll{
       position: relative;
      }
      .setBorderAll::after{
             content:" ";
             position:absolute;
             top: 0;
             left: 0;
             width: 200%;
             height: 200%;
             transform: scale(0.5);
             transform-origin: left top;
             box-sizing: border-box;
             border: 1px solid #E5E5E5;
             border-radius: 4px;
        }

單行省略號
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;

多行省略號
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;

清除浮動
   .div::after{
    content:"";
    display:block;
    height:0;
    clear:both;
    visibility:hidden;
   }
or
.div{
  overflow: hidden;
}
or
浮動後面添加
<div style="clear:both"></div>
or
給浮動元素父級設置高度

相對水平垂直居中
border: 1px solid red;
/*水平*/
margin: 0 auto; 
/*垂直*/
height: 50px;
line-height:50px;
width: 80px;

絕對定位水平居中
    width:100px;
    position:absolute;
    left:50%;
    margin-left:-50px; (此處margin-left的值寫該圖片寬度的一半)
1、使用絕對定位,設置left值將圖片移到正中間,此時圖片的左邊框在屏幕的中線位置
2、設置margin-left,注意值爲負數,咱們把圖片向左移圖片寬度一半的位置

浮動元素的上下左右居中:
border: 1px solid red;
float: left;
position: absolute;
width: 200px;
height: 100px;
left: 50%;
top: 50%;
margin: -50px 0 0 -100px; 

CSS的盒子模型
標準盒子模型:寬度=內容的寬度(content)+ border + padding + margin
box-sizing:content-box
低版本IE盒子模型:寬度=內容寬度(content+border+padding)+ margin
box-sizing:border-box

CSS權重
!important>內聯選擇器>id>class>tag>*
a b{}選擇器大於b{}選擇器

繼承
可繼承的屬性:font-size, font-family, color
不可繼承的樣式:border, padding, margin, width, height

CSS僞類及僞元素
僞類用於向某些選擇器添加特殊的效果。
:link, :visited, :hover, :focus, :active, :first-child, :lang
css3新增的僞類:
:last-child, :first-of-type, :last-of-type, :nth-child(n), :nth-last-child(n), :nth-of-type(n), :nth-last-of-type(n), :root, :empty, :target, :enabled, :disabled, :checked, :not(selector)
僞元素用於向某些選擇器設置特殊效果。
::first-letter, ::first-line, ::before, ::after
css3新增的僞元素
::selection
根本區別在於:它們是否創造了新的元素(抽象)

三角形
元素的寬度、高度設爲0。然後設置邊框樣式
width: 0;
height: 0;
border-top: 40px solid transparent;
border-left: 40px solid transparent;
border-right: 40px solid transparent;
border-bottom: 40px solid #ff0000;

描述css reset的作用和用途?
Reset重置瀏覽器的css默認屬性,瀏覽器的品種不同,樣式不同,然後重置,讓他們統一。

絕對定位和相對定位區別
1、參照物不同 絕對定位的參照物是包含塊(父級)相對定位的參照物是元素自己本身默認位置
2、絕對定位將對象從文檔流中脫離出來因此不佔據空間相對位置不破壞正常的文檔流順序,無論是否進行移動元素仍佔據空間

透明度
opacity:0.6;
filter:alpha(opacity=60); /* IE8 及更早版本 */

margin重疊解決
兄弟間重疊時
底部元素變爲行內盒子(display: inline-block);
父元素與子元素重疊
父元素加入(overflow: hidden);
父元素添加透明邊框(border:1px solid transparent);
子元素變爲行內盒子(display: inline-block);

css BFC
根據W3C的標準,在頁面中元素都一個隱含的屬性叫做Block Formatting Context(塊級 格式化 環境)簡稱BFC
開啓元素的BFC後,元素會有如下特性:
1.父元素的垂直外邊距不會和子元素重疊。
2.開啓BFC的元素不會被浮動的元素所覆蓋。
3.開啓BFC的元素可以包含浮動的子元素。
開啓
1.設置元素浮動(此方法,雖然可以撐開父元素,但是會導致父元素的寬度丟失,也會導致下邊的元素上移)
2.設置元素絕對定位
3.設置元素display:inline-block;(此方法雖然也可以解決問題,但是轉爲行內塊也會導致寬度丟失,因此也不推薦此方法)
4.將元素的父元素的overflow設置爲一個非visible的值(推薦方式:overflow:hidden;是副作用最小的開啓BFC方式)
注:ie6不支持BFC,如果要同時兼容ie6  可以加一個屬性 zoom:1;即可(zoom表示放大,寫幾就是放大幾倍,此屬性僅支持IE,且IE8以下)

display:inline-block;引起的間距
原因:排版問題吧個人認爲
解決:
1、inline-block 即內聯塊,可以水平排版 即標籤水平排版
2、使用margin-left:-3px;(谷歌是-3px,ie好像是-1px)
3、使用font-size:0px;(最外層是容器)


html

Doctype作用? 嚴格模式與混雜模式如何區分?它們有何意義?
聲明位於文檔中的最前面,處於 標籤之前。告知瀏覽器以何種模式來渲染文檔。
嚴格模式的排版和 JS 運作模式是,以該瀏覽器支持的最高標準運行。
在混雜模式中,頁面以寬鬆的向後兼容的方式顯示。模擬老式瀏覽器的行爲以防止站點無法工作。
DOCTYPE不存在或格式不正確會導致文檔以混雜模式呈現。

meta響應式設計
<meta name="’viewport’" content="”width=device-width," initial-scale="1." maximum-scale="1,user-scalable=no”"/>

html5新增的標籤
section:定義文檔中的一個章節
nav:定義只包含導航鏈接的章節
header:定義頁面或章節的頭部。它經常包含 logo、頁面標題和導航性的目錄。
footer:定義頁面或章節的尾部。它經常包含版權信息、法律信息鏈接和反饋建議用的地址。

新特性
a. HTML5 現在已經不是 SGML 的子集,主要是關於圖像,位置,存儲,多任務等功能的增加。
b. 語義化更好的內容標籤(header,nav,footer,aside,article,section)
c. 新的技術webworker, websocket等
d. 音頻、視頻API(audio,video) 畫布(Canvas) API 地理(Geolocation) API 本地離線存儲 localStorage 長期存儲數據
e. sessionStorage 的數據在頁面會話結束時會被清除
f. 表單控件,calendar、date、time、email、url、search
移除的元素:
a. 純表現的元素:basefont,big,center, s,strike,tt,u;
b. 對可用性產生負面影響的元素:frame,frameset,noframes;

標籤語義化的理解
1、讓頁面呈現出清晰的結構
2、遵循語義化即一個標準 便於團隊開發和維護,語義化更具可讀性
3、有利於SEO 搜索引擎會識別標籤


瀏覽器是如何渲染頁面的?
渲染的流程如下:
1.解析HTML文件,創建DOM樹。
   自上而下,遇到任何樣式(link、style)與腳本(script)都會阻塞(外部樣式不阻塞後續外部腳本的加載)。
2.解析CSS。優先級:瀏覽器默認設置<用戶設置<外部樣式<內聯樣式<HTML中的style樣式;
3.將CSS與DOM合併,構建渲染樹(Render Tree)
4.佈局和繪製,重繪(repaint)和重排(reflow)

瀏覽器兼容問題

CSS透明
IE:filter:progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=60)。
FF:opacity:0.6。

IE6下無法設置1px的行高,原因是由其默認行高引起的       
解決辦法:爲期設置overflow:hidden;或者line-height:1px;

不同瀏覽器的標籤默認的外補丁和內補丁不同 即margin padding不一致
使用*{margin:0px;padding:0px;}

盒子模型不一致
ie是box-sizing: border-box;
google 是box-sizing: content-box;

js
1.標準的事件綁定方法函數爲addEventListener,但IE下是attachEvent;
2.事件的捕獲方式不一致,標準瀏覽器是由外至內,而IE是由內到外,但是最後的結果是將IE的標準定爲標準
3.window.event獲取的。並且獲取目標元素的方法也不同,標準瀏覽器是event.target,而IE下是event.srcElement
4.ajax的實現方式不同,這個我所理解的是獲取XMLHttpRequest的不同,IE下是activeXObject
5.IE中不能操作tr的innerHtml7.獲得DOM節點的父節點、子節點的方式不同
其他瀏覽器:parentNode  parentNode.childNodes       
IE:parentElement parentElement.children
6、說明:IE下,event對象有x,y屬性,但是沒有pageX,pageY屬性;
Firefox下,event對象有pageX,pageY屬性,但是沒有x,y屬性. 
解決方法:使用mX(mX  =   event.x   ?   event.x  :   event.pageX;)來代替IE下的event.x或者Firefox下的event.pageX.

自適應

media查詢
flex佈局
百分比佈局(% vw clac)
使用rem

正則

var str = "   23   23   ";
var str2 = str.replace(/\s*/g,"");
console.log(str2); // 2323

陸續更新....

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章