亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

JS高級技巧(簡潔版)

2024-05-06 16:45:26
字體:
來源:轉載
供稿:網友

安全的類型檢測

JS內置的類型檢測機制并不是完全可靠的

typeof

操作符返回一個字符串,表示未經計算的操作數的類型,在大多數情況下很靠譜,但是當然還有例外

正則表達式

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

NULL

typeof null === 'object'; // 從一開始出現JavaScript就是這樣的

在 JavaScript 最初的實現中,JavaScript 中的值是由一個表示類型的標簽和實際數據值表示的。對象的類型標簽是 0。由于 null 代表的是空指針(大多數平臺下值為 0x00),因此,null的類型標簽也成為了 0,typeof null就錯誤的返回了object

instanceof

運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性

語法

object instanceof constructor(要檢測的對象 instanceof 構造函數)

但是在瀏覽器中,我們的腳本可能需要在多個窗口之間進行交互。多個窗口意味著多個全局環境,不同的全局環境擁有不同的全局對象,從而擁有不同的內置類型構造函數。這可能會引發一些問題。

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

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

Object.prototype.toString

方法返回一個表示該對象的字符串
可以通過toString() 來獲取每個對象的類型。為了每個對象都能通過 Object.prototype.toString() 來檢測,需要以 Function.prototype.call() 或者 Function.prototype.apply()的形式來調用,傳遞要檢查的對象作為第一個參數,稱為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.5toString.call(undefined); // [object Undefined]toString.call(null); // [object Null]

作用域安全的構造函數

構造函數其實就是一個使用new操作符調用的函數。當使用new調用時,構造函數內用到的this對象會指向新創建的對象實例

function Person(name, age){  this.name = name;  this.age = age;}let person = new Person("addone", 20);person.name // addone

當你使用new操作符的時候,就會創建一個新的Person對象,同時分配這些屬性,但是如果你沒有使用new

let person = Person("addone", 20);person1.name // Cannot read property 'name' of undefinedwindow.name // addone

這是因為this是在執行時確認的,當你沒有使用new,那么this在當前情況下就被解析成了window,屬性就被分配到window上了

作用域安全的構造函數在進行更改前,首先確認this對象是正確類型的實例,如果不是,就創建新的對象并且返回

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 // addonelet person2 = Person("addone", 20);person2.name // addone

this instanceof Person檢查了this對象是不是Person的實例,如果是則繼續,不是則調用new

惰性載入函數

假如你要寫一個函數,里面有一些判斷語句

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

如果你的ab是不變的,那么這個函數不論執行多少次,結果都是不變的,但是每次執行還要進行if判斷,這就造成了不必要的浪費。

惰性載入表示函數執行的分支只會發生一次,這里有兩種解決方式。

在函數被調用時再處理函數

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

這樣進入每個分支后都會對foo進行賦值,覆蓋了之前的函數,之后每次調用foo就不會再執行if判斷

在聲明函數時就指定適當的函數

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

這里創建一個匿名,自執行的函數,用來確定應該使用哪一個函數來實現。

惰性函數的優點就是只在第一次執行分支時犧牲一點點性能

函數綁定

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

thisArg

當綁定函數被調用時,該參數會作為原函數運行時的 this 指向。當使用new 操作符調用綁定函數時,該參數無效

arg1,arg2,...

當綁定函數被調用時,這些參數將置于實參之前傳遞給被綁定的方法

返回

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

一個例子

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按鈕的事件處理程序,當你點擊按按鈕時,會打印出undefiend,原因是執行時this指向了DOM按鈕而不是person

解決方案: 將this強行指向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) // 5curryAdd(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來存放所有的參數(內部),然后用concat將內部外部參數組合,用apply傳遞給函數

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

防篡改對象

Javascript中任何對象都可以被同一環境中運行的代碼修改,所以開發人員有時候需要定義防篡改對象(tamper-proof object) 來保護自己

不可擴展對象

默認情況下所有對象都是可以擴展的(添加屬性和方法)

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

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

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

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

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

請記住這是不可擴展!!,即不能添加屬性或方法

密封的對象

密封對象不可擴展,且不能刪除屬性和方法

let person = { name: 'addone' };Object.seal(person);person.age = 20;delete person.name;person.age // undefinedperson.name // addone

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

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

凍結的對象

這是最嚴格的防篡改級別,凍結的對象即不可擴展,又密封,且不能修改

let person = { name: 'addone' };Object.freeze(person);person.age = 20;delete person.name;person.name = 'addtwo'person.age // undefinedperson.name // addone

同樣也有Object.isFrozen來檢測

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

以上三種方法在嚴格模式下進行錯誤操作均會導致拋出錯誤

高級定時器

閱讀前提

大概理解setTimeout的基本執行機制和js事件機制

重復的定時器

當你使用setInterval重復定義多個定時器的時候,可能會出現某個定時器代碼在代碼再次被添加到執行隊列之前還沒有完成執行,導致定時器代碼連續執行多次。

機智Javascript引擎解決了這個問題,使用setInterval()的時候,僅當沒有該定時器的其他代碼實例時,才會將定時器代碼添加到隊列中。但這還會導致一些問題:

  • 某些間隔被跳過
  • 間隔可能比預期的小

為了避免這個兩個問題,你可以使用鏈式setTimeout()調用

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

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

Yielding Processes

瀏覽器對長時間運行的腳本進行了制約,如果代碼運行超過特定的時間或者特定語句數量就不會繼續執行。

如果你發現某個循環占用了大量的時間,那么對于下面這兩個問題

  • 該處理是否必須同步完成?
  • 數據是否必須按順序完成?

如果你的兩個答案都是"否",那么你可以使用一種叫做數組分塊(array chunking) 的技術。基本思路是為要處理的項目創建一個隊列,然后使用定時器取出下一個要出處理的項目進行處理,然后再設置另一個定時器。

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

這里接受三個參數,要處理的數組,處理的函數,運行該函數的環境(可選),這里設置間隔100ms是個效果不錯的選擇

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

函數節流(Throttle)

節流的目的是防止某些操作執行的太快。比如在調整瀏覽器大小的時候會出發onresize事件,如果在其內部進行一些DOM操作,這種高頻率的更愛可能會使瀏覽器崩潰。為了避免這種情況,可以采取函數節流的方式。

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

這里接受兩個參數,要執行的函數,執行的環境。執行時先清除之前的定時器,然后將當前定時器賦值給方法的tId,之后調用call來確定函數的執行環境。

一個應用的例子

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

這個就不用講了吧2333

文章參考于《JavaScript高級程序設計(第三版)》

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


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲国产中文字幕久久网| 国产精品自拍小视频| 亚洲精品www久久久| 欧美成人sm免费视频| 6080yy精品一区二区三区| 欧美中文在线视频| 久久99亚洲精品| 97在线免费观看| 日韩中文有码在线视频| 日本精品久久久| 91久久精品美女高潮| 欧美极品在线播放| 国产一区二区丝袜高跟鞋图片| 亚洲国产日韩欧美综合久久| 97色在线观看| www.99久久热国产日韩欧美.com| 国产激情999| 亚洲视频在线观看视频| 精品国产欧美一区二区五十路| 亚洲激情免费观看| 日韩欧美在线免费| 国产福利成人在线| 亚洲国产第一页| 日韩美女av在线免费观看| 国产成人激情小视频| 欧美精品在线免费观看| 亚洲人成在线观| 福利视频导航一区| 亚洲日本欧美中文幕| 久久香蕉国产线看观看网| 久久亚洲国产精品| 国产在线一区二区三区| 亚洲欧美一区二区三区情侣bbw| 亚洲综合中文字幕在线| 91午夜在线播放| 色老头一区二区三区| 久久久久久久久国产| 亚洲欧美国产精品va在线观看| 亚洲人成网站999久久久综合| 91久久久国产精品| 欧美最猛性xxxxx亚洲精品| 日韩女优在线播放| 日韩av电影在线免费播放| 性欧美亚洲xxxx乳在线观看| 国产精品99蜜臀久久不卡二区| 亚洲一区二区三区视频| 91九色精品视频| 亚洲美女喷白浆| 国产精品爱啪在线线免费观看| 国产精品久久久久久亚洲影视| 精品国模在线视频| 欧美高清理论片| 亚洲自拍欧美另类| 国产精品美女主播在线观看纯欲| 亚洲欧美激情四射在线日| 色婷婷久久av| 国产精品久久综合av爱欲tv| 中文字幕一区电影| 热久久视久久精品18亚洲精品| 亚洲精选在线观看| 激情av一区二区| 亚洲欧洲成视频免费观看| 欧美精品在线免费播放| 在线观看视频99| 日韩国产高清污视频在线观看| 曰本色欧美视频在线| 久久久免费电影| 成人国产精品久久久久久亚洲| 精品久久久一区二区| 2018国产精品视频| 国产在线视频91| 国外视频精品毛片| 日韩欧美在线免费观看| 成人精品视频久久久久| 亚洲精选中文字幕| 亚洲美女性视频| 日韩毛片中文字幕| 国产精品欧美激情在线播放| 45www国产精品网站| 日韩欧美国产激情| 国产精品精品视频| 国产成人综合精品在线| 性色av一区二区三区| 日本精品久久久久影院| 色综合老司机第九色激情| 亚洲v日韩v综合v精品v| 色综合久综合久久综合久鬼88| 国产精品福利网| 久久久久久免费精品| 久久在线精品视频| 国产欧美日韩精品丝袜高跟鞋| 国产精品成人av性教育| 欧美在线观看网址综合| 一色桃子一区二区| 亚洲欧美日韩国产中文| 亚洲福利在线播放| 久久精品99久久久香蕉| 91久久精品美女高潮| 国产精品69久久| 亚洲国产日韩精品在线| 久久伊人精品视频| 国产精品扒开腿做爽爽爽男男| 成人网中文字幕| 九九热这里只有精品6| 国产91在线视频| 欧美午夜视频在线观看| 国产精品黄页免费高清在线观看| 久久精品国产久精国产一老狼| 亚洲天堂网在线观看| 国产精品男女猛烈高潮激情| 91精品国产乱码久久久久久蜜臀| 国产在线视频不卡| 亚洲最大福利视频网站| 欧美大秀在线观看| 欧美亚洲日本黄色| 久久久免费观看| 欧美电影院免费观看| 欧美极品少妇xxxxx| 色噜噜狠狠色综合网图区| 亚洲人成网站777色婷婷| 国产精品99久久久久久久久久久久| 欧美在线一区二区三区四| 久久99久国产精品黄毛片入口| 成人精品在线观看| 国产午夜精品一区二区三区| 亚洲大尺度美女在线| 日产精品久久久一区二区福利| 国产日韩欧美中文在线播放| 国产精品视频免费在线| 国产精品福利在线观看网址| 91国产一区在线| 亚洲女人天堂视频| **欧美日韩vr在线| 欧美日韩中国免费专区在线看| 青青久久aⅴ北条麻妃| 国产欧美日韩丝袜精品一区| 国产精品成久久久久三级| 色综合色综合网色综合| 91精品国产色综合久久不卡98| 国产成人av在线播放| 久久久久久久久久久人体| 免费91麻豆精品国产自产在线观看| 久久久久久久久久av| 韩国一区二区电影| 日韩欧美中文第一页| 亚洲tv在线观看| 岛国av在线不卡| 欧美一性一乱一交一视频| 欧美成年人在线观看| 日韩一区二区三区在线播放| 日韩欧美国产中文字幕| 国产噜噜噜噜噜久久久久久久久| 日韩av不卡电影| 日韩免费视频在线观看| 中文欧美日本在线资源| 欧美一级免费视频| 国产精品一区二区三区在线播放| 久久天天躁夜夜躁狠狠躁2022| 欧美性生交xxxxx久久久| 亚洲国产欧美日韩精品| 久久婷婷国产麻豆91天堂| 亚洲wwwav| 欧美老少配视频| 免费91麻豆精品国产自产在线观看|