JavaScript小技巧介紹

HarrisonMay 8年前發布 | 40K 次閱讀 JavaScript開發 JavaScript

來自: http://www.cnblogs.com/ys-ys/p/5158510.html

感謝好友破狼提供的這篇好文章,也感謝寫這些知識點的作者們和將他們整理到一起的作者。這是github上的一篇文章,在這里本獸也就只做翻譯,由于本獸英語水平和編程能力都不咋地,如有不好的地方也請多理解體諒。 原文

能夠為大家提供這些簡短而實用的JavaScript技巧來提高大家編程能力,這對于我來說是件很開心的事。每天僅花上不到2分鐘的時間中,你將可以讀遍JavaScript這門可怕的語言所呈現給我們的特性:performance(性能), conventions(協議), hacks(代碼hack), interview questions(面試問題)及所有其他的項。

#24 - 使用 === 代替 ==

==(或者!=)做對比的時候會將進行對比的兩者轉換到同一類型再比較。===(或者!==)則不會,他會將進行對比的兩者做類型對比和值對比,相對于 == ,=== 的對比會更加嚴謹。

[10] == 10     // true
[10] === 10    // false
"10" == 10     // true
"10" === 10    // false
[] == 0        // true
[] === 0       // false
"" == false    // true 但是 true == "a" 是false
"" === false   // false

#23 - 轉換數值的更加的方法

將字符串轉換為數字是非常常見的。最簡單和最快的( jspref )的方式來實現,將使用+(加)算法。

</div>

var one = '1';
var numberOne = +one; // Number 1

你也可以使用-(減號)算法的轉換類型并且變成負數值。

var one = '1';
var negativeNumberOne = -one; // Number -1

#22 - 清空一個數組

你定義一個數組,并希望清空它的內容。通常,你會這樣做:

</div>

var list = [1, 2, 3, 4];
function empty() {
    //清空數組
    list = [];
}
empty();

但是還有一種更高性能的方法。你可以使用這些代碼:

var list = [1, 2, 3, 4];
function empty() {
    //清空數組
    list.length = 0;
}
empty();

·list = [] 將一個變量指定個引用到那個數組,而其他引用都不受影響。這意味著,對于先前數組的內容的引用仍然保留在內存中,從而導致內存泄漏。

·list.length = 0 刪除數組內的所有東西,這不需要引用任何其他的東西

然而,如果你有一個copy的數組(A和copy-A),如果你使用list.length = 0 刪除其內容,副本也會失去它的內容。

</div>

var foo = [1,2,3];
var bar = [1,2,3];
var foo2 = foo;
var bar2 = bar;
foo = [];
bar.length = 0;
console.log(foo, bar, foo2, bar2);
//[] [] [1, 2, 3] []

StackOverflow上的更多詳情: difference-between-array-length-0-and-array

#21 - 對數組排序進行"洗牌"(隨機排序)

這段代碼在這里使用Fisher Yates洗牌算法給一個指定的數組進行洗牌(隨機排序)。

function shuffle(arr) {
    var i,
        j,
        temp;
    for (i = arr.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1));
        temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    return arr;    
};

案例:

var a = [1, 2, 3, 4, 5, 6, 7, 8];
var b = shuffle(a);
console.log(b);
// [2, 7, 8, 6, 5, 3, 1, 4]

#20 - 返回對象的函數能夠用于鏈式操作

當創建面向對象的JavaScript對象的function時,函數返回一個對象將能夠讓函數可鏈式的寫在一起來執行。

</div>

function Person(name) {
  this.name = name;
  this.sayName = function() {
    console.log("Hello my name is: ", this.name);
    return this;
  };
  this.changeName = function(name) {
    this.name = name;
    return this;
  };
}
var person = new Person("John");
person.sayName().changeName("Timmy").sayName();
//Hello my name is:  John
//Hello my name is:  Timmy

#19 - 字符串安全連接

假設你有一些類型未知的變量,你想將它們連接起來。可以肯定的是,算法操作不會在級聯時應用:

</div>

var one = 1;
var two = 2;
var three = '3';
var result = ''.concat(one, two, three); //"123"

這樣的連接不正是你所期望的。相反,一些串聯和相加可能會導致意想不到的結果:

var one = 1;
var two = 2;
var three = '3';
var result = one + two + three; //"33"  而不是 "123"

談到性能,對join和concat進行比較,他們的執行速度是幾乎一樣的。你可以在 MDN 了解更多與concat相關的知識

#18 - 更快的四舍五入

今天的技巧是關于性能。見到過雙波浪線"~~"操作符嗎?它有時也被稱為double NOT運算符。你可以更快的使用它來作為Math.floor()替代品。為什么呢?

單位移~將32位轉換輸入-(輸入+1),因此雙位移將輸入轉換為-(-(輸入+1)),這是個趨于0的偉大的工具。對于輸入的數字,它將模仿Math.ceil()取負值和Math.floor()取正值。如果執行失敗,則返回0,這可能在用來代替Math.floor()失敗時返回一個NaN的時候發揮作用。

// 單位移
console.log(~1337)    // -1338
// 雙位移
console.log(~~47.11)  // -> 47
console.log(~~-12.88) // -> -12
console.log(~~1.9999) // -> 1
console.log(~~3)      // -> 3
//失敗的情況
console.log(~~[]) // -> 0 
console.log(~~NaN)  // -> 0
console.log(~~null) // -> 0
//大于32位整數則失敗
console.log(~~(2147483647 + 1) === (2147483647 + 1)) // -> 0

雖然~~可能有更好的表現,為了可讀性,請使用Math.floor()。

#17 - Node.js:讓module在沒被require的時候運行

在node里,你可以根據代是運行了require('./something.js')還是node something.js,來告訴你的程序去做兩件不同的事情。如果你想與你的一個獨立的模塊進行交互,這是很有用的。

if (!module.parent) {
    // 運行 `node something.js`
    app.listen(8088, function() {
        console.log('app listening on port 8088');
    })
} else {
    // 使用 `require('/.something.js')`
    module.exports = app;
}

更多信息,請看 the documentation for modules

#16 - 給回調函數傳遞參數

在默認情況下,你無法將參數傳給回調函數,如下:

function callback() {
  console.log('Hi human');
}
document.getElementById('someelem').addEventListener('click', callback);

你可以采取JavaScript閉包的優點來給回調函數傳參,案例如下:

function callback(a, b) {
  return function() {
    console.log('sum = ', (a+b));
  }
}
var x = 1, y = 2;
document.getElementById('someelem').addEventListener('click', callback(x, y));

什么是閉包呢?閉包是指一個針對獨立的(自由)變量的函數。換句話說,閉包中定義的函數會記住它被創建的環境。了解更多請參閱 MDN 所以這種方式當被調用的時候,參數X/Y存在于回調函數的作用域內。

另一種方法是使用綁定方法。例如:

</div>

var alertText = function(text) {
  alert(text);
};
document.getElementById('someelem').addEventListener('click', alertText.bind(this, 'hello'));

兩種方法在性能上有一些略微區別,詳情參閱 jsperf

#15 - 使用更簡單的類似indexOf的包含判斷方式

原生的JavaScript沒有contains方法。對檢查字符串或字符串數組項中是否存在某值,你可以這樣做:

var someText = 'JavaScript rules';
if (someText.indexOf('JavaScript') !== -1) {
}
// 或者
if (someText.indexOf('JavaScript') >= 0) {
}

但是我們再看看這些ExpressJs代碼片段。

// examples/mvc/lib/boot.js
for (var key in obj) {
  // "reserved" exports
  if (~['name', 'prefix', 'engine', 'before'].indexOf(key)) continue;

// examples/lib/utils.js exports.normalizeType = function(type){ return ~type.indexOf('/') ? acceptParams(type) : { value: mime.lookup(type), params: {} }; };

// examples/web-service/index.js // key is invalid if (!~apiKeys.indexOf(key)) return next(error(401, 'invalid api key'));</pre>

問題是~位運算符。"運算符執行操作這樣的二進制表達式,但他們返回標準的JavaScript的數值."他們將-1轉換為0,而0在JavaScript中又是false。

var someText = 'text';
!!~someText.indexOf('tex'); // someText 包含 "tex" - true
!~someText.indexOf('tex'); // someText 不包含 "tex" - false
~someText.indexOf('asd'); // someText 不包含 "asd" - false
~someText.indexOf('ext'); // someText 包含 "ext" - true

String.prototype.includes()</pre>

在ES6(ES 2015)中介紹了includes()方法可以用來確定是否一個字符串包含另一個字符串:

'something'.includes('thing'); // true

在ECMAScript 2016 (ES7)中,甚至數組都可以這樣操作,如indexOf:

!!~[1, 2, 3].indexOf(1); // true
[1, 2, 3].includes(1); // true

不幸的是,這只是在Chrome,Firefox,Safari 9或以上的瀏覽器中被支持。

#14 - arrow 函數(ES6)

介紹下ES6里的新功能,arrow函數可能會是個很方便的工具,用更少行數寫更多代碼。他的名字來源于他的語法,=>和小箭頭->比就像一個“胖胖的箭頭”。可能有些人知道,這種函數類型和其他靜態語言如lambda表達式的匿名函數。它被稱為匿名,因為這些箭頭函數沒有一個描述性的函數名。

那么這樣有什么好處呢?

語法:更少的LOC,不用一次次的鍵入函數關鍵字。

語義:從上下文中捕捉關鍵字this。

簡單語法案例:

看看下面的兩段代碼片段,他們做的是一樣的工作。你能很快的理解arrow函數的功能。

// arrow函數的日常語法
param => expression
// 可能也會寫在括號中
// 括號是多參數要求
(param1 [, param2]) => expression

// 使用日常函數 var arr = [5,3,2,9,1]; var arrFunc = arr.map(function(x) { return x * x; }); console.log(arr)

// 使用arrow函數 var arr = [5,3,2,9,1]; var arrFunc = arr.map((x) => x*x); console.log(arr)</pre>

正如你所看到的,這個例子中的arrow函數可以節省你輸入括號內參數和返回關鍵字的時間。建議把圓括號內的參數輸入,如 (x,y) => x+y 。在不同的使用情況下,它只是

用來應對遺忘的一種方式。但是上面的代碼也會這樣執行:x => x*x.目前看來,這些僅僅是導致更少的LOC和更好的可讀性的句法改進。

this 綁定

還有一個更好的理由使用arrow函數。那就是在會出現this問題的背景下。使用arrow函數,你就不用擔心.bind(this)和 that=this 了。因為arrow函數會從上下文中找到this。

看下面的例子:

// 全局定義this.i
this.i = 100;
var counterA = new CounterA();
var counterB = new CounterB();
var counterC = new CounterC();
var counterD = new CounterD();

// 不好的示例 function CounterA() { // CounterA's this 實例 (!! 忽略這里) this.i = 0; setInterval(function () { // this 指全局對象,而不是 CounterA's this // 因此,開始計數與100,而不是0 (本地的 this.i) this.i++; document.getElementById("counterA").innerHTML = this.i; }, 500); } // 手動綁定 that = this function CounterB() { this.i = 0; var that = this; setInterval(function() { that.i++; document.getElementById("counterB").innerHTML = that.i; }, 500); } // 使用 .bind(this) function CounterC() { this.i = 0; setInterval(function() { this.i++; document.getElementById("counterC").innerHTML = this.i; }.bind(this), 500); } // 使用 arrow函數 function CounterD() { this.i = 0; setInterval(() => { this.i++; document.getElementById("counterD").innerHTML = this.i; }, 500); }</pre>

關于arrow函數的進一步信息可以看 這里 。查看不同的語法選請訪問該 站點

#13 - 測量一個JavaScript代碼塊性能的技巧

快速測量一個JavaScript塊的性能,我們可以使用控制臺的功能像console.time(label)和console.timeEnd(label)

console.time("Array initialize");
var arr = new Array(100),
    len = arr.length,
    i;
for (i = 0; i < len; i++) {
    arr[i] = new Object();
};
console.timeEnd("Array initialize"); // 輸出: Array initialize: 0.711ms

更多信息 Console object , JavaScript benchmarking

demo: jsfiddle-codepen (在瀏覽器控制臺輸出)

</div>

#12 - ES6中參數處理

在許多編程語言中,函數的參數是默認的,而開發人員必須顯式定義一個參數是可選的。在JavaScript中的每個參數是可選的,但我們可以這一行為而不讓一個函數利用 ES6的默認值 作為參數。

const _err = function( message ){
  throw new Error( message );
}
const getSum = (a = _err('a is not defined'), b = _err('b is not defined')) => a + b
getSum( 10 ) // throws Error, b is not defined
getSum( undefined, 10 ) // throws Error, a is not defined

_err是立即拋出一個錯誤的函數。如果沒有一個參數作為值,默認值是會被使用,_err將被調用,將拋出錯誤。你可以在Mozilla開發者網絡看到的更多默認參數的例子。

#11 - 提升

理解 提升 將幫助你組織你的function。只需要記住,變量聲明和定義函數會被提升到頂部。變量的定義是不會的,即使你在同一行中聲明和定義一個變量。此外,變量聲明讓系統知道變量存在,而定義是將其賦值給它。

function doTheThing() {
  // 錯誤: notDeclared is not defined
  console.log(notDeclared);
  // 輸出: undefined
  console.log(definedLater);
  var definedLater;
  definedLater = 'I am defined!'
  // 輸出: 'I am defined!'
  console.log(definedLater)
  // Outputs: undefined
  console.log(definedSimulateneously);
  var definedSimulateneously = 'I am defined!'
  // 輸出: 'I am defined!'
  console.log(definedSimulateneously)
  // 輸出: 'I did it!'
  doSomethingElse();
  function doSomethingElse(){
    console.log('I did it!');
  }
  // 錯誤: undefined is not a function
  functionVar();
  var functionVar = function(){
    console.log('I did it!');
  }
}

為了使事情更容易閱讀,在函數作用域內提升變量的聲明將會讓你明確該變量的聲明是來自哪個作用域。在你需要使用變量之前定義它們。在作用域底部定義函數,確保代碼清晰規范。

#10 - 檢查一個對象是否有屬性

當你要檢查一個對象是否存在某個屬性時, 你可能會這樣做

var myObject = {
  name: '@tips_js'
};
if (myObject.name) { ... }

這是可以的,但你必須知道這個還有兩原生的方式, in operatorobject.hasownproperty ,每個對象是對象,既可用方法。每個object都繼承自Object,這兩個方法都可用。

兩個方法的一些不同點:

</div>

var myObject = {
  name: '@tips_js'
};
myObject.hasOwnProperty('name'); // true
'name' in myObject; // true
myObject.hasOwnProperty('valueOf'); // false, valueOf 是從原型鏈繼承的
'valueOf' in myObject; // true

他們之間的不同在于檢查的性質,換句話說,當該對象本身有查找的屬性時hasOwnProperty返回yrue,然而,in operator不區分屬性創建的對象和屬性繼承的原型鏈。這里有另外一個例子:

var myFunc = function() {
  this.name = '@tips_js';
};
myFunc.prototype.age = '10 days';
var user = new myFunc();
user.hasOwnProperty('name'); // true
user.hasOwnProperty('age'); // false, 因為age是原型鏈上的

點擊看 例子 。同時,建議在檢查對象的屬性存在時,閱讀這些有關的 常見錯誤

#09 - 模板字符串

截至ES6,JS已經有模板字符串作為替代經典的結束引用的字符串。

案例:普通字符串

var firstName = 'Jake';
var lastName = 'Rawr';
console.log('My name is ' + firstName + ' ' + lastName);
// My name is Jake Rawr

模板字符串:

var firstName = 'Jake';
var lastName = 'Rawr';
console.log(`My name is ${firstName} ${lastName}`);
// My name is Jake Rawr

在模板字符串中${}中,你可以寫不用寫/n或者簡單邏輯來實現多行字符串。

您還可以使用函數來修改模板字符串的輸出,它們被稱為 模板字符串的標記 。你可能還想讀到更多的理解模板字符串 相關信息

</div>

#08 - 將節點列表轉換為數組

querySelectorAll 方法返回一個和數組類似的節點列表對象。這些數據結構類似數組,因為經常以數組形式出現,但是又不能用數組的方法,比如map和foreach。這里是一個快速、安全、可重用的方式將一個節點列表到一個DOM元素數組:

const nodelist = document.querySelectorAll('div');
const nodelistToArray = Array.apply(null, nodelist);
//later on ..
nodelistToArray.forEach(...);
nodelistToArray.map(...);
nodelistToArray.slice(...);
//etc...

apply方法是將一系列數組格式的參數傳遞給一個給定this的函數。MDN指出,apply將會調用類似數組的對象,而這正是querySelectorAll所返回的。因為我們不需要在函數的上下文中指定this,所以我們傳入null或0。返回的結果是一組能使用數組方法的DOM元素數組。

如果你使用的是es2015可以利用...( spread operator )

const nodelist = [...document.querySelectorAll('div')]; // 返回的是個真實的數組
//later on ..
nodelist.forEach(...);
nodelist.map(...);
nodelist.slice(...);
//etc...

#07 - "use strict" 和懶惰

嚴格模式的JavaScript讓開發人員更加安全的編寫JavaScript。

默認情況下,JavaScript允許開發者懶惰,例如,我們在第一次聲明變量的時候可以不用var,雖然這可能看起來像一個沒有經驗的開發人員,同時這也是很多錯誤的根源,變量名拼寫錯誤或意外地將它提到了外部作用域。

</div>

程序員喜歡讓電腦為我們做些無聊的事,檢查一些我們工作的錯誤。"use strict"指令我們做這些,將我們的錯誤轉換成JavaScript的錯誤。我們把這個指令可以通過添加在一個js文件的頂部:

// 整個script文件都將是嚴格模式語法
"use strict";
var v = "Hi!  I'm a strict mode script!";
或者在函數內:
function f()
{
// 函數范圍內的嚴格模式語法
  'use strict';
  function nested() { return "And so am I!"; }
  return "Hi!  I'm a strict mode function!  " + nested();
}
function f2() { return "I'm not strict."; }

在包含這個指令的JavaScript文件或者函數內,我們將一些較大的JavaScript項目中的不良行為直接在JavaScript引擎執行中禁止了。在其他情況中,嚴格模式改變以下的行為:

·變量只有在前面 var 聲明了才能用

·試圖寫入只讀屬性產生的誤差

·必須用 new 關鍵字調用構造函數

·this 不會默認指向全局對象

·非常有限的使用eval()

·保護保留字符或未來保留字符不被作為變量名使用

嚴格模式在新項目中是很有好處的,但是在大多數地方沒使用到它的老項目里使用它是非常具有挑戰性的。當你把多個文件合并到一個文件時,它也是個問題,就像可能導致整個文件都在嚴格模式下執行。

它不是一個聲明,只是一個字面量,早期版本的瀏覽器會忽略它。嚴格模式支持:

·IE 10+

·FF 4+

·Chrome 13+

·Safari 5.1+

·Opera 12+

參閱MDN對于 嚴格模式 的描述。

</div>

#06 - 處理一個數組或單個元素作為參數的方法

相比于寫個單獨的方法去分別操作一個數組和一個元素作為參數的函數,更好的是寫一個通用的函數,這樣就都可以操作。這類似于一些jQuery的方法(css匹配將修改所有的選擇器)。

你僅需要先將一切放進數組,Array.concat會接收數組或單一的對象:

function printUpperCase(words) {
  var elements = [].concat(words);
  for (var i = 0; i < elements.length; i++) {
    console.log(elements[i].toUpperCase());
  }
}

printUpperCase現在可以接收無論單一的元素作為參數還是一個數組:

printUpperCase("cactus");
// => CACTUS
printUpperCase(["cactus", "bear", "potato"]);
// => CACTUS
//  BEAR
//  POTATO

#05 - undefined 和 null 的不同

·undefined指的是一個變量未被聲明,或者一個變量被聲明但未賦值

·null是指一個特定的值,即"沒有值"

.JavaScript給未賦值的變量默認定義為undefined

·JavaScript不會給未賦值的變量設置null值,它被程序員用來表示一個無價值的值

·undefined在json格式數據中是無效的,而null有效

·undefined 類型是 undefined

·null類似是object. 為什么呢?

·兩者都是原始值

·兩者都被認為false(Boolean(undefined) // false, Boolean(null) // false)。

·辨認變量是不是undefined

</div>

typeof variable === "undefined"

·檢查變量是不是null

variable === "null"

從值考慮他們是相等的,但是從類型和值共同考慮他們是不相等的

null == undefined // true
null === undefined // false

#04 - 以非ASCII字符形式來排序字符串

JavaScript有個原生的方法對字符串格式的數組進行排序,做一個簡單的array.sort()將會把字符串們按首字母的數序排列。當然,也可以提供自定義排序功能。

</div>

['Shanghai', 'New York', 'Mumbai', 'Buenos Aires'].sort();
// ["Buenos Aires", "Mumbai", "New York", "Shanghai"]

當你試圖用非ASCII字符,如 ['é', 'a', 'ú', 'c']這樣的進行排序,你會得到一個奇怪的結果['c', 'e', 'á', 'ú'],因為只有用英語的語言才能排序,所以發生這種情況。看一個簡單的例子:

// Spanish
['único','árbol', 'cosas', 'fútbol'].sort();
// ["cosas", "fútbol", "árbol", "único"] // 錯誤的排序
// German
['Woche', 'w?chentlich', 'w?re', 'Wann'].sort();
// ["Wann", "Woche", "w?re", "w?chentlich"] // 錯誤的排序

幸運的是,有兩種方法來避免這種行為,ECMAScript國際化的API提供了localecompare和and Intl.Collator。

這兩種方法都有自己的自定義參數,以便將其配置來充分的完成功能。

使用 localeCompare()

</div>

['único','árbol', 'cosas', 'fútbol'].sort(function (a, b) {
  return a.localeCompare(b);
});
// ["árbol", "cosas", "fútbol", "único"]
['Woche', 'w?chentlich', 'w?re', 'Wann'].sort(function (a, b) {
  return a.localeCompare(b);
});
// ["Wann", "w?re", "Woche", "w?chentlich"]

使用 intl.collator()

['único','árbol', 'cosas', 'fútbol'].sort(Intl.Collator().compare);
// ["árbol", "cosas", "fútbol", "único"]
['Woche', 'w?chentlich', 'w?re', 'Wann'].sort(Intl.Collator().compare);
// ["Wann", "w?re", "Woche", "w?chentlich"]

·每個方法都可以自定義位置

·在FF瀏覽器,intl.collator()會更快,當比較的是較大的數值或字符串

因此,當你在用英語以外的語言來賦值給字符串數組時,記得要使用此方法來避免意外的排序。

</div>

#03 - 改善嵌套條件

我們怎樣才能改善并且使JavaScript中的if語句做出更有效的嵌套。

if (color) {
  if (color === 'black') {
    printBlackBackground();
  } else if (color === 'red') {
    printRedBackground();
  } else if (color === 'blue') {
    printBlueBackground();
  } else if (color === 'green') {
    printGreenBackground();
  } else {
    printYellowBackground();
  }
}

一個改善的辦法是用switch語句代替嵌套的if語句。雖然它是更加簡潔,更加有序,但不推薦這樣做,因為很難debug。 這里 指出原因。

switch(color) {
  case 'black':
    printBlackBackground();
    break;
  case 'red':
    printRedBackground();
    break;
  case 'blue':
    printBlueBackground();
    break;
  case 'green':
    printGreenBackground();
    break;
  default:
    printYellowBackground();
}

但是,當我們有多個判斷條件的情況下呢?在這種情況下,如果我們想讓它更加簡潔,更加有序,我們可以使用switch。如果我們將true的作為一個參數傳遞給該switch語句,它可以讓我們在每一個情況下放置一個條件。

switch(true) {
  case (typeof color === 'string' && color === 'black'):
    printBlackBackground();
    break;
  case (typeof color === 'string' && color === 'red'):
    printRedBackground();
    break;
  case (typeof color === 'string' && color === 'blue'):
    printBlueBackground();
    break;
  case (typeof color === 'string' && color === 'green'):
    printGreenBackground();
    break;
  case (typeof color === 'string' && color === 'yellow'):
    printYellowBackground();
    break;
}

但我們必須避免在每一個條件下進行多次檢查,盡量避免使用switch。我們也必須考慮到最有效的方法是通過一個object。

var colorObj = {
  'black': printBlackBackground,
  'red': printRedBackground,
  'blue': printBlueBackground,
  'green': printGreenBackground,
  'yellow': printYellowBackground
};

if (color in colorObj) { colorObjcolor; }</pre>

這里 有更多相關的信息。

#02 - ReactJs 子級構造的keys是很重要的

keys是代表你需要傳遞給動態數組的所有組件的一個屬性。這是一個獨特的和指定的ID,react用它來標識每個DOM組件以用來知道這是個不同的組件或者是同一個組件。使用keys來確保子組件是可保存的并且不是再次創造的,并且防止怪異事情的產生。

· 使用已存在的一個獨立的對象值

· 定義父組件中的鍵,而不是子組件

//不好的
...
render() {
    <div key={{item.key}}>{{item.name}}</div>
}
...
//好的
<MyComponent key={{item.key}}/>

· 使用數組不是個好習慣

·random()從不會執行

</div>

//不好的
<MyComponent key={{Math.random()}}/>

·你可以創建你的唯一id,請確保該方法是快速的并已經附加到對象上的

·當子級的數量是龐大的或包含復雜的組件,使用keys來提高性能

·你必須為所有的子級 ReactCSSTransitionGroup 提供key屬性

</div>

#01 - AngularJs: $digest vs $apply

AngularJs最讓人欣賞的特點是雙向數據綁定。為了是它工作,AngularJs評估模型的變化和視圖的循環($digest)。你需要了解這個概念,以便了解框架是如何在引擎中工作的。

Angular評估每時的每個事件的變化。這就是$digest循環。有時你必須手動運行一個新的循環,你必須有正確的選擇,因為這個階段是性能方面表現出最具影響力的。

$apply

這個核心方法讓你來啟動一個$digest循環。這意味著所以的watch列表中的對象都將被檢查,整個應用程序啟動了$digest循環。在內部,執行可選的函數參數之后,調用$rootScope.$digest();

$digest

在這種情況下,$digest方法在當前作用域和它的子作用域執行,你應該注意到,父級的作用域將不被檢查,并沒有受到影響。

建議:

·只在瀏覽器DOM事件在Angular之外被觸發的時候使用$apply或者$digest

·給$apply傳遞函數表達式,這有一個錯誤處理機制,允許在消化周期中整合變化。

$scope.$apply(() => {
    $scope.tip = 'Javascript Tip';
});

·如果你僅僅想更新當前作用域或者他的子作用域,用$digest,并且防止整個應用程序的$digest。性能不言而喻咯。

·當$apply有很多東西綁定時,這對機器來說是個艱難的過程,可能會導致性能問題。

·如果你使用的是Angular 1.2.x以上的,使用$evalAsync。這是一個在當前循環或下一次循環的期間或對表達式做出評估的核心方法,這可以提高你的應用程序的性能。

</div>

#00 - 在數組插入一個項

將一個項插入到現有數組中,是一個日常常見的任務,你可以使用push在數組的末尾添加元素,使用unshift在開始的位置,或者在中間使用splice。

這些都是已知的方法,但這并不意味著沒有一個更高性能的途徑。我們來看一看。

在數組的末尾添加一個元素很容易與push(),但還有一個更高性能的途徑。

var arr = [1,2,3,4,5];
arr.push(6);
arr[arr.length] = 6; //在Chrome 47.0.2526.106 (Mac OS X 10.11.1)上提高了 43% 的速度

這兩種方法都修改了數組,不相信我?看這個 jsperf

現在,如果我們正在嘗試將一個項目添加到數組的開頭:

</div>

var arr = [1,2,3,4,5];
arr.unshift(0);
[0].concat(arr); //在Chrome 47.0.2526.106 (Mac OS X 10.11.1)上提高了 98% 的速度

這里更詳細一點:unshift編輯原有的數組,concat返回一個新數組。 jsperf

添加在陣列中的物品很容易使用splice,它是做它的最高效的方式。

</div>

var items = ['one', 'two', 'three', 'four'];
items.splice(items.length / 2, 0, 'hello');

我試著在不同的瀏覽器和操作系統中運行這些測試,結果是相似的。我希望這些建議對你有用,鼓勵你自己做測試!

以上:(2016-01-25)

未完待續...(該文章知識點如在github有更新,這邊每隔一小段時間也會做相對應的更新,原諒本獸時間不是那么充足)

本篇文章也會在微信號"shuang_lang_shuo"發表,同時大家也多支持破狼的處女作新書《AngularJS深度剖析與最佳實踐》。

本篇文章中涉及到的本獸的相關文章: JavaScript 寫幾個簡單的知識點 野獸的 Angular 學習 - - 臟值檢查及其相關 

</div>

 本文由用戶 HarrisonMay 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!