開發技巧
需求分析
輸入查詢條件得出結果的需求:留意是數據篩選仍是查詢
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 in Args = Array.prototype.slice.call(null, arguments);
var finalArgs = args.concat(in Args);
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 {
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);
}
複製代碼
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
複製代碼
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)
}
複製代碼
const ob = {
* generator () { //... }
}
等同於
const ob = {
generator: function * () { //... }
}
複製代碼
協程是指並行執行,能夠交互執行權的線程
求值策略,便是函數的參數什麼時候取值的問題,有兩種類型:傳值調用和傳名調用
編譯器的「傳名調用」實現,每每是將參數放到一個臨時函數之中,再將這個臨時函數傳入函數體。這個臨時函數就叫作 Thunk 函數。
基於Thunk的流程自動化管理
var fs = require('fs' );
var thunkify = require('thunkify' );
var read FileThunk = 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 read FileThunk('fileA' );
var f2 = yield read FileThunk('fileB' );
var fn = yield read FileThunk('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 { 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;
}));
複製代碼
設計模式
單一指責原則
里氏替換
接口拆分
依賴倒置
開放封閉原則