Sunday, December 4, 2016

เทคนิค JavaScript 1 : "use strict" ทำไม และ อย่างไร ?

JavaScript ถูกคิดค้นขึ้นในปี 1995
ด้วยความนิยมจึงมีหน่วยงานกลางมากำหนดมาตรฐานที่เป็นทางการเพื่อให้มันทำงานเหมือนกันในทุก browser 
หน่วยงานนั้นก็คือ ECMA 
นั่นคือเหตุผลว่า บางครั้งคนเรียก JavaScript ว่า ECMAScript (ES) นั่นเอง 😮

ECMAScript ผ่านการปรับปรุงมาหลายครั้ง ครั้งสำคัญคือ version ปี 1999 หรือ ES3
browser ส่วนใหญ่ทำ JavaScript ให้มีพฤติกรรมตาม ES3 มากที่สุด
(ECMAScript เป็นมาตรฐานกลาง แต่ browser จะทำตามหรือเปล่านั้นเป็นอีกเรื่องนึง 😕)
มี JavaScript บาง feature ที่ไม่มีใน ES แต่ browser แต่ละเจ้าคิดกันเอง และมีวิธี code แตกต่างจาก browser อื่นๆ จึงเป็นปัญหาต่อมา

การเปลี่ยนแปลงครั้งสำคัญถัดมา คือ ES5 ปี 2009 
ES5 เพิ่ม feature ใหม่ๆ มากมาย 
บาง feature ก็มีอยู่แล้วในบาง browser แต่กำหนดให้เป็นมาตรฐานมากขึ้น

ปัญหาใหญ่ของ JavaScript คือ feature ที่ไม่ใช่มาตรฐาน บาง browser ก็ใช้ได้ บาง browser ก็ไม่ได้ และถึงแม้จะใช้ได้ก็อาจทำงานไม่เหมือนกัน 
เช่น
const myName = "James";
myName = "Bob
 !";
myName; // "James"
นั่นคือ const ไม่ยอมให้เปลี่ยนค่าเริ่มต้น
แต่ !!
บาง browser ยอมให้เปลี่ยน
const myName = "James";
myName = "Bob !";
myName; // "Bob !"
JavaScript มีมานาน การจำว่า feature ไหนเป็นมาตรฐานหรือไม่ ควรใช้หรือไม่ เป็นเรื่องน่าปวดหัวของโปรแกรมเมอร์สุดๆ 
ด้วยเหตุนี้จึงมีกรณีที่ web app ทำงานถูกใน Chrome แต่พังใน IE (Internet Explorer) บ่อยๆ

ES5 พยายามแก้ปัญหานี้โดยใช้ strict mode
strict mode ไม่ยอมให้มี JavaScript code ที่ใช้ feature ที่เป็นปัญหา
โปรแกรมเมอร์สามารถใช้ strict mode โดยเพิ่ม string พิเศษเข้าไปใน JavaScript code
"use strict";
 ถ้าอยากใช้กับบาง function ก็ทำได้ตามด้านล่าง
function foo(x) {
             "use strict";
          //..
}
บาง browser อาจใช้ strict mode ไม่ได้ ซึ่งไม่เป็นปัญหา เพราะมันจะมอง "use strict" เป็น string ธรรมดา

browser ที่ใช้ strict mode ได้ จะมี error กับ code ด้านล่าง
function foo(x) {
             "use strict";
          var arguments = []; // error: redefinition of arguments
          //..
}
strict mode ไม่ยอมให้ตั้งชื่อตัวแปรว่า arguments เพราะทุก function มีตัวแปร arguments ซ่อนอยู่ การตั้งชื่อซ้ำจะไปทับค่าเดิม ดู ตัวอย่าง

ตำแหน่งของ "use strict" ก็มีประเด็นอยู่ เราควรวางมันใน function หรือข้างนอกดี
คำแนะนำคือไว้ข้างในดีกว่า  มาดูเหตุผลกัน 👇

โปรเจคส่วนใหญ่มี js file หลายไฟล์ แต่เวลา deploy ที่ production จะรวมไฟล์ทั้งหมดเป็นไฟล์เดียว เรียกว่า script concatenation เพื่อลดการ request js ไฟล์จาก browser และทำให้ web page โหลดเร็วขึ้น
สมมติมี 2 ไฟล์ file1.js และ file2.js
// file1.js
"use strict";
function foo() {
     //...
}
//..
และ
// file2.js
// ไม่ใช้ strict mode
function bar() {
      var arguments = [];
}
//..
ทีนี้ตอนรวมไฟล์ ถ้า file1.js มาก่อน จะเกิด error
// file1.js 
"use strict";
function foo() {
     //...
}
//..

// file2.js 
// ไม่ใช้ strict mode
function bar() {
      var arguments = []; // error: redefinition of arguments
}
//..
ไฟล์ file1.js มาก่อนและใช้ strict mode ทำให้ส่วนของ file2.js เป็น strict mode ไปด้วย ทำให้เกิด error ขึ้น
วิธีแก้คือทุกไฟล์ใช้ strict mode ให้หมด

แต่ !! 😬
ถ้าต้องรวมไฟล์ของ third-party library เข้าไปด้วยล่ะ เช่น open-source library 
เราไม่สามารถควบคุม third-party code ให้ใช้ strict mode ได้
วิธีแก้คือ ใช้เทคนิค immediately invoked function expression (IIFE)
นั่นคือ ห่อ code ของทั้ง file1.js และ file2.js ด้วย function ด้านล่าง

(function() {
   // code file1.js หรือ file2.js
})();

เมื่อรวมไฟล์แล้วจะได้ผลตามด้านล่าง

(function() {
   // file1.js 
   "use strict";
   function foo() {
         //...
   }
   //..
})();

(function() {   
   // file2.js 
   // ไม่ใช้ strict mode
   function bar() {
       var arguments = [];
   }
   //..
})();


เท่านี้โค้ดของ file1.js และ file2.js จะอยู่ในโลกของตัวเองถึงแม้จะรวมเป็นไฟล์เดียวกันแล้วก็ตาม


สรุป

  1. ใช้ strict mode เสมอ
  2. ห่อโค้ดในแต่ละไฟล์ด้วย IIFE

Enjoy coding !! 😃

บทความน่าสนใจ
Soft Skills 1 : Agile ก็เท่านั้น ถ้าไม่มีใครฟังเราพูด !



No comments:

Post a Comment