[深刻01] 執行上下文
[深刻02] 原型鏈
[深刻03] 繼承
[深刻04] 事件循環
[深刻05] 柯里化 偏函數 函數記憶
[深刻06] 隱式轉換 和 運算符
[深刻07] 瀏覽器緩存機制(http緩存機制)
[深刻08] 前端安全
[深刻09] 深淺拷貝
[深刻10] Debounce Throttle
[深刻11] 前端路由
[深刻12] 前端模塊化
[深刻13] 觀察者模式 發佈訂閱模式 雙向數據綁定
[深刻14] canvas
[深刻15] webSocket
[深刻16] webpack
[深刻17] http 和 https
[深刻18] CSS-interview
[react] Hooksjavascript
[部署01] Nginx
[部署02] Docker 部署vue項目
[部署03] gitlab-CIcss
[源碼-webpack01-前置知識] AST抽象語法樹
[源碼-webpack02-前置知識] Tapable
[源碼-webpack03] 手寫webpack - compiler簡單編譯流程html
js中省略每行結尾的 ; 分號,須要注意的問題:
- () 小括號開頭的前一條語句,小括號前必須加分號,或者在前一條語句結束時加分號
- [] 中括號開頭的前一條語句,中括號前必須加分號,或者在前一條語句結束時加分號
例子:
(1) () 小括號開頭的前一條語句,小括號前要加 ';' 分號,或者前一條語句結尾加分號
var a = 1
(function() { // 報錯:Uncaught TypeError: 1 is not a function
console.log(a)
})()
解決方法:
var a = 1
;(function() { <---------
// 在()前加分號
// 或者在 var a = 1; 結尾加分號
console.log(a)
})()
(2) [] 中括號開頭的前一條語句,須要在[]前面加上 ';' 分號,或者前一條語句結尾加分號
var a = 1
[1,2,3].forEach(item => console.log(item)) // Uncaught TypeError: Cannot read property 'forEach' of undefined
解決方法:
var a = 1
;[1,2,3].forEach(item => console.log(item)) <---------
複製代碼
<script>
var a = 1
var c = 2
function x() {
var a = 10 // 全局中也有a,可是函數做用域聲明的a不會影響全局
var b = 100
c = 20 // 可是函數內部能修改全局的變量,(做用域鏈內部能修改外部的變量)
}
x()
console.log(a) // 1
console.log(c) // 20
;(function() { // 注意分號是必須的,由於()[]開頭的前一條語句末尾,或者()[]開頭加 ;
console.log(c) // 20
})()
console.log(b) // 報錯,b is not defined 函數外部不能訪問函數內部的變量
</script>
複製代碼
瀏覽器加載 javascript 腳本,主要經過script標籤
來完成前端
就是說:不等到html下載完成,就開始解析
外部腳本
,則下載腳本並執行
;若是沒有
就直接執行
script標籤內的代碼執行完畢
,控制權交還渲染引擎
,恢復解析html網頁
瀏覽器解析js文件流程
總結:
1. html是一邊下載,一邊解析的
2. script標籤會阻塞html解析,若是耗時較長,就會出現瀏覽器假死現象
3. script標籤之因此會阻止html解析,阻止渲染頁面,是由於js可能會修改DOM樹和CSSOM樹,形成複雜的線程競賽和控制權競爭的問題
複製代碼
defer:是延遲的意思vue
(1) script標籤放置在body底部java
(2) defer 屬性node
異步加載,不阻塞頁面,在DOM解析完成後才執行js文件
順序執行,不影響依賴關係
(3) async 屬性react
異步加載,加載不阻塞頁面,可是async會在異步加載完成後,當即執行,若是此時html未加載完,就會阻塞頁面
注意:異步加載,加載不會阻塞頁面,執行會阻塞頁面
不能保證各js文件的執行順序
defer (1)加載:是異步加載,加載不阻塞頁面;(2)執行:要DOM渲染完才執行,能保證各js的執行順序 |
async (1)加載:是異步加載,加載不阻塞頁面;(2)執行:加載完當即執行,不能保證各js的執行順序 |
defer,async,放在body底部,三種方法哪一種好?jquery
<script>
寫在<body>
底部,沒有兼容性問題,沒有白屏問題,沒有執行順序問題tree [<Drive>:][<Path>] [/f] [/a]
webpack
tree命令生成目錄結構
tree [<Drive>:][<Path>] [/f] [/a]
/f:顯示每一個目錄中文件的名稱
/a:使用文本字符而不是圖形字符鏈接
例子:
C:.
│ index.html
│
├─a
│ └─b
│ ccc.js
│
└─requirejs
a.js
b.js
c.js
複製代碼
IIFE Immediately-invoked Function Expressions 當即調用的函數表達式
(function(){...})()
,(function(){...}())
報錯:function(){}();
(1) IIFE如何傳參
(2) 多個IIFE一塊兒時,分號不能省略
(3) IIFE不會污染全局變量,由於不用爲函數命名
(4) IIFE能夠造成一個單獨的做用域名,則能夠封裝一些外部沒法讀取的變量
(5) IIFE的兩種寫法
IIFE 當即調用的函數表達式
須要理解的幾個方面:
(1) IIFE如何傳參 - (做爲模塊時,依賴項就是經過參數傳遞實現的)
(2) 多個IIFE一塊兒時,分號不能省略
(3) IIFE不會污染全局變量,由於不用爲函數命名
(4) IIFE能夠造成一個單獨的做用域名,則能夠封裝一些外部沒法讀取的變量
(5) IIFE的兩種寫法
---------------
案例:
const obj = {
name: 'woow_wu7'
};
(function(params) { // params形參
console.log(obj) // 這裏訪問的obj,不是函數參數傳入的,而是訪問的父級做用域的obj
console.log(params)
})(obj); // obj是實參
// (1)
// 注意:這裏末尾的分號是必須的,由於是兩個IIFE連續調用
// 打印:都是 { name: 'woow_wu7' }
// (2)
// IIFE的兩種寫法:
// 1. (function(){...})()
// 2. (function(){...}())
// 上面的(1)(2)都會被js理解爲表達式,而不是語句
// 表達式能夠以圓括號結尾,函數定義語句不能以圓括號結尾
// (3)
// 由於function沒有函數名,避免了變量名污染全局變量
(function(params2){
console.log(obj)
console.log(params2)
}(obj))
複製代碼
規則(規範)
封裝不一樣的塊(不一樣的文件)
,並組合在一塊兒<!DOCTYPE html>
<html lang="en">
<head>
<script>
var me = 'changeMe';
console.log(window.me, '全局變量未被修改前的window.me') // changeMe
</script>
<script src="./home.js"></script> <!-- var home = 'chongqing' -->
<script src="./me.js"></script> <!-- var me = 'woow_wu7' -->
<script src="./map.js"></script> <!-- var map = 'baidu' -->
</head>
<body>
<script>
console.log(window.me, '全局變量被修改後的window.me') // 'woow_wu7' 說明污染了全局變量
console.log(map, '模塊內變量map被修改前') // baidu
var map = 'Amap'
console.log(map, '別的模塊內mao竟然被修改了') // Amap 說明模塊內的變量被修改了,由於只有全局做用域
</script>
</body>
</html>
複製代碼
能夠先記憶一下,有個概念
IIFE,CommonJS規範,AMD,CMD,ES6的模塊化方案
commonjs -------------------------------- node.js使用的規範
AMD:Asynchronous Module Definition ----- 異步模塊定義
CMD:Common Module Definition ----------- 通用模塊定義
commonjs用於服務端,同步加載 ------------------------------ node.js使用的標準 |
AMD和CMD主要用於瀏覽器端,異步加載 |
ES6的模塊方案:用於瀏覽器和服務器,通用方案,靜態化 |
AMD依賴前置,依賴必須一開始寫好,提早加載依賴 ---------- RequireJS |
CMD依賴就近,須要使用的時候,纔去加載依賴 --------------- seajs |
ES6模塊是靜態化的,在編譯時就能肯定模塊得依賴關係,輸入,輸出;而AMD和CMD只能在運行時才能肯定 |
var a1 = 'a1'
function a1() {}
function a2() {}
缺點: 函數名會污染全局變量
複製代碼
var a3 = 'a3'
var a1 = {
a2: function() {}
a3: function() {}
}
優勢:
1. a1對象的a3屬性不會污染全局變量a3
2. 減小了全局做用域內的變量數量:
- 這裏只有a3,a1 ------- 2個
- 而全用函數:---------- 3個
缺點:
1. 仍是會污染全局變量
2. 外部能夠修改a1的屬性,即會暴露全部屬性而且能夠被外部修改
複製代碼
IIFE Immediately-invoked Function Expressions
權衡全局變量污染問題,可使用特殊符號避免
用 IIFE(當即調用的函數表達式) 實現模塊化
須要解決的問題:
(1) 各個模塊中定義的變量不能在模塊外被修改,只能在該模塊內修改,則每一個模塊須要造成單獨的做用域
(2) 模塊內的變量不能污染全局變量 => 即不能在同一個做用域,用函數能夠解決
------
未解決以上問題前的模塊:
<!DOCTYPE html>
<html lang="en">
<head>
<script>
var me = 'changeMe';
console.log(window.me, '全局變量未被修改前的window.me') // changeMe
</script>
<script src="./home.js"></script> <!-- var home = 'chongqing' -->
<script src="./me.js"></script> <!-- var me = 'woow_wu7' -->
<script src="./map.js"></script> <!-- var map = 'baidu' -->
</head>
<body>
<script>
console.log(window.me, '全局變量被修改後的window.me') // 'woow_wu7' 說明污染了全局變量
console.log(map, '模塊內變量map被修改前') // baidu
var map = 'Amap'
console.log(map, '別的模塊內mao竟然被修改了') // Amap 說明模塊內的變量被修改了
</script>
</body>
</html>
------
IIFE實現的模塊化:
<!DOCTYPE html>
<html lang="en">
<head>
<script>
(function(window,$) {
var me = 'changeMe';
console.log(me) // changeMe
window.me = me
})(window, jquery)
// 該模塊依賴jquery
// 須要暴露的變量,能夠掛載到window對象上
</script>
</head>
<body>
<script>
console.log(me, '外部沒法訪問,報錯')
// me is not defined
</script>
</body>
</html>
複製代碼
nodejs中 moudle.exports 和 exports 的區別
案例:
--- modu.js ---
const a = 11;
module.exports = a ---------------------------------- module.exports 暴露模塊
--- modu2.js ---
const b = 22;
exports.bVar = b ------------------------------------ exports 暴露模塊
--- index.js ---
const a = require('./modu.js') ---------------------- require 引入模塊
const b = require('./modu2.js')
console.log(a, 'a') // 11
console.log(b, 'b') // { bVar: 22 }
console.log(b.bVar, 'b.bVar') // 22
複製代碼
RequireJS
(1) 目錄結構:
C:.
│ index.html
│
└─requirejs
b.js
c.js
(2) 例子
b.js
define(function () { // ----------------- define(function(){...}) 定義一個模塊
return 'string b'
})
c.js
define(['./b.js'], function(res) { // --- define(['a'], function(res){...}) 定義一個有依賴的模塊,c 依賴模塊 b
return res + 'c'
});
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdn.bootcss.com/require.js/2.3.6/require.min.js"></script>
</head>
<body>
<script>
require(['./requirejs/c.js'], function(res) { // 引入模塊,並使用模塊暴露的值,res 就是模塊 c 暴露的值
console.log(res, 'res')
})
</script>
</body>
</html>
複製代碼
//定義沒有依賴的模塊
define(function(require, exports, module){
var value = 1
exports.xxx = value
module.exports = value
})
//定義有依賴的模塊
define(function(require, exports, module){
var module2 = require('./module1') //引入依賴模塊(同步)
require.async('./module2', function (m3) { //引入依賴模塊(異步)
})
exports.xxx = value // 暴露模塊,也能夠用module.exports
})
// 引入使用模塊
define(function (require) {
var a = require('./module1')
var b = require('./module2')
})
複製代碼
CommonJS模塊就是對象,輸入時(引入模塊)必須查找對象屬性
// CommonJS模塊
let { stat, exists, readFile } = require('fs');
(1) 實質上是總體加載模塊fs,在fs對象上再去讀取stat,exists等屬性
(2) 像CommonJS這種加載方式成爲運行時加載,由於只有運行時才能獲得這個對象
// ES6模塊
import { stat, exists, readFile } from 'fs';
(1) 實質是從fs模塊加載3個方法,其餘方法不加載 - 稱爲編譯時加載或者靜態加載
(2) ES6在編譯時完成加載,而不須要像CommonJS,AMD,CMD那樣運行時加載,因此效率較高
- 這會致使無法引用 ES6 模塊自己,由於它不是對象
// ES6模塊的好處
(1) 靜態加載,編譯時加載 ----- 效率較高,能夠實現( 類型檢查 )等只能靠( 靜態分析 )實現的功能
(2) 再也不須要( 對象 )做爲( 命名空間 ),將來這些功能能夠經過模塊提供
複製代碼
// 報錯
export 1;
// 報錯
var m = 1;
export m;
// 寫法一
export var m = 1;
// 寫法二
var m = 1;
export {m};
// 寫法三
var n = 1;
export {n as m};
// 報錯
function f() {}
export f;
// 正確
export function f() {};
// 正確
function f() {}
export {f};
複製代碼
// 正確
export var a = 1;
// 正確
var a = 1;
export default a; ----------------> export default a : 意思是把變量a賦值給default變量
// 錯誤
export default var a = 1
// 正確
export default 42; ---------------> 注意:能夠將值賦值給default變量,對外的接口是 default
// 報錯
export 42; -----------------------> 沒有指定對外的接口
複製代碼
export { foo, bar } from 'my_module';
// 能夠簡單理解爲
import { foo, bar } from 'my_module';
export { foo, bar };
複製代碼
import() 語法
(1) 按需加載:在須要的時候,再加載某個模塊
(2) 條件加載:能夠根據不一樣的條件加載不一樣的模塊,好比 if 語句中
(3) 動態的模塊路徑:容許模塊路徑動態生成
import(f()).then(...); // 據函數f()的返回值,加載不一樣的模塊。
(4) import()加載模塊成功之後,這個模塊會做爲一個對象,看成then方法的參數。
// 所以,可使用對象解構賦值的語法,獲取輸出接口。
// import('./myModule.js').then(({export1, export2}) => {...});
(5) 若是模塊有default輸出接口,能夠用參數直接得到。
// import('./myModule.js').then(myModule => {console.log(myModule.default)});
// 上面 myModule 模塊具備defalut接口,因此能夠用 ( 參數.default ) 獲取
(6) 同時加載多個模塊
Promise.all([
import('./module1.js'),
import('./module2.js'),
import('./module3.js'),
])
.then(([module1, module2, module3]) => {
···
});
複製代碼
詳細 (模塊化) 真的寫得好:juejin.im/post/5cb004…
超完整(模塊化):juejin.im/post/5c17ad…
js中哪些狀況不能省略分號:blog.csdn.net/BigDreamer_…
ES6模塊化方案:es6.ruanyifeng.com/#docs/modul…
個人語雀:www.yuque.com/woowwu/msyq…