Javascript的一些學習和使用體會

JavaScript 堪称世界上被人误解最深的编程语言。虽然常被嘲为“玩具语言”,但在它看似简洁的外衣下,还隐藏着强大的语言特性。WEB開發離不開Javascript,特別是ES6(ECMAScript 2015)版本以后,各種新功能新用法的推出,Javascript成為越來越受歡迎的語言之一。下面總結一下自己學習和使用Javascript的一些體會。

1. 編寫的代碼可維護性要高.
1)直觀簡潔,容易理解
2)適應性高,數據的變化不會導致代碼重寫修改
3)代碼可擴展性高
4)可調試性高

2. 變量命名
1)變量名稱應為名詞,如car
2)函數名應為動詞加目的,如getName()
3)名稱儘量說明白,如覺得太冗長,可將元音字母去掉
4)變量、函數名稱以小寫開頭;類名,對象名可用大寫開頭;駝峰形式。
5)常量用大寫加下劃線,例如REQUEST_URL

3. 變量定義時進行數據類型初始化
如:
let found=false;//boolean
let count = 0;//number
let name=””;//string
let person = null;//object

或 以b開頭表示boolean,n數字,s 字符串 o對象

let bFound;
let nCount;
let sName;
let oPerson;

4. 函數之間低耦合
各部分之間不要太過緊密依賴,儘量獨立,不要當一個部分更改時,會導致另一部分也需要順應修改。

5. 分離HTML/CSS/JAVASCRIPT
會讓代碼更清晰,易于維護。 如果需要在JS中生成或嵌入HTML,這不是一個很好的習慣,可以嘗試先在HTML中隱藏,然後在JS控制顯示。

6. 業務邏輯與事件分開
例如:

Function handleKeypress(event)
{
  If (event.keyCode==13)
 { 
  let target = event.target;
  let value= 5* parseInt(target.value);
  If (value>10)
      {
       Alert(‘數據超過允許範圍’);
      }
 }
}

建議重構為以下:

function handleKeypress(event)
{
  If (event.keyCode==13)
  {
  Let target =event.target;
  validateValue(target.value);
}
}
funciton validateValue(value)//這個函數是獨立的,它不依賴于其它方法。
//參數只傳遞所需要的數據,是保持低耦合的一個有效方法。**
{
  Let value= 5* parseInt(target.value);
  If (value>10)
      {
       Alert(‘數據超過允許範圍’);
      }
}

7. 尊重對象的所有權
不要隨意增加刪除不是自已創建的的對象的方法屬性。如果你需要,可以創建一個繼承的對象,再去修改新的對象。

8. 避免過多的全局變量。
下面的例子有兩個全局變量

var name = “Nicko”;
function sayName()
{
  Console.log(name);
}

重構為對象,變為一個全局變量,也實現了封裝。

var MyApplication={
name:”Nicko”,
sayName: function(){
 console.log(this.name);
}}

9. 小心 NULL 比較
我們經常會檢查一個變量是否為NULL, 但有時範圍過于廣泛,不夠精確,從而導致意外。
例如: 本意是對數組參數進行排序

function sortArray(values)
{
   if (values != null)
    {
	  values.sort(); //如果values 不是數組,則會出現.sort()錯誤 
	}
}

重構為以下會更好:

function sortArray(values)
{
   if (values instanceof Array) //或 Array.isArray(values). 如果是引用類型用 instanceof ; 如果是基本類型或對象.屬性 用typeof
    {
	  values.sort(compare); //數組是按string對比,所以為number也能夠正常排序,加上 compare
	}
}

function compare(value1,value2)
{
 return value1 > value2 ? 1 : (value1<value2 ? -1 : 0);
}

10. 使用常量

如果你確定該變量當賦值后不會改變的,應儘量設置為常量,更安全和更易於維護。

11. 減少全局掃描

例子:以下做了3次的頁面全局掃描

function updateUi()
{
 let imgs = document.getElementsByTagName("img");
 for (let i =0,len=imgs.length;i<imags.len;i++)
 {
   imags[i].title = `${document.title} image ${i}`;
 }
 let msg = document.getElementById("msg");
 msg.innerHTML = "Update completed"
}

重構為以下,只做一次全局掃描,效果會更好

function updateUi()
{
 let doc = document;
 let imgs = doc.getElementsByTagName("img");
 for (let i =0,len=imgs.length;i<imags.len;i++)
 {
   imags[i].title = `${doc.title} image ${i}`;
 }
 let msg = doc.getElementById("msg");
 msg.innerHTML = "Update completed"
}

12. 優化循環

  1. 簡化條件
  2. 簡化循環體
  3. 使用后測循環
    我們經常使用的是FOR ,while,都是前測循環,后測如do–while,簡化了對終端條件的初始計算,會運行得更快(前提是你確定至少有一次循環要執行)。
    例子:
for(let i=0;i<values.length;i++) //每次判斷終止都要去取 一次 values.length
{
 process(values[i]);
}

以下重構會更好

for(let i=values.length -1; i>=0;i--) //初始化時取一次就夠了
{
process(values[i]);   //如果對 i 先后次序沒有關係
}
或者:
let i=values.length -1;
if (i>-1)
{
 do { process[values[i]);}
 while(--i>=0);//將遞減和終止條件寫在一行了
}

如果是對大數據集進行循環處理(什麽量級才算大數據集,個人覺得以頁面處理響應速度參考吧),使用DUFF’S , Andrew.B.king 的算法更加有效率:

假設 values.length > 0
DUFF’S

let interations = Math.ceil(values.length / 8);
let startAt = values.length % 8;
let i = 0;
do {
switch (startAt)
{
case 0process(values[i++]);
case 7process(values[i++]);
case 6process(values[i++]);
case 5process(values[i++]);
case 4process(values[i++]);
case 3process(values[i++]);
case 2process(values[i++]);
case 1process(values[i++]);
}
startAt = 0;

} while (-- iterations > 0);

更優化的Andrew.B.king

let iterations = Math.floor(values.length /8);
let leftover = values.length % 8 ;
let i = ;
if (leftover > 0)
{
do {
process(values[i++]);
} while (--leftover > 0);
}

do {
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
process(values[i++]);
} while(-- iterations > 0);

13. 最小化代碼的行數
一條語句完成多個操作肯定比 多個語句完成 一個操作效率更高。

例如:

let count = 5;
let coloer=”blue”;
let values = [1,2,3];
let now  = new Date();
改為:
let count = 5,Let coloer=”blue”, values = [1,2,3],Let now  = new Date();
---------------------
例如:
let name = values[i]
i ++;
改為:
let name = values[i++];
---------------
數組,對象的賦值
例如:
let values = new Array();
values[0]=1;
values[1] = 2;

let person = {}
Person.name = “Nickol”;
Person.age = 17;
Person.sayName = function()
{console.log(this.name)};

改為:
let values = [1,2];
let person = 
{
 Name = “nickol”,
 Age = 17,
SayName = function ()
{
 Console.log(this.name)}
}

14. 使用事件委託

事件委託使用冒泡事件,我們把目標的事件放在它的祖先(上級)對象上,可以減少頁面上事件定義(這個當然會佔用更多的內存)的數量。

例如可以把定義在Table td 的click事件,放到 tr , TBody 上,把 li 的click 事件放到它上級的UL上。

当然,事件委托也是有一定局限性的;
比如 focus、blur 之类的事件本身没有事件冒泡机制,所以无法委托.

順便了解下事件是如何運作的
當用戶點擊了一個按鈕,一個事件將會被產生以此來相應用戶。而事件的派遣將會涉及到一下三個方面:
• 捕獲
• 目標
• 冒泡

這裡請注意一下,不是所有事件都有捕獲/冒泡的過程,可能它們直接被派遣到目標上,但是大多數情況下是這樣:
開始
| #document
| HTML |
| BODY } 捕獲
| UL |
| LI#li_1 /
| BUTTON <-- 目標
| LI#li_1
| UL |
| BODY } 冒泡
| HTML |
v #document /
結束

例子:

<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  <li>item n</li>
  </ul>


// 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
  // 兼容性处理  var event = e || window.event;
  var target = event.target || event.srcElement;
  // 判断是否匹配目标元素  if (target.nodeName.toLocaleLowerCase === 'li') {
    console.log('the content is: ', target.innerHTML);
  }});JQUERY:
$(“#list”).on(“click”,”li”,function(e){
console.log('the content is: ', e.target.html());
}
);

15 . 關注內存

1)儘量少用全局变量。這個上面也提到過。
垃圾收集器从不收集全局变量的内存,因此在开始声明全局变量之前,请三思。

2)当涉及到对象和数据绑定时,要注意對象的釋放。
JavaScript的设计方式是,一旦变量被使用,它将自动删除分配的内存,这个过程称为垃圾收集。
例子:

function run(){
  var domObjects = $(".myClass");
  domObjects.click(function(){
  	domObjects.addClass(".myOtherClass");
  });
}
// 上面的函数被调用,本來JavaScript将删除分配的相關内存。但是在上面的代码中,GC没有办法收集“domObjects”的内存,因为它绑定到了事件监听器。
//如果想删除这些引用,可以手动删除它们。
function test(){
  var domObjects = $(".myClass");
  domObjects.click(function(){
    if(domObjects){
      domObjects.addClass(".myOtherClass");
      domObjects = null;//這里不需要再用了,就設為 null,釋放內存 
    }
  });
}

3)字符串连接
这听起来很奇怪,小題大做,但是字符串连接需要额外的内存(多建立了字符串對象)。因此,避免字符串连接,建議使用模板字面量``(記住不是單引號,是~下面那個, 用于字符串連接非常棒_)代替.
例如:
let str1 = “Hello “, str2 = " World!”;
let msg = “The message is :” + str1 + str2;

改為:
let msg = The message is: ${str1}${str2};

4)避免無謂的創建新对象
内存會被分配给新的对象、数组等,想办法减少这种情况。
例如:
let infoBg = $(“.msgInfo”),let warningBg = $(“.msgWarning”);
infoBg.addClass(“bg_info”);
warningBg.addClass(“bg_warning”);

改為:
let $body = $(“body”);
$body.find(“.msgInfo”).addClass(“bg_info”);
$body.find(“.warningBg”).addClass(“bg_warning”);

5) 避免無必要的 try-catch

Try-catch 會分配更多的内存,但try-catch很多時候又是必要的,這時如果可以,能否把它们变成if或其它。如果無必要,堅決不用。

6)Json parse
如果可以,用
const data = JSON.parse(’ {id:12,name:“banana”,color:“yellow”}');
替代
const data = {id:12,name:“banana”,color:“yellow”};

16. Callbacks回调(這個經常會用到)
如果事件的回调频率非常高,并造成頁面卡頓及效能問題,要考虑優化它。
一般綁定 DOM 事件 (resize、scroll、mousemove和keydown/keyup/keypress等) 的時候,常常會因為事件觸發的太頻繁而導致網頁效能低落。

可以使用 Underscore.js 中 _.throttle 和 _.debounce 来减少回调执行。

Debounce
用戶停止某個操作一段時間之後才執行相應的監聽事件.

效果示例:(停止按Button之后執行)
在这里插入图片描述

Throttle
控制監聽事件固定在每 X 毫秒內執行一次

效果示例:(每隔N毫秒執行)
在这里插入图片描述


 <script src="你自己的/js/underscore-min.js"></script>
function log( event ) {
  console.log( $(window).scrollTop(), event.timeStamp );
};

// 控制台记录窗口滚动事件,触发频率比你想象的要快
$(window).scroll( log );

// 控制台记录窗口滚动事件,每250ms最多触发一次
$(window).scroll( _.throttle( log, 250 ) );


function ajax_lookup( event ) {
  // 对输入的内容$(this).val()执行 Ajax 查询
};

// 字符输入的频率比你预想的要快,Ajax 请求来不及回复。
$('input:text').keyup( ajax_lookup );

// 当用户停顿250毫秒以后才开始查找
$('input:text').keyup( _.debounce( ajax_lookup, 250 ) );


更多请阅读:https://css-tricks.com/the-difference-between-throttling-and-debouncing/

17. Javacript 的 boolean 類別
JavaScript 包含布尔类型,这个类型的变量有两个可能的值,分别是 true 和 false(两者都是关键字)。根据具体需要,JavaScript 按照如下规则将变量转换成布尔类型:

false、0、空字符串(“”)、NaN、null 和 undefined 被转换为 false
所有其他值被转换为 true
也可以使用 Boolean() 函数进行显式转换:

Boolean(‘’); // false
Boolean(234); // true
Copy to Clipboard
不过一般没必要这么做,因为 JavaScript 会在需要一个布尔变量时隐式完成这个转换操作(比如在 if 条件语句中)。

18. ES 2020,2021 新增零合并操作符 ?? 用以替代之前 的 ||
|| 是布尔值运算符,所以,左侧的操作数会被先转为布尔值用于计算,而(0,‘’,NAN,null,undifined)都为假值,如
let str = pstr || “”;
当 pstr =0 时,str 也会为 “”;
而 ?? 则可以保证只有undefined , null ,才会返回后者。

19. ES2020,2021 新增 ?.可选链操作符
类似于 c# ?.操作符
例如: const obj ={a:“a”,b:{c:“c”}};
console.log(obj?.b?.d);//不会报错,输出 undefined

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值