欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

JS高級(jí)技巧(簡(jiǎn)潔版)

安全的類型檢測(cè)

創(chuàng)新互聯(lián)建站是一家專注于網(wǎng)站制作、成都網(wǎng)站制作與策劃設(shè)計(jì),嘉定網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)建站做網(wǎng)站,專注于網(wǎng)站建設(shè)十載,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:嘉定等地區(qū)。嘉定做網(wǎng)站價(jià)格咨詢:18982081108

JS內(nèi)置的類型檢測(cè)機(jī)制并不是完全可靠的

typeof

操作符返回一個(gè)字符串,表示未經(jīng)計(jì)算的操作數(shù)的類型,在大多數(shù)情況下很靠譜,但是當(dāng)然還有例外

正則表達(dá)式

typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1
typeof /s/ === 'object'; // Firefox 5+ , 符合 ECMAScript 5.1

NULL

typeof null === 'object'; // 從一開始出現(xiàn)JavaScript就是這樣的

在 JavaScript 最初的實(shí)現(xiàn)中,JavaScript 中的值是由一個(gè)表示類型的標(biāo)簽和實(shí)際數(shù)據(jù)值表示的。對(duì)象的類型標(biāo)簽是 0。由于 null 代表的是空指針(大多數(shù)平臺(tái)下值為 0x00),因此,null的類型標(biāo)簽也成為了 0,typeof null就錯(cuò)誤的返回了object

instanceof

運(yùn)算符用來測(cè)試一個(gè)對(duì)象在其原型鏈中是否存在一個(gè)構(gòu)造函數(shù)的 prototype 屬性

語法

object instanceof constructor(要檢測(cè)的對(duì)象 instanceof 構(gòu)造函數(shù))

但是在瀏覽器中,我們的腳本可能需要在多個(gè)窗口之間進(jìn)行交互。多個(gè)窗口意味著多個(gè)全局環(huán)境,不同的全局環(huán)境擁有不同的全局對(duì)象,從而擁有不同的內(nèi)置類型構(gòu)造函數(shù)。這可能會(huì)引發(fā)一些問題。

[] instanceof window.frames[0].Array    //false

因?yàn)?Array.prototype !== window.frames[0].Array.prototype,因此你必須使用 Array.isArray(myObj) 或者 Object.prototype.toString.call(myObj) === "[object Array]"來判斷myObj是否是數(shù)組
解決以上兩個(gè)問題的方案就是Object.prototype.toString

Object.prototype.toString

方法返回一個(gè)表示該對(duì)象的字符串
可以通過toString() 來獲取每個(gè)對(duì)象的類型。為了每個(gè)對(duì)象都能通過 Object.prototype.toString() 來檢測(cè),需要以 Function.prototype.call() 或者 Function.prototype.apply()的形式來調(diào)用,傳遞要檢查的對(duì)象作為第一個(gè)參數(shù),稱為thisArg

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]

//Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]

作用域安全的構(gòu)造函數(shù)

構(gòu)造函數(shù)其實(shí)就是一個(gè)使用new操作符調(diào)用的函數(shù)。當(dāng)使用new調(diào)用時(shí),構(gòu)造函數(shù)內(nèi)用到的this對(duì)象會(huì)指向新創(chuàng)建的對(duì)象實(shí)例

function Person(name, age){
  this.name = name;
  this.age = age;
}

let person = new Person("addone", 20);

person.name // addone

當(dāng)你使用new操作符的時(shí)候,就會(huì)創(chuàng)建一個(gè)新的Person對(duì)象,同時(shí)分配這些屬性,但是如果你沒有使用new

let person = Person("addone", 20);

person1.name // Cannot read property 'name' of undefined
window.name // addone

這是因?yàn)?code>this是在執(zhí)行時(shí)確認(rèn)的,當(dāng)你沒有使用new,那么this在當(dāng)前情況下就被解析成了window,屬性就被分配到window上了

作用域安全的構(gòu)造函數(shù)在進(jìn)行更改前,首先確認(rèn)this對(duì)象是正確類型的實(shí)例,如果不是,就創(chuàng)建新的對(duì)象并且返回

function Person(name, age){
  if(this instanceof Person){
    this.name = name;
    this.age = age;   
  }else{
    return new Person(name, age);
  }
}

let person1 = new Person("addone", 20);
person1.name // addone

let person2 = Person("addone", 20);
person2.name // addone

this instanceof Person檢查了this對(duì)象是不是Person的實(shí)例,如果是則繼續(xù),不是則調(diào)用new

惰性載入函數(shù)

假如你要寫一個(gè)函數(shù),里面有一些判斷語句

function foo(){
  if(a != b){
    console.log('aaa')
  }else{
    console.log('bbb')
  }
}

如果你的ab是不變的,那么這個(gè)函數(shù)不論執(zhí)行多少次,結(jié)果都是不變的,但是每次執(zhí)行還要進(jìn)行if判斷,這就造成了不必要的浪費(fèi)。

惰性載入表示函數(shù)執(zhí)行的分支只會(huì)發(fā)生一次,這里有兩種解決方式。

在函數(shù)被調(diào)用時(shí)再處理函數(shù)

function foo(){
  if(a != b){
    foo = function(){
      console.log('aaa')
    }
  }else{
    foo = function(){
      console.log('bbb')
    }
  }
  return foo();
}

這樣進(jìn)入每個(gè)分支后都會(huì)對(duì)foo進(jìn)行賦值,覆蓋了之前的函數(shù),之后每次調(diào)用foo就不會(huì)再執(zhí)行if判斷

在聲明函數(shù)時(shí)就指定適當(dāng)?shù)暮瘮?shù)

var foo = (function foo(){
  if(a != b){
    return function(){
      console.log('aaa')
    }
  }else{
    return function(){
      console.log('bbb')
    }
  }
})();

這里創(chuàng)建一個(gè)匿名,自執(zhí)行的函數(shù),用來確定應(yīng)該使用哪一個(gè)函數(shù)來實(shí)現(xiàn)。

惰性函數(shù)的優(yōu)點(diǎn)就是只在第一次執(zhí)行分支時(shí)犧牲一點(diǎn)點(diǎn)性能

函數(shù)綁定

請(qǐng)使用fun.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg

當(dāng)綁定函數(shù)被調(diào)用時(shí),該參數(shù)會(huì)作為原函數(shù)運(yùn)行時(shí)的 this 指向。當(dāng)使用new 操作符調(diào)用綁定函數(shù)時(shí),該參數(shù)無效

arg1,arg2,...

當(dāng)綁定函數(shù)被調(diào)用時(shí),這些參數(shù)將置于實(shí)參之前傳遞給被綁定的方法

返回

由指定的this值和初始化參數(shù)改造的原函數(shù)拷貝

一個(gè)例子

let person = {
  name: 'addone',
  click: function(e){
    console.log(this.name)
  }
}

let btn = document.getElementById('btn');
EventUtil.addHandle(btn, 'click', person.click);

這里創(chuàng)建了一個(gè)person對(duì)象,然后將person.click方法分配給DOM按鈕的事件處理程序,當(dāng)你點(diǎn)擊按按鈕時(shí),會(huì)打印出undefiend,原因是執(zhí)行時(shí)this指向了DOM按鈕而不是person

解決方案: 將this強(qiáng)行指向person

EventUtil.addHandle(btn, 'click', person.click.bind(person));

函數(shù)柯里化

函數(shù)柯里化是把接受多個(gè)參數(shù)的函數(shù)轉(zhuǎn)變成接受單一參數(shù)的函數(shù)

function add(num1, num2){
  return num1 + num2;
}
function curryAdd(num2){
  return add(1, num2);
}
add(2, 3) // 5
curryAdd(2) // 3

這個(gè)例子用來方便理解柯里化的概念

下面是創(chuàng)建函數(shù)柯里化的通用方式

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);
  }
}

第一個(gè)參數(shù)是要進(jìn)行柯里化的函數(shù),其他參數(shù)是要傳入的值。這里使用Array.prototype.slice.call(arguments, 1)來獲取第一個(gè)參數(shù)后的所有參數(shù)(外部)。在返回的函數(shù)中,同樣調(diào)用Array.prototype.slice.call(arguments)innerArgs來存放所有的參數(shù)(內(nèi)部),然后用concat將內(nèi)部外部參數(shù)組合,用apply傳遞給函數(shù)

function add(num1, num2){
  return num1 + num2;
}
let curryAdd1 = curry(add, 1);
curryAdd1(2); // 3

let curryAdd2 = curry(add, 1, 2);
curryAdd2(); // 3

防篡改對(duì)象

Javascript中任何對(duì)象都可以被同一環(huán)境中運(yùn)行的代碼修改,所以開發(fā)人員有時(shí)候需要定義防篡改對(duì)象(tamper-proof object) 來保護(hù)自己

不可擴(kuò)展對(duì)象

默認(rèn)情況下所有對(duì)象都是可以擴(kuò)展的(添加屬性和方法)

let person = { name: 'addone' };
person.age = 20;

第二行為person對(duì)象擴(kuò)展了age屬性,當(dāng)然你可以阻止這一行為,使用Object.preventExtensions()

let person = { name: 'addone' };
Object.preventExtensions(person);
person.age = 20;

person.age // undefined

你還可以用Object.isExtensible()來判斷對(duì)象是不是可擴(kuò)展的

let person = { name: 'addone' };
Object.isExtensible(person); // true

Object.preventExtensions(person);
Object.isExtensible(person); // false

請(qǐng)記住這是不可擴(kuò)展!!,即不能添加屬性或方法

密封的對(duì)象

密封對(duì)象不可擴(kuò)展,且不能刪除屬性和方法

let person = { name: 'addone' };
Object.seal(person);

person.age = 20;
delete person.name;

person.age // undefined
person.name // addone

相對(duì)的也有Object.isSealed()來判斷是否密封

let person = { name: 'addone' };
Object.isExtensible(person); // true
Object.isSealed(person); // false

Object.seal(person);
Object.isExtensible(person); // false
Object.isSealed(person); // true

凍結(jié)的對(duì)象

這是最嚴(yán)格的防篡改級(jí)別,凍結(jié)的對(duì)象即不可擴(kuò)展,又密封,且不能修改

let person = { name: 'addone' };
Object.freeze(person);

person.age = 20;
delete person.name;
person.name = 'addtwo'

person.age // undefined
person.name // addone

同樣也有Object.isFrozen來檢測(cè)

let person = { name: 'addone' };
Object.isExtensible(person); // true
Object.isSealed(person); // false
Object.isFrozen(person); // false

Object.freeze(person);
Object.isExtensible(person); // false
Object.isSealed(person); // true
Object.isFrozen(person); // true

以上三種方法在嚴(yán)格模式下進(jìn)行錯(cuò)誤操作均會(huì)導(dǎo)致拋出錯(cuò)誤

高級(jí)定時(shí)器

閱讀前提

大概理解setTimeout的基本執(zhí)行機(jī)制和js事件機(jī)制

重復(fù)的定時(shí)器

當(dāng)你使用setInterval重復(fù)定義多個(gè)定時(shí)器的時(shí)候,可能會(huì)出現(xiàn)某個(gè)定時(shí)器代碼在代碼再次被添加到執(zhí)行隊(duì)列之前還沒有完成執(zhí)行,導(dǎo)致定時(shí)器代碼連續(xù)執(zhí)行多次。

機(jī)智Javascript引擎解決了這個(gè)問題,使用setInterval()的時(shí)候,僅當(dāng)沒有該定時(shí)器的其他代碼實(shí)例時(shí),才會(huì)將定時(shí)器代碼添加到隊(duì)列中。但這還會(huì)導(dǎo)致一些問題:

  • 某些間隔被跳過
  • 間隔可能比預(yù)期的小

為了避免這個(gè)兩個(gè)問題,你可以使用鏈?zhǔn)?code>setTimeout()調(diào)用

setTimeout(function(){
  TODO();
  
  setTimeout(arguments.callee, interval);
}, interval)

arguments.callee獲取了當(dāng)前執(zhí)行函數(shù)的引用,然后為其設(shè)置另外一個(gè)定時(shí)器,這樣就確保在下一次定時(shí)器代碼執(zhí)行前,必須等待指定的間隔。

Yielding Processes

瀏覽器對(duì)長(zhǎng)時(shí)間運(yùn)行的腳本進(jìn)行了制約,如果代碼運(yùn)行超過特定的時(shí)間或者特定語句數(shù)量就不會(huì)繼續(xù)執(zhí)行。

如果你發(fā)現(xiàn)某個(gè)循環(huán)占用了大量的時(shí)間,那么對(duì)于下面這兩個(gè)問題

  • 該處理是否必須同步完成?
  • 數(shù)據(jù)是否必須按順序完成?

如果你的兩個(gè)答案都是"否",那么你可以使用一種叫做數(shù)組分塊(array chunking) 的技術(shù)?;舅悸肥菫橐幚淼捻?xiàng)目創(chuàng)建一個(gè)隊(duì)列,然后使用定時(shí)器取出下一個(gè)要出處理的項(xiàng)目進(jìn)行處理,然后再設(shè)置另一個(gè)定時(shí)器。

function chunk(array, process, context){
  setTimeout(function(){
    // 取出下一個(gè)項(xiàng)目進(jìn)行處理
    let item = array.shift();
    process.call(item);
    
    if(array.length > 0){
      setTimeout(arguments.callee, 100);
    }
  }, 100)
}

這里接受三個(gè)參數(shù),要處理的數(shù)組,處理的函數(shù),運(yùn)行該函數(shù)的環(huán)境(可選),這里設(shè)置間隔100ms是個(gè)效果不錯(cuò)的選擇

如果你一個(gè)函數(shù)需要50ms以上時(shí)間完成,那么最好看看能否將任務(wù)分割成一系列可以使用定時(shí)器的小任務(wù)

函數(shù)節(jié)流(Throttle)

節(jié)流的目的是防止某些操作執(zhí)行的太快。比如在調(diào)整瀏覽器大小的時(shí)候會(huì)出發(fā)onresize事件,如果在其內(nèi)部進(jìn)行一些DOM操作,這種高頻率的更愛可能會(huì)使瀏覽器崩潰。為了避免這種情況,可以采取函數(shù)節(jié)流的方式。

function throttle(method, context){
  clearTimeout(method.tId);
  method.tId = setTimeout(function(){
    method.call(context);
  }, 100)
}

這里接受兩個(gè)參數(shù),要執(zhí)行的函數(shù),執(zhí)行的環(huán)境。執(zhí)行時(shí)先清除之前的定時(shí)器,然后將當(dāng)前定時(shí)器賦值給方法的tId,之后調(diào)用call來確定函數(shù)的執(zhí)行環(huán)境。

一個(gè)應(yīng)用的例子

function resizeDiv(){
  let div = document.getElementById('div');
  div.style.height = div.offsetWidth + "px";
}

window.onresize = function(){
  throttle(resizeDiv);
}

這個(gè)就不用講了吧2333

文章參考于《JavaScript高級(jí)程序設(shè)計(jì)(第三版)》

如果你覺得我的理解有問題或者整理的太簡(jiǎn)略,那么我強(qiáng)烈安利你自己去讀一下這本書~

分享文章:JS高級(jí)技巧(簡(jiǎn)潔版)
分享地址:http://aaarwkj.com/article24/igjcje.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、商城網(wǎng)站關(guān)鍵詞優(yōu)化、定制網(wǎng)站網(wǎng)站策劃、域名注冊(cè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)
热久久这里只有精品网址| 国产三级传媒视频在线观看| 亚洲欧美丝袜清纯另类| 综合久久—本道中文字幕| 欧美国产一级二级三级| 免费人成视频在线观看不卡| 亚洲一区二区三区在线观看呢| 亚洲成av在线免费不卡| 男人的天堂免费看看av| 在线中文字幕日韩有码| 亚洲精品国产av一区| 99精品久久久中文字幕日本| 日韩精品电影一区在线观看| 美女午夜福利精品视频| 精品亚洲午夜久久久久| 久久精品人妻中文av| 日韩精品成人亚洲天堂| 亚洲视频在线的视频在| 久久精品一区二区熟女| 亚洲经典日韩欧美一区| 中文字幕人妻丝乱一区三区| 亚洲自偷精品视频自拍| 亚洲香蕉视频免费在线观看| 不卡免费av在线高清| 成人av在线播放亚洲| 国产一区日本二区欧美三区| 日本人妻丰满熟妇久久| 中文字幕一区免费视频| 欧美成人精品高清在线| 精品久久久久久亚洲电影| 狼人私人影院在线观看| 亚洲国产欲色有一二欲色| 日本女人体内射精视频| 麻豆一精品传二传媒短视频| 国产精品国产三级国产不产一地| 深夜福利视频一区二区| 精品免费av在线播放| 国产精品播放一区二区三区| 欧美国产日韩二区一区在线| 麻豆午夜福利在线播放| 色欧美一区二区三区在线|