前情回顧:
自執行函數(IIFE):
作用:馬上執行這個函數,自執行函數(IIFE),不易讀
(function(x){console.log(x);})(3);
易讀版本:
(function(x){
return x *x;
})(3);
閉包引申:
回顧:
function create_counter(initial){
var x = initial || 0; //如果initial沒有值,那么采用后面的0
return {
//對象
inc:function(){
x+=1;
return x;
}
}
}
var c1 = create_counter();
console.log(c1.inc());
console.log(c1.inc());
console.log(c1.inc());
var c2 = create_counter(10);
console.log(c2.inc());
console.log(c2.inc());
console.log(c2.inc()); */
箭頭函數:
function (x){
return x * x;
}
上述代碼等價於下面:
x => x*x;
箭頭函數的無參、單參、雙參、多參的格式:
//無參
()=>3;
//單參
x =>{
if(x > 0){
return x*x;
}else{
return -x*x;
}
}
//雙參
(x,y) => x*x+y*y;
//多參
(x,y,...rest)=>{
}
this指向的引入以及發展:
this的指向在有無use strict
會不同的,我們通過幾段不同的代碼段引入this以及this指向的發展。
'use strict';
//1版-->正常使用
var xiaoming = {
name:'小明',
birth:2000,
age:function(){
var y = new Date().getFullYear();
return y - this.birth;
}
};
console.log(xiaoming.age());
//2版:
'use strict';
/*
嚴格模式:
xiaoming.age() 可以得到結果,
getAge()顯示報錯--> Cannot read property 'birth' of undefined
*/
function getAge(){
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name:'小明',
birth:2000,
age:getAge
};
console.log(xiaoming.age());
console.log(getAge());
前兩個版本暫時還是沒有引出this以及指向,下面看第三個版本,這個版本會有較大的改變,在不在strict中的結果也會不一樣。
'use strict';
/*
嚴格模式下:會報錯,Cannot read property 'birth' of undefined
非嚴格模式下:NaN not a number,瀏覽器不會爆紅,可能指向window
*/
var obj = {
birth:2000,
getAge:function(){
function GetAgeFormBirth(){
var y = new Date().getFullYear();
return y - this.birth;
}
return GetAgeFormBirth();
}
};
console.log(obj.getAge());
這是js的遺留問題,為了解決這個問題,我們可以使用變量保存this的指向,如版本四:
'use strict';
var obj = {
birth:2000,
getAge:function(){
//保存thisz指向
var that = this;
function GetAgeFormBirth(){
var y = new Date().getFullYear();
return y - that.birth;
}
return GetAgeFormBirth();
}
};
console.log(obj.getAge());
但是這種表述方式比較麻煩,代碼量也有些多,我們可以采用箭頭函數來實現:
//這是個對象
'use strict';
var obj = {
birth:2000,
getAge:function(){
var b = this.birth;
var fn = ()=> new Date().getFullYear()-this.birth;
return fn();
}
};
console.log(obj.getAge());
模塊化演變:
模塊化演變是為了初學者一步一步實現和解決代碼的冗余、復用性、命名污染問題。
模塊演變1:
缺點已在代碼塊中標明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- html --》"" -->
<!-- js --》'' -->
<!-- 使用內嵌腳本 -->
<!--
缺點:
復用性 很低
1.缺乏依賴解析
2.全局命名空間污染的問題
-->
<h1>
the answer is <span id="answer"></span>
</h1>
<script>
function add(a,b){
return a+b;
}
function reduce(arr,iteratee){
var index=0,length = arr.length,memo = arr[index];
index+=1;
for(index =0;index < length;index++){
memo = iteratee(memo,arr[index]);
}
return memo;
}
function sum(arr){
return reduce(arr,add);
}
var values = [1,2,3,4,5,6,7,8,9];
var answer = sum(values);
document.getElementById("answer").innerHTML = answer;
</script>
</body>
</html>
模塊演變2:
add.js
function add(a,b){
return a+b;
}
reduce.js
function reduce(arr,iteratee){
var index=0,length = arr.length,memo = arr[index];
index+=1;
for(index =0;index < length;index++){
memo = iteratee(memo,arr[index]);
}
return memo;
}
sum.js
function sum(arr){
return reduce(arr,add);
}
main.js
var values = [1,2,3,4,5,6,7,8,9];
var answer = sum(values);
document.getElementById("answer").innerHTML = answer;
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>
the answer is <span id="answer"></span>
</h1>
<!-- script標簽引入JavaScript -->
<!-- 缺點:
必須保證js的引用順序正確
同樣缺乏依賴解析
同樣有命名沖突的問題
-->
<script src = "./add.js"></script>
<script src = "./reduce.js"></script>
<script src="./sum.js"></script>
<script src = "./main.js"></script>
</body>
</html>
模塊演變3:
myApp.js
// 空對象
var myApp = {
};
add.js
// 立即執行函數
(function (){
// 將add放入myApp中
myApp.add = function(a,b){
return a+b;
}
})();
reduce.js
// 立即執行函數IIFE
(function (){
// 將reduce放入myApp中
myApp.reduce = function(arr,iteratee){
var index=0,length = arr.length,memo = arr[index];
index+=1;
for(;index < length;index++){
memo = iteratee(memo,arr[index]);
}
return memo;
}
})();
sum.js
// 立即執行函數
(function (){
// 將sum放入myApp中
myApp.sum = function(arr){
return myApp.reduce(arr,myApp.add);
}
})();
main.js
/**
* @description:
* @param {*}
* @return {*}
*/
/* (function(){
var values = [1,2,3,4,5,6,7,8,9];
var answer = myApp.sum(values);
document.getElementById("answer").innerHTML = answer;
}); */
(function(app){
var values = [1,2,3,4,5,6,7,8,9];
var answer = myApp.sum(values);
document.getElementById("answer").innerHTML = answer;
})(myApp);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>
the answer is <span id="answer"></span>
</h1>
<script src="./myapp.js"></script>
<script src="./reducec.js"></script>
<script src="./sum.js"></script>
<script src="./add.js"></script>
<script src="./main.js"></script>
</body>
</html>
模塊演變4:
采用require.js來實現。
為什么要使用require.js來實現:
在正式開發的項目中,隨着js的外部引用文件越來越多,網頁失去響應的時間就會越長;其次,由於js文件之間存在依賴關系,因此必須嚴格保證加載順序,依賴性最大的模塊一定要放到最后加載,當依賴關系很復雜的時候,代碼的編寫和維護都會變得困難。
在開發中,有一個網頁三秒原則
;
網頁三秒原則:
當用戶的在請求一個網站的時候,響應時間超過三秒鍾,大部分用戶將關閉或者重新刷新網頁,用戶體驗很不爽。
所以require.js就解決上述問題:
-
實現js文件的異步加載,避免網頁失去響應;
-
管理模塊之間的依賴性,便於代碼的編寫和維護。
require.js的AMD格式規范:
// main.js
define(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// some code here
});
define()函數接受的參數。
-
第一個參數是一個數組,表示所依賴的模塊,上例就是['moduleA', 'moduleB', 'moduleC'],即主模塊依賴這三個模塊;
-
第二個參數是一個回調函數,當前面指定的模塊都加載成功后,它將被調用。加載的模塊會以參數形式傳入該函數,從而在回調函數內部就可以使用這些模塊。
-
模塊必須采用特定的define()函數來定義。如果一個模塊不依賴其他模塊,那么可以直接定義在define()函數之中
-
如果這個模塊還依賴其他模塊,那么define()函數的第一個參數,必須是一個數組,且指明該模塊的依賴性。
define()異步加載moduleA,moduleB和moduleC,瀏覽器不會失去響應;它指定的回調函數,只有前面的模塊都加載成功后,才會運行,解決了依賴性的問題。
以下是模塊演變4的實現代碼:
index.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>
the answer is <span id="answer"></span>
</h1>
<!-- 入口點是main -->
<!-- require加載了main.js的依賴,也會加載它依賴的依賴 -->
<!-- 帶來的問題:
1. 降低一些性能
-->
<script data-main="main" src = "require.js"></script>
</body>
</html>
data-main屬性的作用是,指定網頁程序的主模塊
main.js
define(['sum'],function(sum){
var value = [1,2,3,4,5,6,7,8,9];
var answer = sum(value);
document.getElementById('answer').innerHTML = answer;
})
sum.js
define([
'add',
'reduce'
], function(add, reduce) {
var sum = function(arr){
return reduce(arr,add);
}
return sum;
});
reduce.js
define([], function(arr,iteratee){
var reduce = function(arr,iteratee){
var index=0,length = arr.length,memo = arr[index];
index+=1;
for(;index < length;index++){
memo = iteratee(memo,arr[index]);
}
return memo;
}
return reduce;
});
add.js
define([],function(){
var add = function(a,b){
return a+b;
}
return add;
})
分析上述代碼的執行流程:
- 先加載index.html以及require.js文件,找到模塊的主入口(main.js)
- 加載main.js,由於main中依賴sum.js
- 再加載sum.js,sum中依賴add.js以及reduce.js
- 再加載add.js以及reduce.js
- 最后全部依賴執行完成后,回調得到的結果
執行效果以及文件加載順序的觀察:
模塊演變5:
基於commonJS規范以及browserify瀏覽器端的模塊演變
什么是browserify:
browserify是專注於解決按照CommonJS規范書寫的模塊能夠在瀏覽器中使用問題的構建工具。
CommonJS規范:
- 每個文件就是一個模塊,有自己的作用域。在一個文件里面定義的變量、函數、類,都是私有的,對其他文件不可見
- 每個模塊內部,
module
變量代表當前模塊。這個變量是一個對象,它的exports
屬性(即module.exports
)是對外的接口。加載某個模塊,其實是加載該模塊的module.exports
屬性。
下載方式:
npm install -g browserify
代碼如下:
index.js
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<h1>
The Answer is <span id="answer"></span>
</h1>
<!-- browserify .\main.js -o bundle.js 打包-->
<script src="bundle.js"></script>
</body>
</html>
注意點:引用的js的文件是與我們打包命令時 -o后面名字對應的。
main.js
var sum = require('./sum');
var values = [1,2,3,4,5,6,7,8,9];
var answer = sum(values);
document.getElementById("answer").innerHTML = answer;
sum.js
var reduce = require('./reduce');
var add = require('./add');
module.exports = function(arr){
return reduce(arr,add);
};
reduce.js
module.exports = function reduce(arr,iteratee){
var index=0,length = arr.length,memo = arr[index];
index+=1;
for(;index < length;index++){
memo = iteratee(memo,arr[index]);
}
return memo;
};
add.js
module.exports = function add(a,b){
return a+b;
};
打包方式:
browserify .\main.js -o bundle.js //window中
效果圖:
運行查看加載信息:
可以與require.js的加載方式做對比,理解兩者的不同以及相同的地方。
擴展:
require.js VS browserify
- require.js是模塊加載器;browserify是預編譯工具
- require.js遵循的是AMD規范;browserify遵循的是CommonJS規范
- require.js是在瀏覽器端運行期分析依賴;browserify在服務器端編譯期就進行了依賴分析,通過每個模塊的外部接口獲取信息
結束:
如果你看到這里或者正好對你有所幫助,希望能點個關注或者推薦,感謝;
有錯誤的地方,歡迎在評論指出,作者看到會進行修改。