整理中高級前端系列,能夠看成面試複習,也能夠看成實戰來看,分享一下 方便本身,方便他人。有不足的地方歡迎評論~javascript
第一趴:css進階css
第二趴:js進階前端
第三趴:vue框架進階vue
第四趴:工程化java
當函數執行時,去建立一個稱爲「執行上下文(execution contex)」的環境,分爲 建立和執行 兩個階段node
是指 函數被調用但未被執行任何代碼時,此時建立了一個擁有3個屬性的對象:git
主要工做:一、分配變量、函數的飲用、賦值 二、執行代碼es6
js中有全局做用域、函數做用域,es6中又增長了 塊級做用域。 做用域最大的用途就是 隔離變量或函數,並控制他們的生命週期。 做用域是在函數執行上下文建立時定義好的,不是函數執行時定義的。github
當一個塊或函數嵌套在另外一個塊或函數中時,就發生了做用域的嵌套。若是在當前做用域沒法找到會向上一級做用域尋找,直到找到或抵達全局做用域,這樣的鏈式關係就是 做用域鏈(Scope Chain)web
能夠訪問其餘函數做用域中(內部)變量的函數
什麼節點循環綁定事件,解決方案 當即執行函數、var => let、
一、函數直接調用時
function myfunc() {
console.log(this) // this是widow
}
var a = 1;
myfunc();
// 常考點
function show () {
console.log('this:', this); // this是window
}
var obj = {
show: function() {
show(); // 函數被直接調用了
}
};
obj.show()
複製代碼
二、函數被別人調用時
function myfunc(){
console.log(this) // this是對象a
}
var a = { myfunc: myfunc }
a.myfunc();
複製代碼
三、new一個實例時(構造函數)
function Penson(name) {
this.name = name;
console.log(this); // this是實例p
}
var p = new Penson('this:::');
複製代碼
四、apply、call、bind
function getColor(color) {
this.color = color;
console.log(this);
}
function Car(name, color){
this.name = name; // this指的是實例car
getColor.call(this, color); // 這⾥的this從本來的getColor,變成了car
}
var car = new Car('卡⻋', '綠⾊');
複製代碼
五、箭頭函數時
// 箭頭函數
var a = {
myfunc: function() {
setTimeout(() => {
console.log(this); // this是a
}, 0)
}
};
a.myfunc();
複製代碼
一、對於直接調⽤的函數來講,無論函數被放在了什麼地⽅,this都是window 二、對於被別⼈調⽤的函數來講,被誰點出來的,this就是誰 三、在構造函數中,類中(函數體中)出現的 this.xxx = xxx 中的 this是當前類的⼀個實例 四、call、apply時,this是第⼀個參數。bind要優於call/apply哦,call參數多,apply參數少 五、箭頭函數沒有⾃⼰的this,須要看其外層是否有函數,若是有,外層函數的this就是內部箭頭函數 的this,若是沒有,則this是window
call()、apply()、bind() 都是用來重定義 this 這個對象的!
obj.myFun.call(db,'string1', ... ,'stringN' )
obj.myFun.apply(db,['成都',...,'string' ])
自己就是一個函數,爲了規範通常將首字母大寫,區別在於 使用 new 生成實例的函數就是構造函數,直接調用的就是 普通函數。
每一個對象都有其原型對象,對象從原型那繼承屬性和方法,這些屬性和方法定義在 對象的構造函數的 prototype 屬性上,而非對象實例自己。
簡單來說,淺拷貝 之解決了 第一層問題 基本類型值和引用類型地址
展開語法 Spread ...
let a = {
name: "ceshi",
book: {
title: "You Don't Know JS",
price: "45"
}
}
let b = {...a};
console.log(b);
// {
// name: "ceshi",
// book: {title: "You Don't Know JS", price: "45"}
// }
複製代碼
拷貝全部屬性以及指向得動態分配的內存。拷貝先後兩個 對象互不影響。
-- | 和原數據是否指向同一對象 | 第一層數據爲基本數據類型 | 原數據中包含子對象 |
---|---|---|---|
賦值 | 是 | 改變會使原數據一同改變 | 改變會使原數據一同改變 |
淺拷貝 | 否 | 改變不會使原數據一同改變 | 改變會使原數據一同改變 |
深拷貝 | 否 | 改變不會使原數據一同改變 | 改變不會使原數據一同改變 |
思路:淺拷貝 + 遞歸,淺拷貝時 判斷屬性值是不是對象,是對象就進行遞歸操做。
export function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone')
}
const targetObj = source.constructor === Array ? [] : {}
Object.keys(source).forEach(keys => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}
複製代碼
某個函數在一段時間內不管被觸發了多少次,都只執行最後一次。(會延長觸發時間)
實現原理是利用定時器,函數第一次執行時設置一個定時器,調用時 發現已有定時器那麼清空以前定時器重新設置一個新的定時器,直到最後一個定時器到時觸發函數執行。
function debounce(fn, awit = 50) {
let timer = null
return function(...args) {
// 存在定時器則清空
if (timer) clearTimeout(timer)
// 第一次設置定時器
timer = setTimeout(() => {
fn.apply(this, args)
}, awit);
}
}
const ceshiFnDeb = debounce(()=> console.log('ceshiFnDeb防抖函數執行了'), 1000)
document.addEventListener('scroll', ceshiFnDeb)
複製代碼
函數節流指的是 某個函數在 指定時間內(n秒)只執行一次,無論後面函數如何調用請求,不會延長時間間隔,n秒間隔結束後 第一次遇到 新的函數調用會觸發執行,以此類推。
// 節流 throttle: 固定間隔時間內只調用一次函數
// 思路1:根據兩個時間戳來對比
function throttle (fn, awit = 50) {
let startTime = 0
return function(...args){
let nowTime = +new Date()
// 當前時間和上次時間作對比,大於間隔時間的話,就能夠執行函數fn
if (nowTime - startTime > awit) {
// 執行完函數以後重置初始時間,等於最後一次觸發的時間
startTime = nowTime
fn.apply(this, args)
}
}
}
// 執行 throttle 函數返回新函數
const ceshiFn = throttle(()=> console.log('ceshiFn節流函數執行了'), 2000)
// 每 10 毫秒執行一次 betterFn 函數,可是隻有時間差大於 1000 時纔會執行 fn
setInterval(ceshiFn, 10);
複製代碼
不過市面上比較全的仍是 lodash的防抖節流函數 **
script所有代碼、setTimeOut、setInterval、I/O、
Promise、Process.nextTick(Node獨有)
這裏概括3個重點
自己是一個構造函數,自身有 all、reject、resolve方法,原型上有 then、catch方法
promise的then能夠接受兩個函數,第一個resolve,第二個參數爲reject
函數返回一個 Promise對象,若是內部發生異常則會致使返回的 Promise 對象狀態變爲reject
狀態。拋出的錯誤會被catch
方法接收到。
async
函數內部 return 返回的值。會成爲then
方法回調函數的參數。
正常狀況下,await 命令後面跟着的是Promise對象,返回對象的結果,若是不是的話,就直接返回對應的值。
Object.defineProperty()
Vue 2.x 利用 Object.defineProperty(),而且把內部解耦爲 Observer, Dep, 並使用 Watcher 相連
Proxy
Vue 在 3.x 版本以後改用 Proxy 進行實現
爲了解決兩大痛點: 一、每一個模塊都要有本身的 變量做用域,兩個模塊之間的內部變量不會產生衝突。 二、不一樣模塊之間保留相互 導入和導出的方式方法,模塊之間可以相互通訊,模塊的執行與加載遵循必定的規範,能保證彼此之間的依賴關係。
模塊化開發的4個好處:
是服務器端模塊的規範,Node.js採用了這個規範。
每一個JS文件就是一個模塊(module),每一個模塊內部使用 require
函數和 module.exports
對象來對模塊進行導入和導出
適合web開發的模塊化規範
模塊文件中,咱們使用 define 函數定義一個模塊,在回調函數中接受定義組件內容。這個回調函數接受一個 require 方法,可以在組件內部加載其餘模塊,這裏咱們分別傳入 模塊ID,就能加載對應文件內的AMD模塊。
// moduleA.js
define(function(require) {
var m = require('moduleB');
setTimeout(() => console.log(m), 1000);
});
// moduleB.js
define(function(require) {
var m = new Date().getTime();
return m;
});
// index.js
require(['moduleA', 'moduleB'], function(moduleA, moduleB) {
console.log(moduleB);
});
複製代碼
同時被 CommonJs規範和AMD規範加載的UMD模塊,一套同時適用於node.js和web環境
UMD先判斷是否支持Node.js的模塊(exports)是否存在,存在則使用Node.js模塊模式。 在判斷是否支持AMD(define是否存在),存在則使用AMD方式加載模塊。
ES6 爲導入(importing)導出(exporting)模塊帶來了不少可能性
與前二者的最大區別在於,ESModule是由JS解釋器實現,然後二者是 在宿主環境中運行時實現。ESModule導入實際上實在語法層面新增了一個語句,而AMD和ComminJs加載模塊其實是調用了 require函數。
正則表達式能夠從一個基礎字符串中根據必定的匹配模式替換文本中的字符串、驗證表單、提取字符串等等。
最全正則表達式連接
正則表達式主要依賴於元字符。 元字符不表明他們自己的字面意思,他們都有特殊的含義。一些元字符寫在方括號中的時候有一些特殊的意思。如下是一些元字符的介紹:
元字符 | 描述 |
---|---|
. | 句號匹配任意單個字符除了換行符。 |
[ ] | 字符種類。匹配方括號內的任意字符。 |
[^ ] | 否認的字符種類。匹配除了方括號裏的任意字符 |
* | 匹配>=0個重複的在*號以前的字符。 |
+ | 匹配>=1個重複的+號前的字符。 |
? | 標記?以前的字符爲可選. |
{n,m} | 匹配num個大括號之間的字符 (n <= num <= m). |
(xyz) | 字符集,匹配與 xyz 徹底相等的字符串. |
| | 或運算符,匹配符號前或後的字符. |
\ | 轉義字符,用於匹配一些保留的字符 [ ] ( ) { } . * + ? ^ $ \ | |
^ | 從開始行開始匹配. |
$ | 從末端開始匹配. |
同窗以爲有幫助的能夠點個贊,以示鼓勵~ 😊