前言正則表達式
你真的瞭解JS嗎,看徹底篇,你可能對人生產生疑問。數組
typeof瀏覽器
typeof運算符,把類型信息當作字符串返回。安全
//正則表達式 是個什麼 ? typeof /s/ // object //null typeof null // object
正則表達式並非一個‘function’,而是一個object。在大多數語言中,null 表明的是一個空指針(0x00),可是在js中,null爲一個object。app
instanceof函數
instanceof運算符,用來測試一個對象在其原型鏈中是否存在一個構造函數:prototype測試
//語法 object instanceof constructor function Person(){}; var p =new Person(); p instanceof Person; //true
但this
[] instanceof window.frames[0].Array // false
由於 Array.prototype !== window.frames[0].Array.prototype ,所以,咱們必須使用Array.isArray(obj)或者Object.prototype.toString.call(obj) === "[object Array]" 來判斷obj是否爲數組。spa
Object.prototype.toStringprototype
根據上面提到的,可使用該方法獲取對象類型的字符串。
//call的使用能夠看博主前面的文章。(使用apply亦可) var toString = Object.prototype.toString; toString.call(new Date); // [object Date] toString.call(new String); // [object String] toString.call(Math); // [object Math] toString.call(/s/); // [object RegExp] toString.call([]); // [object Array] toString.call(undefined); // [object Undefined] toString.call(null); // [object Null]
做用域安全與構造函數
構造函數:使用new調用的函數,當使用new調用時,構造函數內的this會指向新建立的對象實例。
function Dog(name, age){ this.name = name; this.age = age; } let dog = new Dog("柴犬", 5); dog.name // 柴犬
若是咱們沒有使用new又會如何?
let dog = Dog("柴犬", 5); dog.name // undefined window.name // 柴犬
這是由於在沒有使用new關鍵字時,this在當前狀況被解析成window,因此屬性就被分配到window上了。
function Dog(name, age){ if(this instanceof Dog){ this.name = name; this.age = age; }else{ return new Dog(name, age); } } let dog1 = new Person("柴犬", 5); dog1.name // 柴犬 let dog2 = Dog("柯基犬", 20); dog2 .name // 柯基犬
使用上面的方法,就能夠再不使用new的狀況下,正常構造函數。
惰性載入函數
一個函數以下:
function foo(){ if(a != b){ console.log('111') //返回結果1 }else{ console.log('222') //返回結果2 } }
a和b是不變的,那麼不管執行多少次,結果都是不變的,可是每一次都要執行if判斷語句,這樣就形成了資源浪費。
而惰性載入函數,即可以解決這個問題。
function foo(){ if(a != b){ foo = function(){ console.log('111') } }else{ foo = function(){ console.log('222') } } return foo(); }
var foo = (function foo(){ if(a != b){ return function(){ console.log('111') } }else{ return function(){ console.log('222') } } })();
如上函數所示:第一次執行後便會對foo進行賦值,覆蓋以前的函數,因此再次執行,便不會在執行if判斷語句。
fun.bind(thisarg[,arg1[,arg2[,....]]])綁定函數
thisarg:當綁定函數被調用時,該參數會做爲原函數運行時的this指向。當使用new時,該參數無效。
arg:當綁定時,這些參數將傳遞給被綁定的方法。
例子:
let person = { name: 'addone', click: function(e){ console.log(this.name) } } let btn = document.getElementById('btn'); EventUtil.addHandle(btn, 'click', person.click);
這裏建立了一個person對象,而後將person.click方法分配給DOM,可是當你按按鈕時,會打印undefied,緣由是this指向了DOM而不是person。
解決方法,當時是使用綁定函數了:
EventUtil.addHandle(btn, 'click', person.click.bind(person));
函數柯里化
柯里化是把接受多個參數的函數轉變成接受單一參數的函數。
//簡單例子,方便你明白柯里化 function add(num1, num2){ return num1 + num2; } function curryAdd(num2){ return add(1, num2); } add(2, 3) // 5 curryAdd(2) // 3
下面是柯里化函數的通用方法:
function curry(fn){ var args = Array.prototype.slice.call(arguments, 1); return function(){ let innerArgs = Array.prototype.slice.call(arguments); let finalArgs = args.concat(innerArgs); return fn.apply(null, finalArgs); } }
Array.prototype.slice.call(arguments, 1)來獲取第一個參數後的全部參數。在函數中,一樣調用 Array.prototype.slice.call(arguments)讓innerArgs存放全部的參數, 而後用contact將內部外部參數組合起來,用apply傳遞函數。
function add(num1, num2){ return num1 + num2; } let curryAdd1 = curry(add, 1); curryAdd1(2); // 3 let curryAdd2 = curry(add, 1, 2); curryAdd2(); // 3
不可擴展對象
默認狀況下對象都是可擴展的,不管是擴展屬性或是方法。
let dog = { name: '柴犬' };
dog.age = 5;
如第二行,咱們爲dog擴展了age屬性。
使用Object.preventExtensions()能夠阻止擴展行爲。
let dog = { name: '柴犬' }; Object.preventExtensions(dog); dog.age = 20; dog.age // undefined
還可使用 Object.isExtensible()來判斷對象是否支持擴展。
let dog = { name: 'addone' }; Object.isExtensible(dog); // true Object.preventExtensions(dog); Object.isExtensible(dog); // false。
密封的對象
密封后的對象不可擴展,且不能刪除屬性和方法。
使用Object.seal()來進行密封。
let dog = { name: '柴犬' }; Object.seal(dog); dog.age = 20; delete dog.name; dog.age // undefined dog.name // 柴犬
固然也有Object.isSealed()來判斷是否密封
let dog = { name: '柴犬' }; Object.isExtensible(dog); // true Object.isSealed(dog); // false Object.seal(dog); Object.isExtensible(dog); // false Object.isSealed(dog); // true
凍結對象
凍結對象爲防篡改級別最高的,密封,且不能修改。
使用Object.freeze()來進行凍結。
let dog= { name: '柴犬' }; Object.freeze(dog); dog.age = 20; delete dog.name; dog.name = '吉娃娃' dog.age // undefined dog.name // 柴犬
固然也有Object.isFrozen()來判斷是否凍結
let dog = { name: '柴犬' }; Object.isExtensible(dog); // true Object.isSealed(dog); // false Object.isFrozen(dog); // false Object.freeze(dog); Object.isExtensible(dog); // false Object.isSealed(dog); // true Object.isFrozen(dog); // true
數組分塊
瀏覽器對長時間運行的腳本進行了制約,若是運行時間超過特定時間或者特定長度,便不會繼續執行。
若是發現某個循環佔用了大量的時間,那麼就要面對下面兩個問題:
1.該循環是否必須同步完成?
2.數據是否必須按順序完成?
若是是否,那麼咱們可使用一種叫作數組分塊的技術。基本思路是爲要處理的項目建立一個列隊,而後使用定時取出一個要處理的項目進行處理,以此類推。
function chunk(array, process, context){ setTimeout(function(){ // 取出下一個項目進行處理 let item = array.shift(); process.call(item); if(array.length > 0){ setTimeout(arguments.callee, 100); } }, 100) }
這裏設置三個參數,要處理的數組,處理的函數,運行該函數的環境。
節流函數
節流函數目的是爲了防止某些操做執行的太快,好比onresize,touch等事件。這種高頻率的操做可能會使瀏覽器崩潰,爲了不這種狀況,能夠採用節流的方式。
function throttle(method, context){ clearTimeout(method.tId); method.tId = setTimeout(function(){ method.call(context); }, 100) }
這裏接收兩個參數,要執行的函數,和執行的環境。執行時先clear以前的定時器,而後將當前定時器賦值給方法的tId
,以後調用call
來肯定函數的執行環境。
function resizeDiv(){ let div = document.getElementById('div'); div.style.height = div.offsetWidth + "px"; } window.onresize = function(){ throttle(resizeDiv); }