前端小零識

開發技巧

需求分析

  • 輸入查詢條件得出結果的需求:留意是數據篩選仍是查詢

JavaScript

JS基本原理

  • javascript運行在單線程環境

數組操做

segmentfault.com/a/119000001…

this指向

  • 首先this指向的對象只有三個:windows、函數實例、所處對象
  • 若是函數有this,可是沒有所處對象或函數實例調用,那麼this指向windows
function a(){
    var user = "追夢子";
    console.log(this.user); //undefined
    console.log(this); //Window
}
a();
複製代碼
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();
複製代碼
  • 若是this被所處對象或函數實例調用,this指向該對象
var o = {
    a:10,
    b:{
        //a:12,
        fn:function(){
            console.log(this.a); //undefind  有兩個對象b和o,因此此this.a指向它的上一級
        }
    },
    fn1:function(){
        console.log(this.a);  //10 
    }
}
o.fn1();
o.b.fn();
複製代碼
  • 當函數中有this,且最後使用了return,若是return的是對象,那麼this指向該對象,不然this指向函數實例
function fn()  
{  
    this.user = '追夢子';  
    return {};  // 或function(){}
}
var a = new fn;  
console.log(a.user); //undefined
複製代碼
function fn()  
{  
    this.user = '追夢子';  
    return 1;   
}
var a = new fn;  
console.log(a.user); //追夢子
複製代碼
  • 雖然null也是對象,可是null比較特殊,return null,this依然指向函數實例,不指向null

bind、apply、call的區別

  • apply和call不一樣點在於,call須要一個個傳入參數,apply能夠數組形式傳入參數;使用方法分別爲funA.apply(funB, args)和funA.call(funB, arg1, arg2, arg3...)。
  • bind的傳參方式與call相同,但永久改變this的指向,並返回新的函數;使用方法爲var newFun = funA.bind(funB, arg1, arg2...);若是在使用bind時傳入了參數,那麼以後調用newFun時參數也是默認被傳入,如var newFun = funA.bind(null, a, b); newFun(c, d); 這裏至關於傳入了a、b、c、d四個參數。

柯里化

  • 柯里化是建立一個已經設置好一個或多個參數的函數,是用於動態建立函數的強大功能
  • 柯里化函數的通用方式:
function curry(fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function () {
        var inArgs = Array.prototype.slice.call(null, arguments);
        var finalArgs = args.concat(inArgs);
        return fn.apply(null, finalArgs);
    };
}
複製代碼

不可擴展對象

  • 使用Object.preventExtensions()能夠防止對象添加新成員
var ob = {name: 'tom'};
Object.preventExtensions(ob);
ob.age = 22;
alert(ob.age);  // undefined;
複製代碼
  • 使用Object.preventExtensions()後的對象,非嚴格模式下,添加新成員靜默失敗;嚴格模式下,添加新成員拋錯。
  • 使用Object.preventExtensions()後的對象,依舊能夠刪除修改爲員
  • 可使用Object.isExtensible()可判斷是否能夠擴展;

密封對象

  • 使用Object.seal(ob)密封對象ob,對象不可添加和刪除成員。非嚴格模式默認失敗,嚴格模式下拋錯。可是能夠修改爲員。

凍結對象

  • 使用Object.freeze(ob)凍結對象ob,對象不可修改、添加、刪除成員。非嚴格模式默認失敗,嚴格模式下拋錯。

定時器原理

  • 指定的時間間隔表示什麼時候將定時器的代碼放入隊列,而不是什麼時候當即執行代碼,若是隊列裏面還有其它任務,那麼這些排在前面的任務將會被優先執行,定時器代碼會被滯後執行。
  • 異步隊列中的任務會在進程空閒期執行

重複的定時器原理

  • 重複定時器主要是setInterval,但使用setInterval有不少問題
  • 若是再添加定時器代碼到隊列時,上一次添加到隊列的代碼尚未執行完,可能會致使定時器代碼連續執行屢次,沒有停頓。爲了解決這個問題,瀏覽器會判斷隊列裏有無定時器代碼實例,若是有則不添加代碼到隊列。
  • 上述瀏覽器的解決方案也存在另外一問題:某些定時任務被跳過

數據屬性

訪問器屬性

獲取通用惟一識別碼

https://blog.csdn.net/mr_raptor/article/details/52280753
複製代碼

純函數

  • 函數返回結果只依賴於參數
  • 函數沒有反作用,不會更改參數

運算符

  • NaN === NaN // false
  • +0 === -0 // true (但這裏本應該是不等的,是JS的缺陷)

字符串

  • replace(arg1, arg2):用於字符串內容替換,第一參數爲正則表達式或字符串,第二參數爲需替換的字符串或函數,函數爲function(matchStr, group1[...groupN], index, sourceStr),matchStr爲正則匹配到的字符串,group爲捕獲組,index爲匹配項在字符串中的開始下標,sourceStr爲原字符串

CSS

佈局

  • clearfix
.clearfix {
  display: block;
  zoom: 1;

  &:after {
    content: " ";
    display: block;
    font-size: 0;
    height: 0;
    clear: both;
    visibility: hidden;
  }
}
複製代碼

ES6

對象的新增方法

  • Object.is()方法能夠準確比較NaN與其自身,+0和-0的比較,如:

  • Object.assign()參數爲非對象則轉換爲對象並返回
  • Object.assign()參數爲null或undefined則報錯
  • 利用Object.assign()克隆對象並拷貝對象的原型鏈
function clone(origin) {
  let originProto = Object.getPrototypeOf(origin);
  return Object.assign(Object.create(originProto), origin);
}
複製代碼
  • 如下克隆方法能夠解決get、set不能克隆的問題
function shallowMerge(target, source) {
    return Object.defineProperties(target, Object.getOwnPropertyDescriptors(source))
}
複製代碼
  • 利用Object.create()克隆對象,對象屬性能夠爲訪問器屬性,並拷貝對象的原型鏈
function merge(ob) {
    return Object.create(Object.getPrototypeOf(ob), Object.getOwnPropertyDescriptors(ob));
};
複製代碼
  • Obeject.entries()不能輸出Symbol鍵值對
  • Symbol類型的實例具備惟一性,通常用做屬性,可用於替換魔術字符串
  • 使用Symbol.for()可建立全局的惟一Symbol類型實例
  • 數據結構Set的成員惟一,可用於數組去重,如:
Array.from(new Set(arr))
[...new Set(arr)]
複製代碼

也能夠用於字符串去重,如:javascript

[...new Set(str)].join('')
複製代碼

Map和Set

  • Set的原型鏈屬性有contructor、size,操做屬性有add、delete、has、clear,遍歷方法有keys、values、entries、forEach
  • WeakSet的成員只是對象,且對象都爲弱引用,若對象引用次數爲0,對象則被gc
  • WeakSet的實例操做方法有add、has、delete
  • Map數據結構的鍵能夠爲任意類型
  • Map數據類型+0和-0等同於一個鍵、NaN雖然等同於自身可是會把NaN視爲一個鍵
  • Map數據類型具備繼承屬性size,操做方法set、get、delete、clear、has,遍歷方法有keys、values、entries、forEach
  • WeakMap數據結構只接受對象做爲鍵名

Proxy

  • 元編程即爲對編程語言進行編程
  • proxy是一種元編程方法,機制是在操做對象前會做一層攔截
  • proxy中的get、set能夠被繼承
  • proxy可用於屬性的鏈式操做
var ob = {
  n: 0,
  a: function(n) {
    return n + 1;  
  },
  b: function(n) {
    return n + 1;
  }
}
var pipe = function (ob, value) {
  var funcStack = [];
  var oproxy = new Proxy(ob , {
    get : function (pipeObject, fnName) {
      if (fnName === 'get') {
        return funcStack.reduce(function (val, fn) {
          return fn(val);
        }, value);
      }
      console.log('fnName', fnName)
      funcStack.push(ob[fnName]);
      console.log('funcStack', funcStack)
      return oproxy;
    }
  });
  return oproxy;
};


var proxy = pipe(ob, 1);
console.log(proxy.a.b.get)  // 3
複製代碼
  • Reflect是使用內部語言方法操做對象

Promise

  • 概念:Promise是一個容器,保存着將來發生的事情。Promise是一個對象,能夠獲取異步操做的消息。
  • 優勢:
    (1)狀態不受外界影響:三種狀態pending、fullfilled、reject (2)狀態改變後不會再改變,何時均可以獲得這個結果:從pending到fullfilled或從pending到reject後,狀態resolved(定型),任意時刻能夠得 到結果
  • 缺點:
    (1)Promise一旦建立,不能夠取消
    (2)若是在pending狀態,不能夠知道是處於剛開始仍是即將完成狀態

Interator

  • Interator是一種接口,爲不一樣的數據結構提供統一的訪問機制,具有Interator的數據結構完成遍歷操做
  • 具有Interator的數據結構:Array、Map、Set、String、TypedArray、函數的 arguments 對象、NodeList對象
  • 對象不具有Iterator接口,是由於屬性的順序是不肯定的
  • 只有類數組對象可使用[Symbol.iterator]方法,如:
let iterable = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
  console.log(item); // 'a', 'b', 'c'
}
複製代碼
  • 普通對象使用[Symbol.iterator]方法無效
let iterable = {
  a: 'a',
  b: 'b',
  c: 'c',
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
  console.log(item); // undefined, undefined, undefined
}
複製代碼
  • [Symbol.iterator]方法的使用場合,在解構賦值、擴展運算符、yield*(yield*後面爲可遍歷結構時,會調用後面的可遍歷結構的[Symbol.iterator]方法),其它場合:(for...of Array.from() Map(), Set(), WeakMap(), WeakSet()(好比new Map([['a',1],['b',2]])) Promise.all() Promise.race())
  • 除了next方法外,還有return(),throw()方法
  • for...of循環可使用的範圍包括數組、Set 和 Map 結構、某些相似數組的對象(好比arguments對象、DOM NodeList 對象)、後文的 Generator 對象,以及字符串

Generator

  • Generator是一個狀態機,同時也是遍歷器對象生成器
  • 特徵:function和函數名之間有一個*號,函數內部使用field表達式,表示不一樣的狀態
  • 返回:指向內部狀態的指針對象
  • 能夠把Generator賦值給對象的[Symbol.iterator]實現對象的iterator操做
  • Generator執行後返回的遍歷器也具備[Symbol.iterator],而且Symbol.iterator指向其自身
  • 若是next帶有參數,那麼這個參數就是上一個field的返回值
function* generator() {
  yield 1;
  yield 2;
  return 3;
}

var g = generator();
console.log(g.next())
console.log(g.next())
console.log(g.next())
/**
 * Object {value: 1, done: false}
    Object {value: 2, done: false}
    Object {value: 3, done: true}
    Object {value: undefined, done: true}
 */
複製代碼

若是調用next時遇到return,返回值中的done就會提早爲true;若是沒有return,當把generator的值遍歷完後調用next,返回的done才爲truejava

  • 實現斐波那契數列:
function* fibonacci() {
  let [prev, cur] = [0, 1];
  for (;;) {
    yield cur;
    [prev, cur] = [cur, prev + cur]
  }
}

for (let i of fibonacci()) {
  if (i > 10000) break;
  console.log(i)
}
複製代碼
  • Generator能夠做爲對象屬性:
const ob = {
    * generator () { //... }
}
等同於
const ob = {
   generator: function* () { //... } 
}

複製代碼
  • 協程是指並行執行,能夠交互執行權的線程
  • 求值策略,便是函數的參數什麼時候取值的問題,有兩種類型:傳值調用和傳名調用
  • 編譯器的「傳名調用」實現,每每是將參數放到一個臨時函數之中,再將這個臨時函數傳入函數體。這個臨時函數就叫作 Thunk 函數。
  • 基於Thunk的流程自動化管理
var fs = require('fs');
var thunkify = require('thunkify');
var readFileThunk = thunkify(fs.readFile);

function run(fn) {
  var gen = fn();

  function next(err, data) {
    var result = gen.next(data);
    console.log(result)
    if (result.done) return;
    result.value(next);
  }

  next();
}

var g = function* (){
  var f1 = yield readFileThunk('fileA');
  var f2 = yield readFileThunk('fileB');
  var fn = yield readFileThunk('fileN');
};

run(g);
複製代碼

async

  • async是generator的語法糖,優勢:(1)內置執行器
    (2)更好的語義
    (3)更廣的適用性,await後面能夠是Promise或原始類型值(若原始類型值爲n,至關於Promise.resolve(n))
    (4)返回的值是Promise

class

  • 子類沒有定義constructor方法,這個方法會被默認添加
  • 在子類的constructor方法中,須要調用super纔可使用this
  • super在靜態方法中指向父類,在普通方法中指向父類的原型
  • 在子類普通方法中使用super調用父類的方法,方法中的this指向子類實例
  • 在子類的靜態方法中使用super調用父類方法,方法中的this指向子類而不是子類的實例
  • 經過super爲屬性賦值,此時super就是this,致使賦值的是子類的屬性
class A {
  constructor() {
    this.x = 1;
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
    super.x = 3;
    console.log(super.x); // undefined
    console.log(this.x); // 3
  }
}

let b = new B();
複製代碼
  • Object.getPrototypeOf方法能夠用來從子類上獲取父類
  • 子類的構造函數必須執行一次super()
  • 若A爲B的父類,super()至關於A.prototype.constructor.call(this)
  • new.target只能在constructor中使用,而且指向當前執行的函數
  • 子類的__proto__指向父類,子類的prototype的__proto__指向父類的prototype
class A {
}

class B extends A {
}

B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
複製代碼
  • 若是隻是單純的類,沒有繼承,類的__proto__指向Function.prototype,類的prototype.__proto__指向Object.prototype
class A {
}

A.__proto__ === Function.prototype // true
A.prototype.__proto__ === Object.prototype // true
複製代碼
  • 子類實例的__proto__屬性的__proto__屬性,指向父類實例的__proto__屬性
class Point {}
class ColorPoint extends Point {}

var p1 = new Point(2, 3);
var p2 = new ColorPoint(2, 3, 'red');

console.log(p2.__proto__.__proto__ === p1.__proto__ )  // true
console.log(p2.__proto__ === p1 )  // false
複製代碼
  • ES的原生構造函數有以下:
    Boolean()
    Number()
    String()
    Array()
    Date()
    Function()
    RegExp()
    Error()
    Object()
    在ES5中不能經過繼承內部屬性和內部方法,在ES6中能夠實現。注意在繼承Object時會有異常:
class NewObj extends Object{
  constructor(){
    super(...arguments);
  }
}
var o = new NewObj({attr: true});
o.attr === true  // false
複製代碼

由於若是不是使用new Object()新建對象,ES6會忽略傳入的參數jquery

  • Mixin混入模式是指多個對象合成新對象,新對象具備這些原對象成員的接口

Module

  • export用於定義模塊對外的接口
  • export能夠輸出變量、函數、類,不能輸出常量
  • 須要注意使用export輸出函數的寫法
function fn() { ... }
export fn;	// 錯
export { fn };	// 對
複製代碼
  • export 只能放在模塊的頂層,能夠放在頂層的任意位置,但不能夠放在函數內部
  • export default A等同於將A賦值給default而後輸出,因此能夠
import { default as B } from 'xx.js';
複製代碼

也能夠正則表達式

export { A as default };
複製代碼
  • export和import的複合寫法:
export { A } from 'xxx.js'
複製代碼
  • import用於引入其餘模塊的功能
  • import引入的變量是動態綁定,如import a,若是輸出的a是異步變化的,那麼引入a的也是變化的
  • import命令具備提高效果,由於import再編譯期間(代碼運行以前)就會執行

ArrayBuffer

  • ArrayBuffer是內存中一段二進制數據
  • TypeArray包括9類視圖:
    (1)Init8Array: 8位整型 (2)Uinit8Array: 8位無符號整型 (3)Uinit8CArray: 8位無符號整型(自動過濾溢出) (4)Init16Array: 16位整型 (5)Uinit16Array: 無符號16位整型 (6)Init32Array: 32位整型 (7)Uinit32Array: 無符號32位整型 (8)Float64Array: 64位浮點型 (9)Ufloat64Array: 無符號64位浮點型
  • DataArray: 自定義的複合格式的視圖
  • ArrayBuffer.prototype.byteLength:用戶獲取ArrayBuffer的實例
  • ArrayBuffer.prototype.slice():用於將ArrayBuffer內存的一部分,拷貝爲一段新的內存;過程爲建立一段新的內存,而後拷貝
  • ArrayBuffer.prototype.slice():判斷是否爲ArrayBuffer的視圖實例(如 DataArray、TypeArray的實例)
  • TypeArray與Array的區別:
    (1)成員連續
    (2)成員默認爲0 (3)成員類型一致 (4)自己只是視圖,實際數據存儲在底層的ArrayBuffer

計算機基礎

編碼

  • 編碼是信息從一種形式轉換到另外一種信息的過程,解碼便是逆編碼。
  • JavaScript有全局方法encodeURI()和encodeURIComponent();
  • encodeURI不對如下字符編碼
    • 保留字符:; , / ? : @ & = + $
    • 非轉義字符:字母 數字 - _ . ! ~ * ' ( )
    • 數字字符 #
  • encodeURIComponent不會對如下字符編碼
    • 非轉義字符:字母 數字 - _ . ! ~ * ' ( )
  • 二者的區別是encodeURI不能對保留字符和#轉義

解碼

  • encodeURI()和encodeURIComponent()對應的解碼方法有decodeURI()和decodeURIComponent()

進程和線程

  • 進程是資源分配的最小單位,線程是程序執行的最小單位
  • 進程有獨立的內存地址空間
  • 一個進程下能夠有多個線程
  • 同一進程下的多個線程可共享進程的資源
  • 多進程程序更加健壯,由於一個線程死掉,進程即死掉,該進程下的全部全部線程都會死掉;而一個進程死掉不會影響另外一進程,由於進程佔用獨立的內存地址空間

計算機網絡

鏈路層

  • 每個網卡都用一個mac地址
  • 廣播:假設子網略內有若干臺主機,一臺主機發出一個數據包,接收到包的主機會讀取數據包頭部的MAC地址,並與自身的MAC地址比較,若是相同則作進一步處理,不然丟棄這個包

網絡層

  • 網絡層的存在是由於:鏈路層廣播的效率低,通訊雙方須要在一個子網略,侷限性太大
  • 網絡層引進了「網絡地址」,引入網絡地址能夠區分哪一些MAC地址處於同一個子網絡
  • 規定網絡地址的協議成爲IP地址,由32位二進制數組成 11111111.11111111.11111111.00000000,可分爲網絡部分和主機部分,若是網絡部分爲前24位,主機部分位後8位,那麼前24位相同的兩個ip地址確定在同一個子網絡。
  • 子網掩碼用於肯定IP地址的網絡部分,好比子網掩碼位255.255.255.0,那麼確定是前24位爲網絡部分
  • ARP協議:用於同一子網絡的通訊,協議內容是:發出的包含有所要查詢主機的ip地址和mac地址,mac地址爲FF:FF:FF:FF:FF:FF(12位16進制),表示廣播到全部主機。所在子網絡的每一臺主機會收到這個包,取出其中的IP地址並與自身比對,若是相同雙方都作出回覆,告訴對方本身的mac地址,不然丟棄這個包
  • 實現數據包的成功發送,須要獲取接收方的MAC地址、IP地址、網關地址、DNP服務器IP地址

動態IP地址

  • 靜態IP地址:每次開機都用一個IP地址上網,便是「靜態IP地址上網」。爲了更方便地爲新接入的主機添加IP地址,通常會使用動態IP地址。DHCP協議(動態主機設置協議)可實現動態IP地址

獲取動態IP地址過程

(1)新加入的主機會向DHCP服務器發送一個DHCP請求數據包,數據包的結構爲 |以太網標頭|IP標頭|UDP標頭|data(數據內容)|編程

  • 以太網標頭含有發送方和接收方的MAC地址,前者爲新加入主機自身的MAC地址,後者爲FF.FF.FF.FF.FF.FF,便是廣播地址
  • IP標頭含有發送方和接收方的IP地址,由於二者都不知道,因而發送發IP地址設爲0.0.0.0,接收方IP地址設爲255.255.255.255
  • UDP標頭含有發送方和接收方的端口,前者設爲68,後者設爲67
  • 請求數據包在子網絡內廣播,接收到數據包的主機首先解析數據包MAC地址,由於接收方MAC地址爲FF.FF.FF.FF.FF.FF廣播地址,因此會解析數據包的IP地址,接收方IP爲255.255.255.255,將之與自身IP地址比對,發現不一樣則丟包
    (2)當DHCP服務器接收到請求數據包並解析接收方IP地址,發現爲255.255.255.255,服務器知道須要去分配IP,發出響應數據包
    (3)響應數據包的數據內容中含有爲新主機分配的IP地址、網關IP地址、DNS的IP地址
  • 響應數據包的以太網標頭含有發送方和接收方的MAC地址,前者爲DHCP服務器看的MAC地址,後者爲新主機的MAC地址
  • IP標頭含有發送方IP地址爲DHCP服務器自身的IP地址,接收方IP地址依然爲255.255.255.255
  • UDP標頭的發送方端口爲67,接收方端口爲68 (4)新加入的數據包接收到響應數據包,拿到IP地址、子網掩碼、網關IP、DNS服務器的IP。

傳輸層

  • 端口:表示數據包供哪一個程序使用,端口號能夠爲0到65535,0到1023供系統使用
  • 傳輸層是"端口到端口"的通訊
  • UDP的優勢是簡單,可是可靠性差,沒法知道對方是否接收到。
  • TCP可靠性比UDP強,缺點是過程複雜、消耗較多資源

應用層

  • 主要用於規定好客戶端和服務端的通訊格式

一次網絡通訊的過程

好比說用咱們的計算機訪問一次百度(baidu.com):segmentfault

  • 設置好本機IP、子網掩碼、DNS_IP、網關IP
  • 本機向DNS_IP發送一個DNS數據包,經過DNS協議得到將baidu.com解析爲IP地址
  • 接下來建立咱們的數據包,首先將HTTP數據包嵌入TCP數據包,新數據包再嵌入IP數據包,這個由HTTP數據包、TCP數據包、IP數據包組成的新數據包最後會嵌入以太網數據包(它的結構以下圖)
  • 經過子網掩碼判斷本機與百度服務器是否在同一網關(咱們和百度服務器的必然是不一樣的)
  • 以太網標頭的目標MAC地址改成本機網關的MAC地址,咱們的數據包轉由網關發送
  • 經過ARP協議將百度服務器的IP地址解析爲MAC地址,獲得了最終的數據包。假設這一個數據包大小爲4600字節,由於以太網數據包的大小限制爲1500字節,因此須要切割爲大小分別爲1500、1500、1500、100字節的四個以太網數據包,最後再發送到百度的服務。

JS替換語言

TypeScript

基礎類型

  • 基礎類型有:number、boolean、string、null、undefined、symbol、object
  • null和undefined是全部類型的子類型,所以能夠把它們賦給任何已經定義類型的變量
  • never是那些不存在值的類型,如只會拋錯和沒有return值的函數,是全部類型的子類型,但它沒有子類型(包括any)
  • 類型斷言:相似於類型轉換、不進行類型檢查,可有兩個方式:和as string
  • 若是想變量只讀使用const,想對象的屬性只讀,可定義類型爲只讀類型,好比
interface Point {
    readonly x: number;
    readonly y: number;
}
複製代碼
  • 處理額外屬性可使用索引簽名,索引簽名能夠爲數字也能夠是字符串,可是前者值的類型必須是後者的子類型,如(propName爲其他屬性):
interface Ob {
    name: string;
    [rest: string]: any;    // string定義屬性名類型、any定義值的類型
}
複製代碼

模塊化

AMD(異步模塊規範)

define(['jquery', 'underscore'], function ($, _) {
// 方法
function a(){}; // 私有方法,由於沒有被返回(見下面)
function b(){}; // 公共方法,由於被返回了
function c(){}; // 公共方法,由於被返回了
     //    暴露公共方法
    return {
        b: b,
        c: c
    }
});
複製代碼

CommonJS

var $ = require('jquery');
複製代碼

UMD

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node, CommonJS之類的
        module.exports = factory(require('jquery'));
    } else {
        // 瀏覽器全局變量(root 即 window)
        root.returnExports = factory(root.jQuery);
    }
}(this, function ($) {
    //    方法
    function myFunc(){};
 
    //    暴露公共方法
    return myFunc;
}));
複製代碼

設計模式

單一指責原則

里氏替換

接口拆分

依賴倒置

開放封閉原則

相關文章
相關標籤/搜索