diff options
Diffstat (limited to 'files/vi/web/javascript/guide')
15 files changed, 6524 insertions, 0 deletions
diff --git a/files/vi/web/javascript/guide/control_flow_and_error_handling/index.html b/files/vi/web/javascript/guide/control_flow_and_error_handling/index.html new file mode 100644 index 0000000000..55931e4a1f --- /dev/null +++ b/files/vi/web/javascript/guide/control_flow_and_error_handling/index.html @@ -0,0 +1,405 @@ +--- +title: Control flow and error handling +slug: Web/JavaScript/Guide/Control_flow_and_error_handling +translation_of: Web/JavaScript/Guide/Control_flow_and_error_handling +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}</div> + +<p class="summary">JavaScript hỗ trợ một tập hợp lệnh gọn nhẹ, các lệnh điều khiển luồng chuyên biệt, mà khi kết hợp lại có thể tăng tính tương tác cho ứng dụng của bạn lên đáng kể. Chương này giới thiệu sơ qua về các lệnh này.</p> + +<p>Mục <a href="/en-US/docs/Web/JavaScript/Reference/Statements">JavaScript reference</a> chứa các chi tiết đầy đủ về các câu lệnh trong chương này. Dấu chấm phẩy (<code>;</code>) được dùng để ngăn cách giữa các lệnh trong code JavaScript.</p> + +<p>Bât cứ một biểu thức JavaScript nào cũng đều là một câu lệnh. Xem <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators">Expressions and operators</a> để biết thông tin đầy đủ về các biểu thức.</p> + +<h2 id="Block_statement">Block statement</h2> + +<p>Một trong những lệnh căn bản nhất là khối lệnh (block statement), được dùng để nhóm lại các câu lệnh. Khối lệnh được phân định bởi cặp dấu ngoặc nhọn:</p> + +<pre class="syntaxbox">{ + lệnh_1; + lệnh_2; + . + . + . + lệnh_n; +} +</pre> + +<h3 id="Ví_dụ"><strong>Ví dụ</strong></h3> + +<p>Khối lệnh thường được dùng với lệnh điều khiển luồng (như là <code>if</code>, <code>for</code>, <code>while</code>).</p> + +<pre class="brush: js">while (x < 10) { + x++; +} +</pre> + +<p>Ở đây, <code>{ x++; }</code> là một khối lệnh.</p> + +<p><strong>Quan trọng</strong>: Trước ECMAScript2015 (phiên bản thứ 6), JavaScript <strong>chưa có</strong> phạm vi khối (block-scope). Trong phiên bản JavaScript cũ hơn, biến được khai báo trong khối được đặt phạm vi theo hàm hoặc đoạn mã bao bọc khối đó, và ảnh hưởng của việc thiết lập chúng sẽ vượt ra khỏi phạm vi của khối. Nói cách khác, khối lệnh không định nghĩa phạm vi. Các khối độc lập ("standalone" - tức là đi kèm với lệnh điều khiển nào) trong JavaScript có thể sản sinh kết quả khác so với khối lệnh tương tự trong Java hay C. Chẳng hạn:</p> + +<pre class="brush: js">var x = 1; +{ + var x = 2; +} +console.log(x); // trả về 2 +</pre> + +<p>Đoạn mã này trả về 2 bởi vì câu lệnh <code>var x</code> bên trong khối có cùng phạm vi với câu lệnh <code>var x</code> trước khối. Trong C hoặc Java, đoạn mã này sẽ trả về 1.</p> + +<p>Kể từ ECMAScript2015, hai kiểu khai báo biến mới là <code>let</code> và <code>const</code> đều được đặt trong phạm vi khối lệnh. Tham khảo {{jsxref("Statements/let", "let")}} và {{jsxref("Statements/const", "const")}} để biết thêm chi tiết.</p> + +<h2 id="Lệnh_điều_kiện">Lệnh điều kiện</h2> + +<p>Lệnh điều kiện là tập hợp các dòng lệnh sẽ thực thi nếu một điều kiện nhất định trả về true. JavaScript hỗ trợ hai lệnh điều kiện: <code>if...else</code> và <code>switch</code>.</p> + +<h3 id="Lệnh_if...else"><code>Lệnh if...else</code></h3> + +<p>Dùng mệnh đề <code>if</code> để thực thi lệnh nếu điều kiện trả về true. Có thể dùng thêm mệnh đề <code>else</code> để thực thi lệnh nếu điều kiện trả về <code>false</code>. Lệnh <code>if</code> trông như sau:</p> + +<pre class="syntaxbox">if (điều_kiện) { + lệnh_1; +} else { + lệnh_2; +}</pre> + +<p>Ở đây, <code>điều_kiện</code> có thể là bất cứ biểu thức nào để đánh giá true hoặc false. Xem <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean#Description">Boolean</a> để hiểu cách thức trả về <code>true</code> và <code>false</code>. Nếu <code>điều_kiện</code> trả về true, <code>lệnh_1</code> sẽ được thực thi; trái lại, <code>lệnh_2</code> sẽ được thực thi. <code>lệnh_1</code> và <code>lệnh_2</code> có thể là bất cứ câu lệnh nào, bao gồm các câu lệnh <code>if</code> lồng nhau.</p> + +<p>Bạn cũng có thể dùng lệnh <code>else if</code> để có một dãy điều kiện liên tiếp nhau, chẳng hạn như sau:</p> + +<pre class="syntaxbox">if (điều_kiện_1) { + lệnh_1; +} else if (điều_kiện_2) { + lệnh_2; +} else if (điều_kiện_n) { + lệnh_n; +} else { + lệnh_cuối; +} +</pre> + +<p>Trong trường hợp có nhiều điều kiện, chỉ thực thi các lệnh trong điều kiện đầu tiên trả về true. Để thực thi nhiều lệnh cùng lúc, hãy nhóm chúng lại trong một khối lệnh (<code>{ ... }</code>) . Nói tóm lại, ta luôn nên dùng khối lệnh, nhất là khi lồng trong câu lệnh <code>if</code>:</p> + +<pre class="syntaxbox">if (điều_kiện) { + lệnh_1_nếu_điều_kiện_là_true; + lệnh_2_nếu_điều_kiện_là_true; +} else { + lệnh_3_nếu_điều_kiện_là_false; + lệnh_4_nếu_điều_kiện_là_false; +} +</pre> + +<div>Đừng dùng lệnh gán trong biểu thức điều kiện, bởi vì lệnh gán có thể bị hiểu lầm với so sánh ngang bằng nếu xem sơ qua đoạn code. Chẳng hạn, đừng viết như sau:</div> + +<pre class="example-bad brush: js">// Dễ bị hiểu lầm là "x == y" trong khi ở bên dưới là gán giá trị y cho x +if (x = y) { + /* tập hợp các câu lệnh */ +} +</pre> + +<p>Nếu cần phải gán trong biểu thức điều kiện, hãy bọc chúng lại trong cặp dấu ngoặc tròn, chẳng hạn:</p> + +<pre class="brush: js">if ((x = y)) { + /* tập hợp các câu lệnh */ +} +</pre> + +<h4 id="Giá_trị_Falsy">Giá trị Falsy</h4> + +<p>Các giá trị sau sẽ trả về false (còn được gọi là giá trị {{Glossary("Falsy")}}):</p> + +<ul> + <li><code>false</code></li> + <li><code>undefined</code></li> + <li><code>null</code></li> + <li><code>0</code></li> + <li><code>NaN</code></li> + <li>Chuỗi rỗng (<code>""</code>)</li> +</ul> + +<p>Mọi giá trị khác, bao gồm tất cả object, trả về true khi được truyền vào câu lệnh điều kiện.</p> + +<p><strong>Chú ý:</strong> Đừng nhầm lẫn giữa giá trị Boolean sơ khai <code>true</code> và <code>false</code> với giá trị true và false của object {{jsxref("Boolean")}}. Chẳng hạn:</p> + +<pre class="brush: js">var b = new Boolean(false); +if (b) // điều kiện này trả về true +if (b == true) // điều kiện này trả về false +</pre> + +<h4 id="Ví_dụ_2"><strong>Ví dụ</strong></h4> + +<p>Trong ví dụ sau, hàm <code>checkData</code> trả về <code>true</code> nếu số lượng ký tự của object <code>Text</code> là 3; trái lại, một thông báo sẽ hiện ra và hàm sẽ trả về <code>false</code>.</p> + +<pre class="brush: js">function checkData() { + if (document.form1.threeChar.value.length == 3) { + return true; + } else { + alert('Enter exactly three characters. ' + + document.form1.threeChar.value + ' is not valid.'); + return false; + } +} +</pre> + +<h3 id="Lệnh_switch">Lệnh <code>switch</code></h3> + +<p>Lệnh <code>switch</code> cho phép một chương trình đánh giá một biểu thức và nổ lực thử nghiệm dần để tìm ra trường hợp giống nhau giữa giá trị của biểu thức đó với <code>case</code> label. Nếu một sự kết hợp được tìm thấy, chương trình sẽ chạy câu lệnh liên quan. Câu lệnh <code>switch</code> như sau:</p> + +<pre class="syntaxbox">switch (expression) { + case label_1: + statements_1 + [break;] + case label_2: + statements_2 + [break;] + ... + default: + statements_def + [break;] +} +</pre> + +<ul> + <li>Trước hết, chương trình sẽ tìm mệnh đề <code>case</code> có nhãn giống với giá trị của biểu thức và truyền dẫn việc điểu khiển tới mệnh đề đó, thực thi các lệnh liên quan.</li> + <li>Nếu không có nhãn nào khớp, chương trình sẽ tìm mệnh đề mặc định <code>default</code>, + <ul> + <li>Nếu tìm thấy mệnh đề mặc định <code>default</code>, chương trình sẽ truyền luồng điểu khiển tới mệnh đề đó, thực thi các lệnh liên quan.</li> + <li>Nếu không tìm thấy mệnh đề mặc định <code>default</code>, chương trình tiếp tục thực thi cho tới cuối lệnh <code>switch</code>. (Theo quy ước, mệnh đề <code>default</code> được viết cuối cùng, nhưng không bắt buộc).</li> + </ul> + </li> +</ul> + +<h4 id="Lệnh_break">Lệnh break</h4> + +<p>Lệnh tuỳ chọn <code>break</code> liên kết với từng mệnh đề <code>case</code> nhằm đảm bảo chương trình nhảy ra khỏi <code>switch</code> một khi câu lệnh liên quan tại vị trí mệnh đề phù hợp đã thực hiện xong, và sau đó tiếp tục thực hiện câu lệnh phía sau lệnh <code>switch</code>. Nếu không có <code>break</code>, chương trình sẽ thực thi toàn bộ câu lệnh tiếp theo còn lại trong <code>switch</code> mà không cần đánh giá xem giá trị của biểu thức và <code>case</code> label có khớp nhau không.</p> + +<h4 id="Ví_dụ_3"><strong>Ví dụ</strong></h4> + +<p>Trong ví dụ sau, nếu <code>fruittype</code> được gán giá trị "Bananas", chương trình sẽ khớp với nhãn "Bananas" và thực thi các lệnh đi kèm. Khi chương trình chạy tới <code>break</code>, chương trình ngừng và thực thi các lệnh sau khối lệnh <code>switch</code>. Nếu không có <code>break</code>, lệnh ứng với nhãn "Cherries" cũng sẽ được thực thi.</p> + +<pre class="brush: js">switch (fruittype) { + case 'Oranges': + console.log('Oranges are $0.59 a pound.'); + break; + case 'Apples': + console.log('Apples are $0.32 a pound.'); + break; + case 'Bananas': + console.log('Bananas are $0.48 a pound.'); + break; + case 'Cherries': + console.log('Cherries are $3.00 a pound.'); + break; + case 'Mangoes': + console.log('Mangoes are $0.56 a pound.'); + break; + case 'Papayas': + console.log('Mangoes and papayas are $2.79 a pound.'); + break; + default: + console.log('Sorry, we are out of ' + fruittype + '.'); +} +console.log("Is there anything else you'd like?");</pre> + +<h2 id="Lệnh_xử_lý_ngoại_lệ">Lệnh xử lý ngoại lệ</h2> + +<p>Bạn có thể quăng ngoại lệ (exeption) bằng lệnh <code>throw</code> và xử lý chúng bằng lệnh <code>try...catch</code>.</p> + +<ul> + <li><a href="#throw_statement">Lệnh <code>throw</code></a></li> + <li><a href="#try...catch_statement">Lệnh <code>try...catch</code></a></li> +</ul> + +<h3 id="Kiểu_ngoại_lệ">Kiểu ngoại lệ</h3> + +<p>Gần như mọi object đều có thể bị quăng ra trong JavaScript. Tuy vậy, không phải object nào khi quăng ra cũng được tạo ra tương tự nhau. Trong khi thông thường các số và chuỗi được quăng ra để thông báo lỗi, song sử dụng một trong số những kiểu ngoại lệ chuyên biệt cho mục đích này thường hiệu quả hơn:</p> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types">Ngoại lệ ECMAScript</a></li> + <li>{{domxref("DOMException")}} and {{domxref("DOMError")}}</li> +</ul> + +<h3 id="Lệnh_throw">Lệnh <code>throw</code></h3> + +<p>Lệnh <code>throw</code> để quăng ra ngoại lệ. Khi muốn quăng ra ngoại lệ, bạn phải đặc tả biểu thức chứa giá trị để quăng ra:</p> + +<pre class="syntaxbox">throw expression; +</pre> + +<p>Bạn có thể quăng ra biểu thức nào cũng được, không chỉ biểu thức dành riêng cho kiểu ngoại lệ. Ví dụ sau đây quăng ra vô số kiểu:</p> + +<pre class="brush: js">throw 'Error2'; // String type +throw 42; // Number type +throw true; // Boolean type +throw {toString: function() { return "I'm an object!"; } }; +</pre> + +<div class="note"><strong>Ghi chú:</strong> Bạn có thể đặc tả object khi quăng ngoại lệ. Rồi đặt tham chiếu tới thuộc tính của object đó trong khối <code>catch</code>.</div> + +<pre class="brush: js">// Tạo object có kiểu UserException +function UserException(message) { + this.message = message; + this.name = 'UserException'; +} + +// Bắt ngoại lệ in ra dòng lỗi màu mè một tí +// (như khi in lên console chả hạn) +UserException.prototype.toString = function() { + return this.name + ': "' + this.message + '"'; +} + +// Tạo một instance của object rồi quăng ra +throw new UserException('Value too high');</pre> + +<h3 id="Lệnh_try...catch">Lệnh <code>try...catch</code></h3> + +<p>Lệnh <code>try...catch</code> đánh dấu một khối để thử, và xác định khi nào sẽ quăng ra ngoại lệ. Khi ngoại lệ bị quăng ra, lệnh <code>try...catch</code> sẽ tóm gọn nó.</p> + +<p>Lệnh <code>try...catch</code> bao gồm khối <code>try</code>, chứa một hoặc nhiều câu lệnh, và khối <code>catch</code>, chứa các lệnh dành để xử lý khi có ngoại lệ bị quăng ra trong khối <code>try</code>.</p> + +<p>Tức là, bạn muốn lệnh trong khối <code>try</code> thành công, và nhỡ nó không thành công, bạn muốn truyền luồng xử lý xuống khối <code>catch</code>. Nếu bất cứ lệnh nào trong khối <code>try</code> (hoặc hàm được gọi trong khối <code>try</code>) quăng ra ngoại lệ, luồng điều khiển sẽ ngay lập tức chuyển xuống khối <code>catch</code>. Nếu không có ngoại lệ nào bị quăng ra trong khối <code>try</code>, khối <code>catch</code> sẽ bị bỏ qua. Khối <code>finally</code> thực thi sau khi khối <code>try</code> và <code>catch</code> thực thi xong nhưng trước các lệnh đặt ngay sau lệnh <code>try...catch</code>.</p> + +<p>Ví dụ sau dùng lệnh <code>try...catch</code>. Trong ví dụ này, ta gọi một hàm nhận vào một giá trị và trả về tên tháng tương ứng. Nếu giá trị truyền vào không tương ứng với số tháng (1-12), một ngoại lệ sẽ bị quăng ra có kiểu <code>"InvalidMonthNo"</code> và lệnh trong khối <code>catch</code> sẽ đặt lại giá trị cho biến <code>monthName</code> thành <code>unknown</code>.</p> + +<pre class="brush: js">function getMonthName(mo) { + mo = mo - 1; // Chỉnh lại số tháng cho hợp với chỉ số mảng (1 = Jan, 12 = Dec) + var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', + 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + if (months[mo]) { + return months[mo]; + } else { + throw 'InvalidMonthNo'; // dùng từ khoá throw ở đây nhé + } +} + +try { // lệnh để thử + monthName = getMonthName(myMonth); // hàm để quăng ra ngoại lệ +} +catch (e) { + monthName = 'unknown'; + logMyErrors(e); // truyền object ngoại lệ vào hàm xử lý lỗi của bạn +} +</pre> + +<h4 id="Khối_catch">Khối <code>catch</code></h4> + +<p>Bạn có thể dùng khối <code>catch</code> để xử lý tất cả ngoại lệ sinh ra trong khối <code>try</code>.</p> + +<pre class="syntaxbox">catch (catchID) { + statements +} +</pre> + +<p>Khối <code>catch</code> nhận vào một định danh (<code>catchID</code> như trong cú pháp phía trên) giữ giá trị mà lệnh <code>throw</code> quăng ra; bạn có thể dùng định danh này để lấy thông tin về ngoại lệ bị quăng ra. JavaScript tạo ra định danh này khi chương trình chạy vào khối <code>catch</code>; định danh này chỉ tồn tại trong khối <code>catch</code>; sau khi khối <code>catch</code> thực thi xong, định danh đó sẽ không còn tồn tại nữa.</p> + +<p>Chẳng hạn, đoạn code sau quăng ra một ngoại lệ. Khi ngoại lệ xảy ra, điều khiển được truyền xuống khối <code>catch</code>.</p> + +<pre class="brush: js">try { + throw 'myException'; // sinh ngoại lệ +} +catch (e) { + // lệnh xử lý ngoại lệ + logMyErrors(e); // truyền object ngoại lệ xuống hàm xử lý lỗi +} +</pre> + +<p><strong>Thực tiễn tốt nhất: </strong>Khi log error ra console bên trong một <code>catch</code> block, hãy sử dụng <code>console.error()</code> thay vì <code>console.log()</code>, nó sẽ định dạng dòng văn bản như là một lỗi, và thêm nó vào danh sách các dòng văn bản lỗi được tạo ra bởi trang. Điều này tốt cho việc debugging.</p> + +<h4 id="Khối_finally">Khối <code>finally</code></h4> + +<p>Khối <code>finally</code> chứa các lệnh thực thi ngay sau khi thực thi khối <code>try</code> và <code>catch</code> nhưng trước các lệnh liền sau lệnh <code>try...catch</code>. Khối <code>finally</code> vẫn thực thi dù có xảy ra ngoại lệ hay không. Nếu ngoại lệ bị quăng ra, các lệnh trong khối <code>finally</code> vẫn thực thi dù khối <code>catch</code> có xử lý ngoại lệ hay không.</p> + +<p>Bạn có thể dùng khối <code>finally</code> để khiến mã của bạn lỗi một cách yên bình nhỡ ngoại lệ xảy ra; chả hạn, bạn muốn giải phóng tài nguyên khỏi đoạn mã của mình. Ví dụ sau mở một tệp tin và thực thi lệnh dùng tài nguyên của tệp đó (JavaScript phía server cho phép bạn truy cập vào tệp tin). Nếu có ngoại lệ bị quăng ra trong lúc đang mở tệp tin, khối <code>finally</code> sẽ đóng đoạn tệp tin lại trước khi đoạn mã bị lỗi.</p> + +<pre class="brush: js">openMyFile(); +try { + writeMyFile(theData); // Ghi vào tệp, có thể có lỗi +} catch(e) { + handleError(e); // Nếu có lỗi thì dùng hàm này để xử lý +} finally { + closeMyFile(); // Luôn luôn đóng tệp lại +} +</pre> + +<p>Nếu khối <code>finally</code> trả về giá trị thì giá trị đó sẽ trở thành giá trị trả về của cả dãy lệnh <code>try-catch-finally</code>, bỏ qua mọi lệnh <code>return</code> trong khối <code>try</code> và <code>catch</code>:</p> + +<pre class="brush: js">function f() { + try { + console.log(0); + throw 'bogus'; + } catch(e) { + console.log(1); + return true; // lệnh return ở đây bị tạm ngưng + // cho tới khi thực thi xong khối finally + console.log(2); // không thực thi tới + } finally { + console.log(3); + return false; // ghi đè lệnh "return" phía trên + console.log(4); // không thực thi tới + } + // "return false" sẽ thực thi ngay lúc này + console.log(5); // không thực thi tới +} +console.log(f()); // 0, 1, 3, false +</pre> + +<p>Ghi đè giá trị trả về bằng khối <code>finally</code> cũng áp dụng với các ngoại lệ bị quăng ra trong khối <code>catch</code>:</p> + +<pre class="brush: js">function f() { + try { + throw 'bogus'; + } catch(e) { + console.log('caught inner "bogus"'); + throw e; // lệnh thow này bị tạm ngưng + // cho tới khi thực thi xong khối finally + } finally { + return false; // ghi đè lệnh "throw" phía trên + } + // "return false" sẽ thực thi ngay lúc này +} + +try { + console.log(f()); +} catch(e) { + // khối này sẽ không bao giờ tới được + // bởi vì khối catch phía trên đã bị ghi đè + // bởi lệnh return trong finally + console.log('caught outer "bogus"'); +} + +// ĐẦU RA +// caught inner "bogus" +// false</pre> + +<h4 id="Lồng_lệnh_try...catch">Lồng lệnh try...catch</h4> + +<p>Bạn có thể lồng một hoặc nhiều lệnh <code>try...catch</code>. Nếu lệnh <code>try...catch</code> bên trong không có khối <code>catch</code> :</p> + +<ol> + <li>Nó nên có khối <code>finally</code> và</li> + <li>Lệnh <code>try...catch</code> bọc bên ngoài phải bắt được cái gì đấy. Để biết thêm thông tin, hãy đọc <a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch#Nested_try-blocks">lồng khối try</a> trên trang <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code>.</li> +</ol> + +<h3 id="Tận_dụng_object_Error">Tận dụng object <code>Error</code></h3> + +<p>Tuỳ theo kiểu của lỗi, bạn có thể dùng thuộc tính 'name' và 'message' để lấy ra thông điệp lỗi rõ ràng hơn. 'name' lấy ra class chung của Error (tức là 'DOMException' hoặc 'Error'), trong khi 'message' thường lấy ra thông điệp về lỗi súc tích hơn thông điệp tạo ra bởi ép object lỗi thành xâu ký tự.</p> + +<p>Nếu bạn muốn quăng ra ngoại lệ của riêng mình, để tận dụng được những thuộc tính này (ví dụ như khi khối catch không phân biệt giữa ngoại lệ của bạn và của hệ thống), bạn có thể dùng hàm khởi tạo Error. Chẳng hạn:</p> + +<pre class="brush: js">function doSomethingErrorProne() { + if (ourCodeMakesAMistake()) { + throw (new Error('The message')); + } else { + doSomethingToGetAJavascriptError(); + } +} +.... +try { + doSomethingErrorProne(); +} catch (e) { + console.log(e.name); // logs 'Error' + console.log(e.message); // logs 'The message' or a JavaScript error message +} +</pre> + +<div>{{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}</div> diff --git a/files/vi/web/javascript/guide/cu-phap-lap-trinh/index.html b/files/vi/web/javascript/guide/cu-phap-lap-trinh/index.html new file mode 100644 index 0000000000..64f63492d2 --- /dev/null +++ b/files/vi/web/javascript/guide/cu-phap-lap-trinh/index.html @@ -0,0 +1,710 @@ +--- +title: Cú pháp lập trình +slug: Web/JavaScript/Guide/cu-phap-lap-trinh +translation_of: Web/JavaScript/Guide/Grammar_and_types +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}</div> + +<p class="summary">Phần này nói về các cú pháp cơ bản của ngôn ngữ JavaScript, các cách khai báo biến, các loại dữ liệu và chính tả (literal).</p> + +<h2 id="Cơ_bản">Cơ bản</h2> + +<p>Cú pháp của JavaScript (JS) phần lớn được vay mượn từ Java, nhưng JS cũng chịu ảnh hưởng từ cú pháp của các ngôn ngữ lập trình khác như Awk, Perl và Python.</p> + +<p>JavaScript là ngôn ngữ lập trình sử dụng chuẩn kí tự <strong>Unicode</strong> và khi viết cũng cần phải lưu ý phân biệt chữ HOA và chữ thường (<strong>case-sensitive). </strong>Điều này có nghĩa là các từ như Früh (trong tiếng Đức có nghĩa là "sớm" - early) có thể được sử dụng đặt tên cho biến.</p> + +<pre>let Früh = "foobar" +</pre> + +<p>In JavaScript, instructions are called {{Glossary("Statement", "statements")}} and are separated by a semicolon (;).</p> + +<p>Dấu chấm phẩy (;) chỉ cần thiết nếu trên cùng một dòng có từ hai câu lệnh trở lên. Trường hợp câu lệnh nằm riêng một dòng thì không cần dấu chấm phẩy.</p> + +<p><em>ECMAScript cũng có những nguyên tắc để tự động thêm dấu chấm phẩy (<a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Automatic_semicolon_insertion">ASI</a>) để đánh dấu kết thúc một dòng lệnh. (Để biết thêm, xem tài liệu tham khảo chi tiết tại đây: JavaScript's <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar">lexical grammar</a>.)</em></p> + +<p>Thực tế thì nên luôn luôn thêm một dấu chấm phẩy vào cuối mỗi câu lệnh, thậm chí khi điều này là không bắt buộc. Việc làm này sẽ giúp tránh bớt bug.</p> + +<p>Các đoạn mã Javascript sẽ được đọc từ trái qua phải và được chuyển thể thành một chuỗi các input elements bao gồm: <em>tokens, control characters, line terminators, comments</em> hoặc {{glossary("whitespace")}}. (Spaces, tabs, và các ký tự đánh dấu dòng mới được xem là whitespace.)</p> + +<h2 id="Comments">Comments</h2> + +<p>Cú pháp của<strong> comments</strong> thì ... giống với C++ và một số ngôn ngữ lập trình khác:</p> + +<pre class="brush: js">// a one line comment <-- đây là cách comment trên 1 dòng + +/* this is a longer, cho những dòng dài hoặc nhiều dòng + multi-line comment. hãy sử dụng kiểu comment này + */ + +/* You can't, however /* nest comments */ SyntaxError */ <-- Không nên lồng comment trong comment, như đoạn comment này sẽ gây ra lỗi vì "/*" được mở bên trong comment trước đó không có hiệu lực đối với từ SyntaxError nên dấu đóng comment "*/" sẽ gây ra lỗi cú pháp. </pre> + +<p>Comments hoạt động như whitespace, và sẽ bị bỏ qua trong quá trình script chạy.</p> + +<p class="brush: js"><em><strong>Note:</strong> Bạn có thể thấy loại cú pháp comment này trong một số file javascript <strong>#!/usr/bin/env node</strong>.</em></p> + +<p class="brush: js"><em>Đây là cú pháp <strong>hashbang comment</strong>, và là một comment đặc biệt sử dụng để chỉ định đường dẫn đến một Javascript interpreter cụ thể có nhiệm vụ sẽ chạy đoạn script. Xem chi tiết <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Hashbang_comments">Hashbang comments</a>.</em></p> + +<h2 id="Khai_báo_biến">Khai báo biến</h2> + +<p>Có 3 kiểu khai báo biến trong JavaScript.</p> + +<dl> + <dt>{{jsxref("Statements/var", "var")}}</dt> + <dd>Khai báo một biến, và tùy ý bạn có hoặc không khởi tạo giá trị cho nó.</dd> + <dt>{{jsxref("Statements/let", "let")}}</dt> + <dd>Khai báo một block-scoped, hoặc biến local, chỉ có thể truy cập được trong block bao quanh nó.</dd> + <dt> + <pre>function foo() { + var x = 10; + if (true) { + let x = 20; // x ở đây được khai báo lại nhưng khi ra khỏi block-scoped nó sẽ nhận lại giá trị bên trên là 10 + console.log(x); // in ra 20 + } + console.log(x); // in ra 10 +}</pre> + </dt> + <dt>{{jsxref("Statements/const", "const")}}</dt> + <dd>Khai báo một hằng block-scoped, read-only.</dd> +</dl> + +<h3 id="Biến">Biến</h3> + +<p>Bạn sử dụng biến như là tên tượng trưng cho các giá trị trong chương trình. Tên của biến được gọi là {{Glossary("Identifier", "identifier")}}, tuân theo những quy tắc nhất định.</p> + +<p>Tên biến phải bắt đầu bằng một 'chữ cái', kí tự gạch dưới (<code>_</code>), hoặc kí tự dollar (<code>$</code>). Các ký tự tiếp theo cũng có thể là các chữ số <code>0-9</code>. Vì JavaScript là case sensitive, các chữ các bao gồm các ký tự từ "<code>A</code>" đến "<code>Z</code>" (viết hoa) và "<code>a</code>" đến "<code>z</code>" (viết thường).</p> + +<p>Bạn có thể sử dụng chuẩn ISO 8859-1 hoặc các kí tự Unicode như å và ü trong tên biến, thậm chí cả các kí tự dạng <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals">Unicode escape sequences</a>.</p> + +<p>Ví dụ: <code>Number_hits</code>, <code>temp99</code>, and <code>_name</code>.</p> + +<h3 id="Declaring_variables">Declaring variables</h3> + +<p>Có hai cách khai báo biến:</p> + +<ul> + <li>Sử dụng từ khóa {{jsxref("Statements/var", "var")}}. Ví dụ <code>var x = 42</code>. Cú pháp này dùng khai báo cả 2 loại biến <strong>local </strong>và <strong>global</strong>, tùy thuộc vào ngữ cảnh thực thi.</li> + <li>Sử dụng từ khóa {{jsxref("Statements/const", "const")}} hoặc {{jsxref("Statements/let", "let")}}. Ví dụ <code>let y = 13</code>. Cú pháp này dùng khai báo biến local nhưng chỉ có phạm vi trong block-scoped. (Xem <a href="https://wiki.developer.mozilla.org/vi/docs/Web/JavaScript/Guide/cu-phap-lap-trinh$edit#Variable_scope">Variable scope</a> bên dưới).</li> +</ul> + +<p>Bạn cũng có thể khai báo biến mà không dùng các từ khóa trên, ví dụ <code>x = 42</code>. Điều này sẽ tạo ra một biến <strong><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#Description">undeclared global</a></strong> variable. Nó sẽ tạo nên một warning trong JavaScript. Undeclared variables có thể dẫn đến các hành vi không mong muốn. Nên khuyến cáo không nên sử dụng chúng.</p> + +<h3 id="Evaluating_variables">Evaluating variables</h3> + +<p>Một biến được khai báo với cú pháp <code>var</code> hoặc <code>let</code> mà không gán giá trị, sẽ có giá trị mặc định là {{jsxref("undefined")}}.</p> + +<p>Truong trường hợp truy cập đến một biến chưa được khai báo, thì exception {{jsxref("ReferenceError")}} sẽ được thrown:</p> + +<pre>var a; +console.log('The value of a is ' + a); // The value of a is undefined + +console.log('The value of b is ' + b); // The value of b is undefined +var b; +// This one may puzzle you until you read 'Variable hoisting' below + +console.log('The value of c is ' + c); // Uncaught ReferenceError: c is not defined + +let x; +console.log('The value of x is ' + x); // The value of x is undefined + +console.log('The value of y is ' + y); // Uncaught ReferenceError: y is not defined +let y; </pre> + +<p>Bạn có thể sử dụng <code>undefined</code> để xét xem một biến có đang mang giá trị không. Dưới đây là một ví dụ, biến <code>input</code> chưa được gán giá trị, nên biến <code>input</code> lúc này mang giá trị mặc định <code>undefined</code> vậy câu điều kiện <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else" title="en-US/docs/JavaScript/Reference/Statements/if...else">if</a></code> là <code>return true</code> và không chạy vào <code>else</code>.</p> + +<pre class="brush: js">var input; +if(input === undefined){ + doThis(); +} else { + doThat(); +} +</pre> + +<p>Giá trị <code>undefined</code> tương đương với <code>fasle</code> khi sử dụng trong bối cảnh boolean, như ví dụ dưới đây, chương trình sẽ chạy function <code>myFunction</code> vì element <code>myArray[0]</code>là <code>undefined</code> trả về <code>false</code>.</p> + +<pre class="brush: js">var myArray = []; +if (!myArray[0]) { + myFunction(); +} + +function myFunction() { + alert('return false'); +} +</pre> + +<p>Khi biến có giá trị = <code>undefined </code>thực hiện phép toán với biến có giá trị cụ thể hoặc hằng số sẽ cho ra giá trị = <code>NaN</code> (not a number). </p> + +<pre class="brush: js">var a; +a + 2 = NaN</pre> + +<p><code>Null</code> khác với <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">Undefined</span></font>. Khi biến có giá trị {{jsxref("null")}}, biến sẽ mang giá trị 0 trong các phép toán (numeric) và <code>false</code> trong các ngữ cảnh boolean. Ví dụ:</p> + +<pre class="brush: js">var n = null; +console.log(n * 32); // Will log 0 to the console +</pre> + +<h3 id="Variable_scope">Variable scope</h3> + +<p>Khi bạn khai báo một biến bên ngoài function, biến đó được gọi là <em>global </em>variable, bởi vì biến đó sẽ có hiệu lực đến bất kì đoạn code nào khác trong document hiện tại. Khi bạn khai báo một biến bên trong một function, nó gọi là <em>local </em>variable, vì nó chỉ có thể dùng được trong phạm vi function đó.</p> + +<p>Javascript trước phiên bản ECMAScript 6 không có định nghĩa <a href="/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Block_statement" title="en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Block_statement">block statement</a> scope; thay vào đó, một biến được khai báo trong một block được xem là có giá trị local đối với function (hoặc global scope) mà block đó cư trú.</p> + +<p>Ví dụ sau đây sẽ log ra <code>5</code>, vì scope của <code>x</code> là global context (hoặc function context nếu đoạn code này là một phần của function khác). Scope của <code>x</code> không bị giới hạn vào block câu lệnh <code>if</code> trực tiếp gần nhất.</p> + +<pre class="brush: js">if (true) { + var x = 5; +} +console.log(x); // 5 +</pre> + +<p>Điều này đã thay đổi khi sử dụng kiểu khai báo <code>let</code> được giới thiệu trong ECMAScript 6.</p> + +<pre class="brush: js">if (true) { + let y = 5; +} +console.log(y); // ReferenceError: y is not defined (y bị giới hạn trực tiếp trong block chứa nó) +</pre> + +<h3 id="Variable_hoisting">Variable hoisting</h3> + +<p>Một thứ không bình thường khác về các biến trong JavaScript là bạn có thể tham chiếu đến một biến tại vị trí phía trước câu lệnh khai báo. Khái niệm này gọi là <strong>hoisting</strong>; các biến trong JavaScript ở khía cạnh nào đó sẽ được "hoisted" (treo) hoặc lifted (nâng) vào vị trí trên cùng của câu lệnh hoặc hàm gần nó nhất. Tuy nhiên, các variables bị hoisted này sẽ trả về giá trị <code>undefined</code>. Nên cho dù bạn khai báo và khởi tạo sau khi bạn sử dụng hoặc tham chiếu đến biến này, thì trước đó nó vẫn trả về <code>undefined</code>.</p> + +<pre class="brush: js">/** + * Example 1 + */ +console.log(x); // undefined +var x = 3; +console.log(x); // 3 + +/** + * Example 2 + */ +// will return a value of undefined +var myvar = "my value"; + +(function() { + console.log(myvar); // undefined vì bên dưới có dòng khai báo var myvar, điều này làm biến myvar bị hoisting và nhận giá trị mới là undefined (giá trị 'my value' lúc này không còn hiệu lực vì biến đã bị hoisting) + var myvar = "local value"; +})(); +</pre> + +<p>Ví dụ bên trên có thể được biểu đạt theo cách khác như sau:</p> + +<pre class="brush: js">/** + * Example 1 + */ +var x; +console.log(x === undefined); // logs "true" +x = 3; + +/** + * Example 2 + */ +var myvar = "my value"; + +(function() { + var myvar; + console.log(myvar); // undefined + myvar = "local value"; +})(); +</pre> + +<p>Vì vấn đề hoisting này, tất cả các câu lệnh khai báo biến với <code>var</code> bên trong một function nên được đặt gần với đầu của function nhất có thể. Làm điều này giúp gia tăng độ rõ ràng của code (trường hợp dùng <code>var</code> như trong ví dụ 2 ở trên sẽ gây ra hoisting).</p> + +<h3 id="Function_hoisting">Function hoisting</h3> + +<p>Trong trường hợp của các function, chỉ các function được tạo theo kiểu function declaration là bị hoisted, còn function được tạo theo kiểu function expression thì không. Khác với variable hoisting, hoisted function không trả về giá trị mặc định <code>undefined</code>. Ví dụ:</p> + +<pre class="brush: js">/* Function declaration */ + +foo(); // "bar" + +function foo() { + console.log('bar'); +} + + +/* Function expression */ + +baz(); // TypeError: baz is not a function + +var baz = function() { + console.log('bar2'); +};</pre> + +<h3 id="Biến_toàn_cục_global_variables">Biến toàn cục (global variables)</h3> + +<p>Các global variables trên thực tế là những properties của global object. Trong các web page, global object chính là <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/API/Window" title="The Window interface represents a window containing a DOM document; the document property points to the DOM document loaded in that window."><code>window</code></a>, nên bạn có thể set và truy cập đến các global variables bằng cách sử dụng cú pháp <code>window.<em>variable</em></code><em>.</em></p> + +<p>Hệ quả là, bạn có thể truy cập đến các global variables được khai báo trong một window hoặc frame từ một window hoặc frame khác, bằng cách chỉ định rõ tên của window hoặc frame. Ví dụ, nếu một biến có tên <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">phoneNumber</span></font> được khai báo trong một document, bạn có thể tham chiếu đến biến này từ một <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">iframe</span></font> như là <code>parent.phoneNumber</code>.</p> + +<h3 id="Constants">Constants</h3> + +<p>Bạn có thể tạo các hằng số read-only với từ khóa {{jsxref("Statements/const", "const")}}. Cú pháp đặt tên cho hằng cũng giống như biến, tên hằng phải bắt đầu bằng một chữ cái, hoặc dấu gạch dưới <code>_</code>, hoặc dấu dollar <code>$</code>, và có thể bao gồm mọi ký tự chữ, số, hoặc dấu gạch dưới.</p> + +<pre class="brush: js">const PI = 3.14; +</pre> + +<p>Một hằng số đã khai báo không thể thay đổi giá trị thông qua việc gán lại giá trị hoặc không thể bị khai báo lại trong khi đoạn script đang chạy. Và bắt buộc phải được gán giá trị ngay khi khởi tạo.</p> + +<p>Các nguyên tắc về scope cho các hằng số cũng giống như cách các biến block-scoped như <code>let</code> hoạt động.</p> + +<p>Bạn không thể khai báo một hằng số với tên trùng với tên function hoặc biến trong cùng một scope. Ví dụ:</p> + +<pre class="example-bad brush: js">// THIS WILL CAUSE AN ERROR +function f() {}; +const f = 5; + +// THIS WILL CAUSE AN ERROR ALSO +function f() { + const g = 5; + var g; + + //statements +} +</pre> + +<p>Tuy nhiên, khi gán một object vào một hằng, thì các thuộc tính của object đó là not protected, nên câu lệnh dưới đây sẽ được thực thi mà không lỗi.</p> + +<pre>const MY_OBJECT = {'key': 'value'}; +MY_OBJECT.key = 'otherValue';</pre> + +<p>Cũng tương tự, các nội dung trong một mảng cũng là not protected, nên câu lệnh dưới đây sẽ được thực thi mà không lỗi.</p> + +<pre>const MY_ARRAY = ['HTML','CSS']; +MY_ARRAY.push('JAVASCRIPT'); +console.log(MY_ARRAY); //logs ['HTML','CSS','JAVASCRIPT'];</pre> + +<h2 id="Cấu_trúc_dữ_liệu_và_kiểu_dữ_liệu">Cấu trúc dữ liệu và kiểu dữ liệu</h2> + +<h3 id="Kiểu_dữ_liệu">Kiểu dữ liệu</h3> + +<p>Tiêu chuẩn mới nhất của ECMAScript định nghĩa 8 kiểu dữ liệu:</p> + +<ul> + <li>Bảy kiểu dữ liệu nguyên thủy {{Glossary("Primitive", "primitives")}}: + <ol> + <li>{{Glossary("Boolean")}}. <code>true</code> và <code>false</code>.</li> + <li>{{Glossary("null")}}. Một từ khóa đạc biệt biểu thị giá trị null. Vì JavaScript là case-sensitive, <code>null</code> sẽ không giống với <code>Null</code>, <code>NULL</code>, hoặc bất kỳ biến thể khác.</li> + <li>{{Glossary("undefined")}}. Một thuộc tính top-level mà giá trị của nó là không xác định.</li> + <li>{{Glossary("Number")}}. Một số nguyên (integer) hoặc số thực dấu chấm động (floating point number) <code>42</code> or <code>3.14159</code>.</li> + <li>{{Glossary("BigInt")}}. An integer with arbitrary precision. For example: <code>9007199254740992n</code>.</li> + <li>{{Glossary("String")}}. Một chuỗi các ký tự đại diện cho một giá trị văn bản. Ví dụ: "Howdy".</li> + <li>{{Glossary("Symbol")}} (new in ECMAScript 6). Một kiểu dữ liệu mà các instance của nó là duy nhất và bất biến.</li> + </ol> + </li> + <li>Và {{Glossary("Object")}}</li> +</ul> + +<p>Mặc dù những kiểu dữ liệu này tương đối ít, chúng cho phép bạn có thể thể hiện những hàm rất hữu dụng. {{jsxref("Object", "Objects")}} và {{jsxref("Function", "functions")}} là những phần tử nền tảng khác của JavaScript. Bạn có thể xem object như là những vùng chứa được đặt tên (named container) để phục vụ cho các giá trị, và các hàm là những quy trình thủ tục để đoạn script của bạn thi hành.</p> + +<h3 id="Chuyển_đổi_kiểu_dữ_liệu">Chuyển đổi kiểu dữ liệu</h3> + +<p>JavaScript là dynamically typed language. Điều đó có nghĩa bạn không cần phải chỉ định kiểu dữ liệu của biến khi bạn khai báo biến, và kiểu dữ liệu được tự động chuyển đổi khi cần thiết trong quá trình đoạn script được thực thi.</p> + +<p>Cho nên, ví dụ, bạn có thể định nghĩa một biến như sau:</p> + +<pre class="brush: js">var answer = 42; +</pre> + +<p>Và sau đó, bạn có thể gán cùng một biến này với một giá trị chuỗi, ví dụ:</p> + +<pre class="brush: js">answer = "Thanks for all the fish..."; +</pre> + +<p>Bởi vì JavaScript là dynamically typed, việc gán giá trị này sẽ không gây ra lỗi.</p> + +<h3 id="Các_số_và_toán_tử">Các số và toán tử '+'</h3> + +<p>Trong các biểu thức (expression) có sự liên quan giữa các giá trị numeric và string với toán tử <code>+</code>, JavaScript sẽ chuyển đổi giá trị số sang chuỗi. Ví dụ:</p> + +<pre class="brush: js">x = "The answer is " + 42 // "The answer is 42" +y = 42 + " is the answer" // "42 is the answer" +</pre> + +<p>Với tất cả mọi loại toán tử khác, JavaScript sẽ không chuyển đổi giá trị numeric sang string. Ví dụ:</p> + +<pre class="brush: js">"37" - 7 // 30 +"37" + 7 // "377" +</pre> + +<h3 id="Chuyển_từ_kiểu_chuỗi_string_sang_kiểu_số_number">Chuyển từ kiểu chuỗi (string) sang kiểu số (number)</h3> + +<p>Tong trường hợp một giá trị biểu thị một số nhưng lại được lưu trong bộ nhớ như là một chuỗi, có các phương thức để chuyển đổi.</p> + +<ul> + <li id="parseInt()_and_parseFloat()">{{jsxref("parseInt", "parseInt()")}}</li> + <li>{{jsxref("parseFloat", "parseFloat()")}}</li> +</ul> + +<p><code>parseInt</code> sẽ chỉ trả về các số nguyên, nên mục đích của nó là làm giảm bớt giá trị cho các số decimals. Thêm nữa, một thực hành tốt nhất cho <code>parseInt</code> là luôn luôn thêm vào nó tham số radix. Tham số radix được dùng để chỉ định hệ số học nào sẽ được sử dụng.</p> + +<pre>parseInt('101', 2) // 5</pre> + +<p>Một phương thức khác để nhận được giá trị số từ một chuỗi là dùng toán tử <code>+</code> </p> + +<pre class="brush: js">"1.1" + "1.1" = "1.11.1" +(+"1.1") + (+"1.1") = 2.2 +// Note: the parentheses are added for clarity, not required.</pre> + +<h2 id="Literals">Literals</h2> + +<p>Literals (nguyên văn), đại diện cho các giá trị trong JavaScript. Đây là những giá trị cố định - không phải biến - mà bạn cung cấp một cách <em>litterally </em>trong script của bạn. Phần này mô tả những kiểu literals sau đây:</p> + +<ul> + <li>{{anch("Array literals")}}</li> + <li>{{anch("Boolean literals")}}</li> + <li>{{anch("Floating-point literals")}}</li> + <li>{{anch("Integers")}}</li> + <li>{{anch("Object literals")}}</li> + <li>{{anch("String literals")}}</li> +</ul> + +<h3 id="Array_literals">Array literals</h3> + +<p>Một array literal là một danh sách của không hoặc nhiều biểu thức, mỗi biểu thức trong đó đại diện cho một phần tử của mảng (array element), được bao bọc trong dấu ngoặc vuông (<code>[]</code>). Khi bạn tạo một mảng bằng cách dùng array literal, nó được khởi tạo với những giá trị cụ thể như là các element của mảng, và <code>length</code> của mảng là số lượng đối số (argument).</p> + +<p>Ví dụ sau tạo ra mảng <code>coffees</code> với 3 phần tử và một <code>length</code> của 3:</p> + +<pre class="brush: js">var coffees = ["French Roast", "Colombian", "Kona"]; +</pre> + +<p><strong>Note: </strong>Một array literal là một kiểu của object initializer. Xem <a href="/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Using_object_initializers" title="en-US/docs/JavaScript/Guide/Working with Objects#Using Object Initializers">Using Object Initializers</a>.</p> + +<p>Nếu một mảng được tạo ra sử dụng một literal trong một top-level script, JavaScript sẽ interpret mảng mỗi lần nó đánh giá biểu thức có chứa array literal. Ngoài ra, một literal được sử dụng trong một hàm sẽ được tạo ra mỗi lần function được gọi.</p> + +<p><strong>Note: </strong>Các array literals cũng là các <code>Array</code> objects. Xem {{jsxref("Array")}} and <a href="/en-US/docs/Web/JavaScript/Guide/Indexed_collections">Indexed collections</a> để biết chi tiết về <code>Array</code> objects.</p> + +<h4 id="Dấu_phẩy_dư_trong_các_array_literals">Dấu phẩy dư trong các array literals</h4> + +<p>Bạn không cần phải xác định mọi phần tử trong một array literal. Nếu bạn đặt 2 dấu phẩy trên cùng một hàng, mảng sẽ tạo ra một phần tử mang giá trị <code>undefined</code>. Ví dụ sau tạo ra mảng <code>fish</code>.</p> + +<pre class="brush: js">var fish = ["Lion", , "Angel"]; +</pre> + +<p>Mảng này gồm 2 phần tử có giá trị và một phần tử rỗng (<code>fish[0]</code> là "Lion", <code>fish[1]</code> là <code>undefined</code>, và <code>fish[2]</code> là "Angel").</p> + +<p>Nếu bạn thêm một dấu phẩy theo sau (trailing comma) phần tử cuối cùng của mãng, dấu phẩy này sẽ bị bỏ qua. Trong ví dụ sau, <code>length</code> của mảng là 3. Không có <code>myList[3]</code>. Tất cả dấu phẩy khác trong danh sách ngầm chỉ định là một phần tử mới. (<strong>Note:</strong> trailing commas có thể xem là lỗi đối với các trình duyệt cũ và tốt nhất là nên xóa chúng đi).</p> + +<pre class="brush: js">let myList = ['home', , 'school', ]; +</pre> + +<p>Trong ví dụ bên dưới, <code>length</code> của mảng là 4, <code>myList[0]</code> và <code>myList[2]</code> bị thiếu.</p> + +<pre class="brush: js">var myList = [ , 'home', , 'school']; +</pre> + +<p>Trong ví dụ dưới, <code>length</code> của mảng là 4, <code>myList[1]</code> và <code>myList[3]</code> bị thiếu. <strong>Chỉ có dấu phẩy cuối cùng bị bỏ qua.</strong></p> + +<pre class="brush: js">var myList = ['home', , 'school', , ]; +</pre> + +<p>Hiểu được hành vi của cac dấu phẩy thêm này rất quan trọng để hiểu được JavaScript như là một ngôn ngữ. Tuy nhiên, khi viết code của riêng bạn, bạn nên khai báo một cách rõ ràng các phần tử bị thiếu (missing elements) là <code>undefined</code>. Làm vậy sẽ gia tăng độ rõ ràng cho code và dễ bảo trì sau này.</p> + +<h3 id="Boolean_literals">Boolean literals</h3> + +<p>Kiểu Boolean có 2 giá trị literal: <code>true</code> và<code>false</code>.</p> + +<p><strong>Cẩn thận:</strong> Đừng nhầm lẫn giá trị Boolean nguyên thủy <code>true</code> và <code>false</code> với true và fales của {{jsxref("Boolean")}} object. Boolean object là một lớp bao bên ngoài kiểu dữ liệu Boolean nguyên thủy. Xem {{jsxref("Boolean")}} để biết thêm.</p> + +<h3 id="Numeric_literals">Numeric literals</h3> + +<p>Kiểu dữ liệu {{jsxref("Number")}} và {{jsxref("BigInt")}} có thể được biểu diễn bằng hệ decimal (hệ 10), hệ hexadecimal (hệ 16), octal (hệ 8) và binary (base 2 - hệ nhị phân).</p> + +<ul> + <li>Một <em>decimal</em> numeric literal là một dãy liên tục của các chữ số mà không dẫn đầu bởi số <code>0</code> (zero).</li> + <li>Ký tự số <code>0</code> (zero) dẫn đầu trên một numeric literal, hoặc <code>0o</code> (hoặc <code>0O</code>) ám chỉ rằng nó nằm trong hệ <em>octal. Octal numerics chỉ gồm các ký tự số từ </em><code>0</code>-<code>7</code>.</li> + <li><code>0x</code> (hoặc <code>0X</code>) ám chỉ kiểu dữ liệu <em>hexadecimal </em>numeric. Hexadecimal numerics có thể gồm các ký tự số (<code>0</code>-<code>9</code>) và các chữ cái <code>a-f</code> và <code>A-F</code>. (Việc viết hoa chữ cái sẽ không làm thay đối giá trị của nó. Vì vậy <code>0xa</code> = <code>0xA</code> = <code>10</code> và <code>0xf</code> = <code>0xF</code> = <code>15</code>).</li> + <li>Một ký tự <code>0b</code> (hoặc <code>0B</code>) dẫn đầu ám chỉ hệ nhị phân <em>binary </em>numeric literal. Binary numerics chỉ có thể bao gồm ký tự <code>0</code> và <code>1</code>.</li> +</ul> + +<p>Một số ví dụ của numeric literals:</p> + +<pre class="eval">0, 117, -345, 123456789123456789n (decimal, base 10) +015, 0001 -0o77, 0o777777777777n (octal, base 8) +0x1123, 0x00111, -0xF1A7, 0x123456789ABCDEFn (hexadecimal, "hex" or base 16) +0b11, 0b0011, -0b11, 0b11101001010101010101n (binary, base 2) +</pre> + +<p>Chi tiết xem thêm tại: <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Numeric_literals">Numeric literals in the Lexical grammar reference</a>.</p> + +<h3 id="Floating-point_literals">Floating-point literals</h3> + +<p>Một floating-point literal (literal số thực dấu chấm động) có thể có các bộ phận sau:</p> + +<ul> + <li>Một số nguyên hệ 10 decimal integer (có thể thêm vào trước "<code>+</code>" hoặc "<code>-</code>"),</li> + <li>Một dấu chấm hệ 10 ("<code>.</code>"), </li> + <li>Một phần thập phân (một số hệ 10 khác),</li> + <li>Một số mũ.</li> +</ul> + +<p>Bộ phận số mũ là một ký tự "<code>e</code>" hoặc "<code>E</code>", theo sau nó là một số nguyên integer (số nguyên integer này có thể có thêm phía trước là dấu "<code>+</code>" hoặc "<code>-</code>"). Một floating-point literal phải có ít nhất một ký tự số, và hoặc là một dấu chấm hệ 10 hoặc là ký tự "<code>e</code>" (hoặc "<code>E</code>"). Tóm lại, cú pháp như sau:</p> + +<pre class="eval">[(+|-)][digits][.digits][(E|e)[(+|-)]digits] +</pre> + +<p>Ví dụ: </p> + +<pre class="eval">3.1415926 +-.123456789 +-3.1E+12 +.1e-23 +</pre> + +<h3 id="Object_literals">Object literals</h3> + +<p>Một object literal là một danh sách của không hoặc nhiều cặp property names và associated values (tên thuộc tính và giá trị được liên kết) của một một object, bao bọc bởi cặp dấu ngoặc nhọn (<code>{}</code>).</p> + +<p>Lưu ý đừng sử dụng một object literal ngay tại vị trí bắt đầu của một câu lệnh! Điều này sẽ dẫn đến một lỗi (hoặc nó sẽ thực thi theo cách bạn không mong muốn), vì dấu mở ngoặc nhọn <code>{</code> sẽ được interpreted như là bắt đầu của một block.</p> + +<p>Ví dụ dưới đây là một ví dụ của object literal. Phần tử đầu tiên của object <code>car</code> định nghĩa là một thuộc tính (property), <code>myCar</code>, và được gán giá trị kiểu chuỗi là "<code>myCar</code>", phần tử thứ 2, thuộc tính <code>getCar</code>, ngay lập tức được gán giá trị là kết quả trả về của việc gọi hàm <code>(CarTypes("Honda"));</code> phần tử thứ 3, thuộc tính <code>special</code>, sử dụng một biến đã tồn tại (<code>sales</code>).</p> + +<pre class="brush: js">var Sales = "Toyota"; + +function CarTypes(name) { + if (name == "Honda") { + return name; + } else { + return "Sorry, we don't sell " + name + "."; + } +} + +var car = { myCar: "Saturn", getCar: CarTypes("Honda"), special: Sales }; + +console.log(car.myCar); // Saturn +console.log(car.getCar); // Honda +console.log(car.special); // Toyota +</pre> + +<p>Thêm nữa, bạn có thể sử dụng cả kiểu số hoặc chữ để đặt tên cho thuộc tính của object, hoặc bạn có thể lồng một object bên trong một object khác. Ví dụ:</p> + +<pre class="brush: js">var car = { manyCars: {a: "Saab", "b": "Jeep"}, 7: "Mazda" }; + +console.log(car.manyCars.b); // Jeep +console.log(car[7]); // Mazda +</pre> + +<p>Các tên thuộc tính của object có thể là bất kỳ chuỗi nào, bao gồm cả chuỗi rỗng <code>''</code>. Nếu tên thuộc tính không phải là một JavaScript <a href="/en-US/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Variables">identifier</a> hợp lệ, hoặc nó là số, thì nó phải được bao bọc trong các dấu nháy.</p> + +<p>Các tên thuộc tính mà không phải là các identifier hợp lệ không thể được truy cập đến như các thuộc tính thông thường là dùng dấu chấm (<code>.</code>), nhưng <em>có thể</em> được truy cập đến và set giá trị bằng cặp dấu ngoặc vuông giống mảng ("<code>[]</code>").</p> + +<pre class="brush: js">var unusualPropertyNames = { + "": "An empty string", + "!": "Bang!" +} +console.log(unusualPropertyNames.""); // SyntaxError: Unexpected string +console.log(unusualPropertyNames[""]); // An empty string +console.log(unusualPropertyNames.!); // SyntaxError: Unexpected token ! +console.log(unusualPropertyNames["!"]); // Bang!</pre> + +<p>Please note:</p> + +<pre class="brush: js">var foo = {a: "alpha", 2: "two"}; +console.log(foo.a); // alpha +console.log(foo[2]); // two +//console.log(foo.2); // Error: missing ) after argument list +//console.log(foo[a]); // Error: a is not defined +console.log(foo["a"]); // alpha +console.log(foo["2"]); // two +</pre> + +<h4 id="Enhanced_Object_literals">Enhanced Object literals</h4> + +<p>Trong ES2015, các object literals được mở rộng từ đó hỗ trợ thêm việc cài đặt các prototype tại construction, shorthand cho việc gán biến <code>foo: foo</code>, các phương thức defining, make <code>super</code> calls, và xử lý các tên thuộc tính với các biểu thức. Cùng nhau, những thứ này cũng mang object listerals và khai báo <code>class</code> đến gần nhau hơn, và cho phép các thiết kế object-based để đạt được lợi ích từ một số tiện nghi giống nhau.</p> + +<pre>var obj = { + // __proto__ + __proto__: theProtoObj, + // Shorthand for ‘handler: handler’ + handler, + // Methods + toString() { + // Super calls + return 'd ' + super.toString(); + }, + // Computed (dynamic) property names + [ 'prop_' + (() => 42)() ]: 42 +};</pre> + +<h3 id="RegExp_literals">RegExp literals</h3> + +<p>Một regex literal (được định nghĩa chi tiết <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">sau đây</a>) là một mô hình mẫu bao bọc giữa các dấu xuyệt <code>/</code>. Ví dụ:</p> + +<pre>var re = /ab+c/;</pre> + +<h3 id="String_literals">String literals</h3> + +<p>Một string literal là không có hoặc có nhiều ký tự bao bọc trong dấu (<code>"</code>) hoặc (<code>'</code>). Một chuỗi (string) phải được giới hạn trong cặp dấu cùng loại; hoặc là cùng nháy đơn hoặc là cùng nháy kép. Ví dụ:</p> + +<ul> + <li><code>"foo"</code></li> + <li><code>'bar'</code></li> + <li><code>"1234"</code></li> + <li><code>"one line \n another line"</code></li> + <li><code>"John's cat"</code></li> +</ul> + +<p>Bạn có thể gọi các phương thức của {{jsxref("String")}} object lên một giá trị string nguyên văn (string literal) - JavaScript tự động chuyển đổi string literal sang một String object tạm, gọi phương thức để chạy, chạy xong hủy bỏ String object tạm đó. Bạn cũng có thể sử dụng thuộc tính <code>String.length</code> với một string literal:</p> + +<pre class="brush: js">console.log("John's cat".length) +// Will print the number of symbols in the string including whitespace. +// In this case, 10. +</pre> + +<p>Trong ES2015, <em>template literals</em> cũng được đưa vào sử dụng. Template literals bao bọc trong dấu back-tick (<code>`</code>) (<a href="http://en.wikipedia.org/wiki/Grave_accent" rel="noopener">dấu huyền</a>) thay vì dấu nháy đơn hay nháy kép.</p> + +<p>Các template strings cung cấp cú pháp đặc biệt (synctactic sugar) để xây dựng các chuỗi (string). (Điều này tương tự với đặc điểm nội suy chuỗi string interpolation trong Perl, Python, v.v...)</p> + +<p>Tùy trường hợp, một thẻ tag có thể được thêm vào để cho phép việc xây dựng chuỗi được tùy chỉnh, tránh injection attacks, hoặc xây dựng nên những cấu trúc dữ liệu higher-level từ các nội dung của chuỗi.</p> + +<pre>// Basic literal string creation +// `In JavaScript '\n' is a line-feed.` + +// Multiline strings +`In JavaScript, template strings can run + over multiple lines, but double and single + quoted strings cannot.` + +// String interpolation +var name = 'Bob', time = 'today'; +`Hello ${name}, how are you ${time}?` + +// Construct an HTTP request prefix used to interpret the replacements and construction +POST`http://foo.org/bar?a=${a}&b=${b} + Content-Type: application/json + X-Credentials: ${credentials} + { "foo": ${foo}, + "bar": ${bar}}`(myOnReadyStateChangeHandler); +</pre> + +<p>Bạn nên sử dụng các string literals đơn thuần nếu không cần thiết phải sử dụng đến String object. Xem {{jsxref("String")}} để biết chi tiết về <code>String</code> objects.</p> + +<h4 id="Sử_dụng_các_ký_tự_đặc_biệt_trong_chuỗi">Sử dụng các ký tự đặc biệt trong chuỗi</h4> + +<p>Ngoài các ký tự thông thường, bạn cũng có thể thêm vào các ký tự đặc biệt trong chuỗi, ví dụ:</p> + +<pre class="brush: js">"one line \n another line" +</pre> + +<p>Bảng dưới đây liệt kê danh sách các ký tự đặc biệt có thể sử dụng trong các chuỗi JavaScript.</p> + +<table class="standard-table"> + <caption>Table: JavaScript special characters</caption> + <thead> + <tr> + <th scope="col">Character</th> + <th scope="col">Meaning</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>\0</code></td> + <td>Null Byte</td> + </tr> + <tr> + <td><code>\b</code></td> + <td>Backspace - Khoảng cách</td> + </tr> + <tr> + <td><code>\f</code></td> + <td>Form feed -</td> + </tr> + <tr> + <td><code>\n</code></td> + <td>New line - Dòng mới</td> + </tr> + <tr> + <td><code>\r</code></td> + <td>Carriage return</td> + </tr> + <tr> + <td><code>\t</code></td> + <td>Tab - Tab một tab</td> + </tr> + <tr> + <td><code>\v</code></td> + <td>Vertical tab - Tab dọc</td> + </tr> + <tr> + <td><code>\'</code></td> + <td>Apostrophe or single quote - trích dẫn đơn</td> + </tr> + <tr> + <td><code>\"</code></td> + <td>Double quote - ngoặc kép.</td> + </tr> + <tr> + <td><code>\\</code></td> + <td>Backslash character</td> + </tr> + <tr> + <td><code>\<em>XXX</em></code></td> + <td>The character with the Latin-1 encoding specified by up to three octal digits <em>XXX</em> between 0 and 377. For example, \251 is the octal sequence for the copyright symbol.</td> + </tr> + <tr> + </tr> + <tr> + <td><code>\x<em>XX</em></code></td> + <td>The character with the Latin-1 encoding specified by the two hexadecimal digits <em>XX</em> between 00 and FF. For example, \xA9 is the hexadecimal sequence for the copyright symbol.</td> + </tr> + <tr> + </tr> + <tr> + <td><code>\u<em>XXXX</em></code></td> + <td>The Unicode character specified by the four hexadecimal digits <em>XXXX</em>. For example, \u00A9 is the Unicode sequence for the copyright symbol. See {{anch("Unicode escape sequences")}}.</td> + </tr> + </tbody> +</table> + +<h4 id="Escaping_characters">Escaping characters</h4> + +<p>Đối với các ký tự không có trong bảng trên, dấu backslash <code>\</code> được thêm vào trước sẽ bị bỏ qua, nhưng cách dùng này đã không còn nữa và nên được tránh dùng.</p> + +<p>Bạn có thể chèn vào một dấu ngoặc kép bên trong một chuỗi bằng cách đặt phía trước nó một dấu backslash <code>\</code>. Điều này tức là escaping dấu trích dẫn. Ví dụ:</p> + +<pre class="brush: js">var quote = "He read \"The Cremation of Sam McGee\" by R.W. Service."; +console.log(quote); +</pre> + +<p>Kết quả của đoạn code trên là:</p> + +<pre class="eval">He read "The Cremation of Sam McGee" by R.W. Service. +</pre> + +<p>Để thêm một dấu backslash thật sự vào trong chuỗi, bạn phải escape dấu backslash đó. Ví dụ, để gán dường dẫn file <code>c:\temp</code> vào một chuỗi:</p> + +<pre class="brush: js">var home = "c:\\temp"; +</pre> + +<p>Bạn cũng có thể escape các line breaks bằng cách đặt vào trước chúng một dấu backslash. Backslash và line break đều sẽ được remove khỏi giá trị của chuỗi.</p> + +<pre class="brush: js">var str = "this string \ +is broken \ +across multiple\ +lines." +console.log(str); // this string is broken across multiplelines. +</pre> + +<p>Mặc dù JavaScript không có cú pháp "heredoc", bạn có thể gần đạt được điều này bằng cách thêm vào một linebreak escape và một escaped linebreak ở cuối mỗi dòng:</p> + +<pre class="brush: js">var poem = +"Roses are red,\n\ +Violets are blue.\n\ +I'm schizophrenic,\n\ +And so am I." +</pre> + +<h2 id="Thông_tin_thêm">Thông tin thêm</h2> + +<p>Chương này tập trung vào cú pháp cơ bản cho các việc khai báo và các kiểu dữ liệu. Để biết rõ hơn về cấu trúc ngôn ngữ JavaScript, xem các chương tiếp theo trong bộ hướng dẫn này:</p> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling">Control flow and error handling</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">Loops and iteration</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions">Functions</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators">Expressions and operators</a></li> +</ul> + +<p>Trong chương tiếp theo, chúng ta sẽ tìm hiểu về control flow constructs và error handling.</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}</p> diff --git a/files/vi/web/javascript/guide/details_of_the_object_model/index.html b/files/vi/web/javascript/guide/details_of_the_object_model/index.html new file mode 100644 index 0000000000..12101a6ddf --- /dev/null +++ b/files/vi/web/javascript/guide/details_of_the_object_model/index.html @@ -0,0 +1,742 @@ +--- +title: Details of the object model +slug: Web/JavaScript/Guide/Details_of_the_Object_Model +translation_of: Web/JavaScript/Guide/Details_of_the_Object_Model +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Using_promises")}}</div> + +<p class="summary">JavaScript là một ngôn ngữ dựa trên đối tượng và nguyên mẫu, hơn là dựa trên class. Bởi vì điều này, làm nó kém rõ ràng về cách mà JavaScript cho phép chúng ta tạo cấu trúc cây của đối tượng cũng như tạo sự kế thừa cho thuộc tính và giá trị của chúng. Chương này cố gắng làm rõ đặc điểm này.</p> + +<p>Chương này giả định rằng bạn đã hiểu căn bản JavaScript và bạn đã sử dụng hàm của JavaScript để tạo đối tượng đơn giản.</p> + +<h2 id="Ngôn_ngữ_Class-based_vs._Ngôn_ngữ_prototype-based">Ngôn ngữ Class-based vs. Ngôn ngữ prototype-based</h2> + +<p>Ngôn ngữ dựa theo class, ví dụ Java và C++, tách biệt 2 thực thể chính: lớp (class) và thực thể (instance).</p> + +<ul> + <li>Một class định nghĩa tất cả các thuộc tính mà nó quy định tính chất của tập các object (xem phương thức và trường trong Java, hay thành viên trong C++, như là những thuộc tính). Một class là sự trù tượng hơn là một thành viên cụ thể của tập các object mà nó mô tả. Ví dụ, <code>Employee</code> class có thể biểu diễn tập hợp của tất cả employee.</li> + <li>Mặt khác một thực thể (instance) là một thực thể của một class, và là một trong những thành viên của nó. Ví dụ, <code>Victoria</code> có thể là một thực thể của <code>Employee</code> class, nó đại diện cho một cá nhân như là một employee. Một thực thể có chính xác cùng thuộc tính của class cha của nó (không hơn, không kém).</li> +</ul> + +<p>Ngôn ngữ dựa trên nguyên mẫu, như JavaScript, không tách biệt điều này, nó đơn giản chỉ là những object. Một ngôn ngữ dựa trên nguyên mẫu có ký hiệu của một <em>prototypical object</em>, một object được dùng làm mẫu mà từ mẫu đó nó tạo ra thuộc tính cho object mới. Hơn nữa, bất kỳ object nào cũng có thể được liên kết để dùng làm nguyên mẫu của một object khác, điều này cho phép object thứ hai chia sẽ thuộc tính với object thứ nhất.</p> + +<h3 id="Định_nghĩa_một_class">Định nghĩa một class</h3> + +<p>Ngôn ngữ dựa trên class, bạn định nghĩa một class bằng từ khóa định nghĩa class riêng biệt rõ ràng. Trong đó bạn có thể chỉ định phương thức đặc biệt, gọi là hàm dựng, để khởi tạo thực thể của class. Một hàm dựng có thể khởi tạo giá trị cho thuộc tính của thực thể và thực hiện những xử lý phù hợp tại thời điểm đó. Bạn có thể dùng toán tử <code>new</code> cùng với tên class để tạo thực thể của class.</p> + +<p>JavaScript cũng dùng mô hình tương tự, nhưng không có từ khóa riêng biệt để định nghĩa class (với phiên bản trước ES6). Thay vào đó, bạn có thể định nghĩa hàm dựng để tạo object với tập hợp các giá trị và thuộc tính ban đầu. Bất kỳ hàm JavaScript nào cũng có thể dùng như là constructor. Bạn có thể dùng từ toán tử <code>new</code> với hàm dựng để tạo object mới.</p> + +<h3 id="Class_con_và_sự_kế_thừa">Class con và sự kế thừa</h3> + +<p>Trong ngôn ngữ dựa trên class, bạn tạo cây thứ tự của class thông qua những định nghĩa class. Khi định nghĩa một class, bạn có thể chỉ định class đang tạo là class con của một class khác đang tồn tại. Class con kế thừa tất cả các thuộc tính của class cha và có thể thêm vào những thuộc tính mới hoặc chỉnh sửa thuộc tính được kế thừa. Ví dụ, giả sử class <code>Employee</code> chỉ có thuộc tính <code>name</code> và <code>dept</code>, và <code>Manager</code> là class con của <code>Employee</code> và định nghĩa thêm thuộc tính <code>reports</code>. Trong trường hợp này thực thể của class <code>Manager</code> sẽ có ba thuộc tính: <code>name</code>, <code>dept</code>, and <code>reports</code></p> + +<p>JavaScript cài đặt tính kế thừa bằng cách cho phép bạn liên kết một object mẫu với bất kỳ hàm dựng nào. Vì vậy, bạn có thể tạo chính xác như ví dụ <code>Employee</code> — <code>Manager</code> trên, nhưng thuật cú pháp sẽ nhưng hơi khác một tí. Trước tiên bạn định nghĩa hàm dựng <code>Employee</code>, và trong thân hàm khởi tạo thuộc tính <code>name</code> và <code>dept</code>. Tiếp theo bạn định nghĩa hàm dựng <code>Manager</code>, mà nó gọi hàm dựng <code>Employee</code> và khởi tạo thuộc tính <code>reports</code>. Cuối cúng bạn gán object mới kế thừa từ <code>Employee.prototype</code> như <code>prototype</code> cho hàm được dựng <code>Manager</code>. Sau đó, khi tạo một thực thể <code>Manager</code> mới, nó sẽ kế thừa thuộc tính <code>name</code> và <code>dept</code> của <code>Employee</code>.</p> + +<h3 id="Việc_thêm_và_xóa_những_thuộc_tính">Việc thêm và xóa những thuộc tính</h3> + +<p>Trong ngôn ngữ dựa trên class, bạn thông thường tạo một class lúc biên dịch và rồi bạn khởi tạo thực thể của class tại lúc biên dịch hoặc lúc thực thi. Bạn không thể thay đổi số lượng và kiểu của thuộc tính của class sau khi bạn định nghĩa class. Trong JavaScript, bạn có thể thêm hoặc xóa thuộc tính của bất kỳ object nào. Nếu bạn thêm một thuộc tính của một object mà được sử dụng như prototype của một tập các object, những object đó cũng sẽ có những thuộc tính mới.</p> + +<h3 id="Tóm_tắt_lại_những_khác_biệt">Tóm tắt lại những khác biệt</h3> + +<p>Sau đây là bản tóm tắt ngắn những khác biệt. Phần còn lại của chương mô tả chi tiết việc sử dụng hàm dựng của JavaScript và prototype để tạo cấu trúc cây đối tượng và so sánh với phương pháp tương tự trong Java.</p> + +<table class="standard-table"> + <caption>So sánh class-based (Java) và prototype-based (JavaScript)</caption> + <thead> + <tr> + <th scope="col">Class-based (Java)</th> + <th scope="col">Prototype-based (JavaScript)</th> + </tr> + </thead> + <tbody> + <tr> + <td>Class và thực thể của nó là hai đối tượng riêng biệt.</td> + <td>Tất cả đối tượng có thể kế thừa từ một đối tượng khác.</td> + </tr> + <tr> + <td>Dùng cú pháp riêng của class để định nghĩa class; khởi tạo thực thể của class dùng hàm dựng của class.</td> + <td>Định nghĩa và tạo một tập các đối tượng chỉ với hàm dựng.</td> + </tr> + <tr> + <td>Tạo object đơn với toán tử <code>new</code>.</td> + <td>Cùng cách như class-based.</td> + </tr> + <tr> + <td>Xây dựng cấu trúc cây object bằng cách sử dụng định nghĩa class để tạo class con của class đang tồn tại.</td> + <td>Xây dựng cấu trúc cây object bằng cách gán một object như prototype của hàm dựng.</td> + </tr> + <tr> + <td>Kế thừa thuộc tính theo cơ chế class nối tiếp.</td> + <td>Kế thừa những thuộc tính theo cơ chế prototype nối tiếp.</td> + </tr> + <tr> + <td>Khi định nghĩa class, bạn chỉ định tất cả các thuộc tính của các thực thể của class. Và không thể thêm thuộc tính mới lúc thực thi.</td> + <td>Hàm dựng và prototype chỉ định giá trị ban đầu của thuộc tính. Và có thể thêm hoặc xoá thuộc tính động trên từng đối tượng hoặc toàn bộ các object.</td> + </tr> + </tbody> +</table> + +<h2 id="Ví_dụ_Employee">Ví dụ Employee</h2> + +<p>Phần còn lại của chương này sử dụng cấu trúc cây nhân viên được trình bày như hình bên dưới.</p> + +<div style="display: table-row;"> +<div style="display: table-cell; width: 350px; text-align: center; vertical-align: middle; padding: 10px;"> +<p>Cấu trúc cây object đơn giản:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/3060/figure8.1.png"></p> +</div> + +<div style="display: table-cell; vertical-align: middle; padding: 10px;"> +<ul> + <li><code>Employee</code> có những thuộc tính <code>name</code> (mà có giá trị mặc định là một chuỗi rỗng) và <code>dept</code> (mà giá trị mặc định là chuỗi "general").</li> + <li><code>Manager</code> kế thừa từ <code>Employee</code>. Nó thêm thuộc tính <code>reports</code> (mà giá trị mặc định là một mảng rỗng sẽ dùng để lưu một mảng các <code>Employee</code> object)</li> + <li><code>WorkerBee</code> cũng kế thừa từ <code>Employee</code>. Nó thêm thuộc tính <code>projects</code> (mà có giá trị mặc định là một mảng rỗng sẽ dùng để lưu trữ một mảng các giá trị kiểu chuỗi).</li> + <li><code>SalesPerson</code> kế thừa từ <code>WorkerBee</code>. Nó thêm thuộc tính <code>quota</code> (mà có giá trị mặc định là 100). Nó cũng ghi đè giá trị của thuộc tính <code>dept</code> với giá trị "sales", để chỉ ra rằng tất cả salespersons thuộc cùng phòng ban.</li> + <li><code>Engineer</code> kế thừa <code>WorkerBee</code>. Nó thêm vào thuộc tính <code>machine</code> (mà có giá trị mặc định là chuỗi rỗng) và cũng ghi đè thuộc tính <code>dept</code> với giá trị "engineering".</li> +</ul> +</div> +</div> + +<h2 id="Tạo_hệ_thống_cấp_bậc">Tạo hệ thống cấp bậc</h2> + +<p>Có một vài cách để định nghĩa hàm dựng thích hợp để cài đặt hệ thống cấp bậc của nhân viên. Cách bạn muốn chọn để định nghĩa phụ thuộc phần lớn vào những gì bạn muốn làm trong ứng dụng của bạn.</p> + +<p>Phần này sẽ trình bày cách định nghĩa rất đơn giản để minh họa cách thực hiện sự kế thừa. Trong định nghĩa này, bạn không thể chỉ định giá trị nào cho thuộc tính khi bạn tạo một object. Một cách đơn giản một object mới được ra và nhận những thuộc tính với giá trị mặc định, sau đó bạn có thể thay đổi giá trị của những thuộc tính đó.</p> + +<p>Trong ứng dụng thực tế, bạn có thể định nghĩa hàm dựng mà cho phép bạn cung cấp những giá trị của thuộc tính tại thời điểm tạo object (xem thêm <a href="#More_flexible_constructors">More flexible constructors</a>). Bây giờ, ta chỉ dùng cách đơn giản để minh họa sự kế thừa.</p> + +<p>Việc định nghĩa <code>Employee</code> trong Java và JavaScript thì khá tương tự. Sự khác biệt chỉ là bạn cần chỉ định kiểu của mỗi thuộc tính trong Java nhưng không cần trong JavaScript (bởi vì Java là ngôn ngữ <a href="http://en.wikipedia.org/wiki/Strong_and_weak_typing">kiểu ràng buộc mạnh</a> trong khi JavaScript là ngôn ngữ kiểu rành buộc yếu.</p> + +<div class="twocolumns"> +<h4 id="JavaScript">JavaScript</h4> + +<pre class="brush: js">function Employee() { + this.name = ''; + this.dept = 'general'; +} +</pre> + +<h4 id="Java"><br> + Java</h4> + +<pre class="brush: java">public class Employee { + public String name = ""; + public String dept = "general"; +} +</pre> +</div> + +<p>Việc định nghĩa <code>Manager</code> và <code>WorkerBee</code> chỉ ra sự khác nhau trong cách chỉ định đối tượng cấp cao hơn trong chuỗi kế thừa nối tiếp. Trong JavaScript, bạn có thể thêm nguyên mẫu (trở thành class cha) như là thuộc tính <code>prototype</code> của hàm dựng, rồi ghi đè <code>prototype.constructor</code> lên hàm dựng. Bạn có thể làm điều này bất kỳ thời điểm nào sau khi đã định nghĩa hàm dựng. Trong Java, bạn chỉ định class cha trong khi định nghĩa class. Bạn không thể thay đổi class cha sau khi định nghĩa class.</p> + +<div class="twocolumns"> +<h4 id="JavaScript_2">JavaScript</h4> + +<pre class="brush: js">function Manager() { + Employee.call(this); + this.reports = []; +} +Manager.prototype = Object.create(Employee.prototype); +Manager.prototype.constructor = Manager; + +function WorkerBee() { + Employee.call(this); + this.projects = []; +} +WorkerBee.prototype = Object.create(Employee.prototype); +WorkerBee.prototype.constructor = WorkerBee; +</pre> + +<h4 id="Java_2"><br> + Java</h4> + +<pre class="brush: java">public class Manager extends Employee { + public Employee[] reports = + new Employee[0]; +} + + + +public class WorkerBee extends Employee { + public String[] projects = new String[0]; +} + + +</pre> +</div> + +<p> </p> + +<p>Việc định nghĩa <code>Engineer</code> và <code>SalesPerson</code> giúp tạo objects theo thứ tự giảm dần từ <code>Employee</code> rồi xuống <code>WorkerBee</code>. Một object được tạo ra từ lớp con sẽ có tất cả thuộc tính của lớp cha ở trên trong chuỗi nối tiếp đó. Hơn nữa những định nghĩa ở lớp con có thể ghi đè những giá trị kế thừa từ lớp cha.</p> + +<div class="twocolumns"> +<h4 id="JavaScript_3">JavaScript</h4> + +<pre class="brush: js">function SalesPerson() { + WorkerBee.call(this); + this.dept = 'sales'; + this.quota = 100; +} +SalesPerson.prototype = Object.create(WorkerBee.prototype); +SalesPerson.prototype.constructor = SalesPerson; + +function Engineer() { + WorkerBee.call(this); + this.dept = 'engineering'; + this.machine = ''; +} +Engineer.prototype = Object.create(WorkerBee.prototype) +Engineer.prototype.constructor = Engineer; +</pre> + +<h4 id="Java_3"><br> + Java</h4> + +<pre class="brush: java">public class SalesPerson extends WorkerBee { + public String dept = "sales"; + public double quota = 100.0; +} + + +public class Engineer extends WorkerBee { + public String dept = "engineering"; + public String machine = ""; +} + +</pre> +</div> + +<p>Với việc sử dụng cách định nghĩa này, bạn có thể tạp hóa việc khởi tạo giá trị cho thuộc tính của thực thể với những giá trị mặc định cho các thuộc tính. Hình tiếp theo sẽ minh họa việc sử dụng cách định nghĩa trong JavaScript để tạo những object mới và hiển thị giá trị của thuộc tính của những object đó.</p> + +<div class="note"> +<p><strong>Lưu Ý:</strong> Thuật ngữ thực thể (instance) có ý nghĩa kỹ thuật cụ thể trong ngôn ngữ class-based. Trong ngôn ngữ này, một thực thể (instance) là một thực thể riêng biệt của class và là tách biệt với class. Trong JavaScript, "thực thể" không có khái niệm kỹ thuật riêng bởi vì JavaScript không tách biệt sự khác nhau giữa class và instance. Tuy nhiên, khi nói về JavaScript, "thực thể" có thể được sử dụng để ám chỉ những object được tạo ra bằng hàm dựng. Vì vậy, trong ví dụ này, bạn có thể nói <code><code>jane</code></code> là một thực thể của <code><code>Engineer</code></code>. Tương tự, mặc dù những thuật ngữ <em><em>parent</em>, <em>child</em>, <em>ancestor</em></em>, và <em><em>descendant</em></em> không có ý nghĩa chính thống trong JavaScript, bạn có thể sử dụng chúng để ám chỉ những đối tượng cấp cao hơn hoặc thấp hơn trong cây thừa kế.</p> +</div> + +<h3 id="Việc_tạo_những_đối_tượng_bằng_cách_đơn_giản">Việc tạo những đối tượng bằng cách đơn giản</h3> + +<div class="twocolumns"> +<h4 id="Cây_object">Cây object</h4> + +<p>Cây sau được tạo ra bằng những câu lệnh ở bên phải.</p> + +<p><img src="https://mdn.mozillademos.org/files/10412/=figure8.3.png"></p> + +<p> </p> + +<h4 id="Individual_objects_Jim_Sally_Mark_Fred_Jane_etc._Instances_created_from_constructor">Individual objects = Jim, Sally, Mark, Fred, Jane, etc.<br> + "Instances" created from constructor</h4> + +<pre class="brush: js">var jim = new Employee; +// Parentheses can be omitted if the +// constructor takes no arguments. +// jim.name is '' +// jim.dept is 'general' + +var sally = new Manager; +// sally.name is '' +// sally.dept is 'general' +// sally.reports is [] + +var mark = new WorkerBee; +// mark.name is '' +// mark.dept is 'general' +// mark.projects is [] + +var fred = new SalesPerson; +// fred.name is '' +// fred.dept is 'sales' +// fred.projects is [] +// fred.quota is 100 + +var jane = new Engineer; +// jane.name is '' +// jane.dept is 'engineering' +// jane.projects is [] +// jane.machine is '' +</pre> +</div> + +<h2 id="Thuộc_tính_của_Object">Thuộc tính của Object</h2> + +<p>Phần này mô tả cách mà những thuộc tính của những object có thể được kế thừa từ object khác trong chuỗi prototype và điều gì xãy ra khi bạn thêm một thuộc tính lúc thực thi.</p> + +<h3 id="Việc_kế_thừa_thuộc_tính">Việc kế thừa thuộc tính</h3> + +<p>Giả định bạn tạo <code>mark</code> object như là một <code>WorkerBee</code> với câu lệnh sau:</p> + +<pre class="brush: js">var mark = new WorkerBee; +</pre> + +<p>khi JavaScript thấy toán tử <code>new</code>, nó sẽ tạo một object mới và âm thầm đặt những giá trị của thuộc tính bên trong [[Prototype]] cho <code>WorkerBee.prototype</code> và truyền đối tượng mới tạo như là giá trị của từ khóa <em><code>this</code></em> cho hàm dựng <code>WorkerBee</code>. Thuộc tính [[Prototype]] xác định chuỗi prototype được dùng để trả về cho những giá trị của thuộc tính. Một khi những thuộc tính được thiết lập, JavaScript trả về đối tượng mới và những câu lệnh gán thiết lập giá trị thuộc tính của đối tượng <code>mark.</code></p> + +<p>Quy trình này không đặt giá trị cho những thuộc tính kế thừa từ chuỗi prototype trực tiếp vào trong đối tượng <code>mark</code>. Khi bạn lấy giá trị của một thuộc tính, JavaScript đầu tiên sẽ kiểm tra xem nếu giá trị tồn tại trực tiếp trên chính đối tượng đó. Nếu có, giá trị sẽ được trả về. Nếu không tồn tại trên chính đối tượng đó, JavaScript kiểm tra chuỗi prototype (sử dụng thuộc tính [[Prototype]]). Nếu một object trong chuỗi prototype có giá trị cho thuộc tính, giá trị sẽ được trả về. Nếu không tồn tại thuộc tính, JavaScript sẽ trả lời là không có thuộc tính. Bằng cách này, đối tượng <code>mark</code> có những thuộc tính và những giá trị sau:</p> + +<pre class="brush: js">mark.name = ''; +mark.dept = 'general'; +mark.projects = []; +</pre> + +<p>Đối tượng <code>mark</code> được gán những giá trị cục bộ cho thuộc tính <code>name</code> và <code>dept</code> bằng hàm dựng Employee. Nó được gán giá trị cục bộ cho thuộc tính <code>projects</code> bằng hàm dựng <code>WorkerBee</code>. Điều này giúp tạo ra sự kế thừa của các thuộc tính trong JavaScript. Một vài điểm tinh tế trong qui trình này được mô tả trong <a href="#Property_inheritance_revisited">Property inheritance revisited.</a></p> + +<p>Bởi vì hàm dựng không cho phép bạn chỉ định những giá trị riêng của thực thể, những thông tin này là chung. Những giá trị của thuộc tính là mặc định được chia sẻ cho tất cả các đối tượng được tạo ra từ <code>WorkerBee</code>. Tất nhiên bạn có thể thay đổi giá trị của bất kỳ thuộc tính nào. Bạn có thể làm điều đó trên <code>mark</code> object bằng những câu lệnh sau:</p> + +<pre class="brush: js">mark.name = 'Doe, Mark'; +mark.dept = 'admin'; +mark.projects = ['navigator'];</pre> + +<h3 id="Thêm_thuộc_tính">Thêm thuộc tính</h3> + +<p>Trong JavaScript, bạn có thể thêm thuộc tính cho object lúc thực thi. Bạn không bị rành buộc phải sử dụng chỉ những thuộc tính được cung cấp bởi hàm dựng. Để thêm một thuộc tính cụ thể cho một object riêng lẻ, bạn có thể gán giá trị cho thuộc tính của object đó như sau:</p> + +<pre class="brush: js">mark.bonus = 3000; +</pre> + +<p>Bây giờ object <code>mark</code> có thuộc tính <code>bonus</code>, những thực thể của <code>WorkerBee</code> không có thuộc tính này.</p> + +<p>Nếu bạn thêm thuộc tính mới vào một object mà đang được sử dụng làm prototype cho một hàm dựng, bạn đang thêm thuộc tính đó cho tất cả các object mà kế thừa từ prototype. Ví dụ, bạn có thể thêm thuộc tính <code>specialty</code> cho tất cả employees bằng câu lệnh sau:</p> + +<pre class="brush: js">Employee.prototype.specialty = 'none'; +</pre> + +<p>Ngay sau khi thực thi câu lệnh này, đối tượng <code>mark</code> cũng có thuộc tính <code>specialty</code> với giá trị <code>"none"</code>. Hình sau minh họa việc thêm thuộc tính vào prototype của <code>Employee</code> và sau đó ghi đè nó lên prototype của <code>Engineer</code>.</p> + +<p><img alt="" class="internal" src="/@api/deki/files/4422/=figure8.4.png" style="height: 519px; width: 833px;"><br> + <small><strong>Adding properties</strong></small></p> + +<h2 id="Những_hàm_dựng_linh_hoạt_hơn">Những hàm dựng linh hoạt hơn</h2> + +<p>Những hàm dựng đã được trình bày ở trên không cho phép chúng ta chỉ định giá trị cho thuộc tính khi chúng ta tạo thực thể. Với Java, bạn có thể cung cấp đối số cho hàm dựng để khởi tạo giá trị của thuộc tính cho những thực thể. Hình sau minh họa cách để thực hiện điều này.<br> + </p> + +<p><img alt="" class="internal" id="figure8.5" src="/@api/deki/files/4423/=figure8.5.png" style="height: 481px; width: 1012px;"><br> + <small><strong>Việc chỉ định thuộc tính trong hàm dựng, cách 1</strong></small></p> + +<p>Bảng minh họa sau trình bày cách định nghĩa những đối tượng này trong Java và JavaScript.</p> + +<div class="twocolumns"> +<h4 id="JavaScript_4">JavaScript</h4> + +<h4 id="Java_4">Java</h4> +</div> + +<div class="twocolumns"> +<pre class="brush: js">function Employee(name, dept) { + this.name = name || ''; + this.dept = dept || 'general'; +} +</pre> + +<p> </p> + +<p> </p> + +<p> </p> + +<p> </p> + +<p> </p> + +<pre class="brush: java">public class Employee { + public String name; + public String dept; + public Employee () { + this("", "general"); + } + public Employee (String name) { + this(name, "general"); + } + public Employee (String name, String dept) { + this.name = name; + this.dept = dept; + } +} +</pre> +</div> + +<div class="twocolumns"> +<pre class="brush: js">function WorkerBee(projs) { + + this.projects = projs || []; +} +WorkerBee.prototype = new Employee; +</pre> + +<p> </p> + +<p> </p> + +<p> </p> + +<pre class="brush: java">public class WorkerBee extends Employee { + public String[] projects; + public WorkerBee () { + this(new String[0]); + } + public WorkerBee (String[] projs) { + projects = projs; + } +} +</pre> +</div> + +<div class="twocolumns"> +<pre class="brush: js"> +function Engineer(mach) { + this.dept = 'engineering'; + this.machine = mach || ''; +} +Engineer.prototype = new WorkerBee; +</pre> + +<p> </p> + +<p> </p> + +<p> </p> + +<pre class="brush: java">public class Engineer extends WorkerBee { + public String machine; + public Engineer () { + dept = "engineering"; + machine = ""; + } + public Engineer (String mach) { + dept = "engineering"; + machine = mach; + } +} +</pre> +</div> + +<p>Những định nghĩa này trong JavaScript sử dụng cú pháp đặc biệt để thiết lập giá trị mặc định:</p> + +<pre class="brush: js">this.name = name || ''; +</pre> + +<p>Trong JavaScript toán tử luận lý OR (<code>||</code>) ước lượng giá trị đầu tiên của đối số. Nếu đối số được chuyển đổi thành true, toán tử trả về giá trị của đối số đó. Ngược lại toán tử trả về đối số thứ hai. Vì vậy, đoạn mã trên kiểm tra xem nếu <code>name</code> có giá trị cho thuộc tính <code>name</code>. Nếu có, nó thiết lập giá trị đó cho <code>this.name</code>. Ngược lại, nó đặt giá trị chuỗi rỗng vào <code>this.name</code>. Chương này sử dụng cú pháp vắn tắt, tuy nhiên nó có thể làm chúng ta khó hiểu lúc ban đầu.</p> + +<div class="note"> +<p><strong>Lưu Ý:</strong> Cách này có thể không hoạt động như mong đợi nếu hàm dựng được gọi với đối số mà được chuyển đổi thành false (ví dụ như 0 (zero) và chuỗi rỗng (<code><code>""</code></code>). trong trường hợp này giá trị mặc định sẽ được chọn)</p> +</div> + +<p>Với những định nghĩa này, khi bạn tạo một thực thể của một object, bạn có thể chỉ định giá trị cho những thuộc tính được định nghĩa cục bộ. Bạn có thể sử dụng những câu lệnh sau để tạo một <code>Engineer</code>:</p> + +<pre class="brush: js">var jane = new Engineer('belau'); +</pre> + +<p>Thuộc tính của <code>Jane</code> bây giờ là:</p> + +<pre class="brush: js">jane.name == ''; +jane.dept == 'engineering'; +jane.projects == []; +jane.machine == 'belau'; +</pre> + +<p>Lưu ý là với những định nghĩa này, bạn không thể chỉ định giá trị khởi tạo cho một thuộc tính được kế thừa như thuộc tính <code>name</code>. Nếu bạn muốn chỉ định một giá trị khởi tạo cho thuộc tính được kế thừa trong JavaScript, bạn cần để thêm câu lệnh cho hàm khởi tạo.</p> + +<p>Hàm tạo đã tạo một đối tượng chung và rồi sau đó những giá trị được khởi tạo cho những thuộc tính cục bộ trực tiếp của đối tượng mới. Bạn có thể khởi tạo thêm những thuộc tính bằng cách trực tiếp gọi những hàm dựng khác của chuỗi prototype. Hình sau sẽ minh họa điều đó.</p> + +<p><img alt="" class="internal" src="/@api/deki/files/4430/=figure8.6.png" style="height: 534px; width: 1063px;"><br> + <small><strong>Những giá trị đang được chỉ định trong hàm dựng, hình 2</strong></small></p> + +<p>Hãy xem xét một trong những định nghĩa một cách chi tiết. Đây là định nghĩa mới cho hàm dựng <code>Engineer</code>:</p> + +<pre class="brush: js">function Engineer(name, projs, mach) { + this.base = WorkerBee; + this.base(name, 'engineering', projs); + this.machine = mach || ''; +} +</pre> + +<p>Giả định rằng bạn tạo một đối tượng <code>Engineer</code> mới như sau:</p> + +<pre class="brush: js">var jane = new Engineer('Doe, Jane', ['navigator', 'javascript'], 'belau'); +</pre> + +<p>JavaScript thực thi theo những bước sau:</p> + +<ol> + <li>Toán tử <code>new</code> tạo một object và thiết lập giá trị <code>__proto__</code> của object mới tạo với giá trị là <code>Engineer.prototype</code>.</li> + <li>Toán tử mới sẽ truyền object mới cho hàm dựng <code>Engineer</code> như là giá trị của từ khóa <code>this</code>.</li> + <li>Hàm dựng tạo một thuộc tính mới được gọi là <code>base</code> cho đối tượng đó và gán giá trị của hàm dựng <code>WorkerBee</code> cho thuộc tính <code>base</code>. Điều này làm hàm dựng trở thành một phương thức của đối tượng <code>Engineer</code>. Tên của thuộc tính <code>base</code> thì không có gì đặc biệt. Bạn có thể dùng bất kỳ tên hợp lệ nào như là classBase, _base,... <code>base</code> đơn giản chỉ là một con trỏ đến hàm.</li> + <li>Hàm dựng gọi phương thức <code>base</code>, truyền vào hàm dựng như những đối số (<code>"Doe, Jane"</code> and <code>["navigator", "javascript"]</code> và <code>"engineering"</code>). Việc sử dụng tường minh <code>"engineering"</code> trong hàm dựng mà tất cả đối tượng <code>Engineer</code> có cùng giá trị cho thuộc tính được kế thừa <code>dept</code>, và giá trị ghi đè giá trị mà được kế thừa từ <code>Employee</code>.</li> + <li>Bởi vì <code>base</code> là phương thức của <code>Engineer</code>, JavaScript gắn từ khóa <code>this</code> với object được tạo ra ở bước 1. Vì thế hàm <code>WorkerBee</code> truyền các giá trị <code>"Doe, Jane"</code> và <code>"engineering"</code> cho hàm dựng <code>Employee</code>. Dựa trên giá trị trả về của hàm dựng <code>Employee</code>, hàm <code>WorkerBee</code> sử dụng những đối số còn lại để thiết lập giá trị cho thuộc tính <code>projects</code>.</li> + <li>Dựa trên giá trị trả về của phương thức <code>base</code>, hàm dựng <code>Engineer</code> khởi tạo thuộc tính <code>machine</code> của đối tượng với giá trị <code>"belau"</code>.</li> + <li>Dựa trên giá trị trả về của hàm dựng, JavaScript gán đối tượng cho biến <code>jane</code>.</li> +</ol> + +<p>Bạn có thể nghĩ rằng, việc phải gọi hàm dựng <code>WorkerBee</code> bên trong hàm dựng <code>Engineer</code>, để đảm bảo việc cài đặt sự kế thừa cho tất cả đối tượng <code>Engineer</code>. Điều này không quá quan trọng. Việc gọi hàm dựng <code>WorkerBee</code> để đảm bảo tất cả đối tượng <code>Engineer</code> được tạo ra với các thuộc tính được chỉ định trong tất cả các hàm dựng được gọi. Tuy nhiên nếu bạn thêm thuộc tính vào prototype của <code>Employee</code> hoặc <code>WorkerBee</code>, những thuộc tính đó không được kế thừa bởi đối tượng <code>Engineer</code>. Ví dụ, giả sử bạn có đoạn mã sau:</p> + +<pre class="brush: js">function Engineer(name, projs, mach) { + this.base = WorkerBee; + this.base(name, 'engineering', projs); + this.machine = mach || ''; +} +var jane = new Engineer('Doe, Jane', ['navigator', 'javascript'], 'belau'); +Employee.prototype.specialty = 'none'; +</pre> + +<p>Đối tượng <code>jane</code> không kế thừa thuộc tính <code>specialty</code>. Bạn vẫn cần cài đặt tường minh prototype để đảm bảo sự kế thừa động. Giả sử bạn có đoạn mã sau:</p> + +<pre class="brush: js">function Engineer(name, projs, mach) { + this.base = WorkerBee; + this.base(name, 'engineering', projs); + this.machine = mach || ''; +} +Engineer.prototype = new WorkerBee; +var jane = new Engineer('Doe, Jane', ['navigator', 'javascript'], 'belau'); +Employee.prototype.specialty = 'none'; +</pre> + +<p>Bây giờ thuộc tính <code>specialty</code> của đối tượng <code>jane</code> là "none".</p> + +<p>Một cách khác để kế thừa là dùng hàm phương thức <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call" title="en-US/docs/JavaScript/Reference/Global Objects/Function/call">call()</a></code> / <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply" title="en-US/docs/JavaScript/Reference/Global Objects/Function/apply"><code>apply()</code></a>. Hai đoạn mã sau là tương đương:</p> + +<div class="twocolumns"> +<pre class="brush: js">function Engineer(name, projs, mach) { + this.base = WorkerBee; + this.base(name, 'engineering', projs); + this.machine = mach || ''; +} +</pre> + +<pre class="brush: js">function Engineer(name, projs, mach) { + WorkerBee.call(this, name, 'engineering', projs); + this.machine = mach || ''; +} +</pre> +</div> + +<p>Việc sử dụng phương thức <code>call()</code> làm cho code rõ ràng hơn và <code>base</code> không còn cần thiết nữa.</p> + +<h2 id="Xem_lại_sự_kế_thừa_thuộc_tính">Xem lại sự kế thừa thuộc tính</h2> + +<p>Đoạn trên đã mô tả cách hàm dựng và prototype trong JavaScript cung cấp cơ chế kế thừa và cây kế thừa. Trong phần này, chúng ta sẽ nói về điểm tinh tế mà thật sự chưa phù hợp để mô tả ở những phần trước.</p> + +<h3 id="Dùng_Giá_Trị_Cục_Bộ_hay_là_Giá_Trị_Được_Kế_Thừa">Dùng Giá Trị Cục Bộ hay là Giá Trị Được Kế Thừa</h3> + +<p>Khi bạn truy xuất thuộc tính của object, JavaScript thực hiện những bước sau:</p> + +<ol> + <li>Kiểm tra nếu tồn tại thuộc tính trực tiếp, nó trả về giá trị của thuộc tính đó.</li> + <li>Nếu không có thuộc tính trực tiếp, kiểm tra trong chuỗi prototype (sử dụng thuộc tính <code>__proto__</code>).</li> + <li>Nếu một object trong chuỗi prototype chứa giá trị cho một thuộc tính đang tìm thì trả về giá trị của thuộc tính đó.</li> + <li>Nếu không tồn tại thuộc tính như vậy, thì object đó không có thuộc tính đang truy xuất.</li> +</ol> + +<p>Kết quả nhận được của những bước trên phụ thuộc vào cách bạn định nghĩa đối tượng. Ví dụ sau minh họa những cách định nghĩa đối tượng:</p> + +<pre class="brush: js">function Employee() { + this.name = ''; + this.dept = 'general'; +} + +function WorkerBee() { + this.projects = []; +} +WorkerBee.prototype = new Employee; +</pre> + +<p>Với cách định nghĩa này, giả định rằng bạn tạo đối tượng <code>amy</code> là thực thể của <code>WorkerBee</code> với đoạn lệnh sau:</p> + +<pre class="brush: js">var amy = new WorkerBee; +</pre> + +<p>Đối tượng <code>amy</code> có một biến cục bộ (riêng) là <code>projects</code>. Các thuộc tính <code>name</code> và <code>dept</code> thì không là thuộc tính riêng của <code>amy</code> mà được lấy ra từ thuộc tính <code>__proto__</code>. Vì vậy, đối tượng <code>amy</code> có những thuộc tính với những giá trị sau:</p> + +<pre class="brush: js">amy.name == ''; +amy.dept == 'general'; +amy.projects == []; +</pre> + +<p>Giả định rằng bạn thay đổi giá trị của thuộc tính <code>name</code> trong prototype của <code>Employee</code>:</p> + +<pre class="brush: js">Employee.prototype.name = 'Unknown'; +</pre> + +<p>Bạn mong muốn rằng giá trị mới sẽ được thiết lập cho tất cả các thực thể của <code>Employee</code>. Nhưng điều nay không xãy ra.</p> + +<p>Khi bạn tạo bất kỳ thực thể nào của đối tượng từ <code>Employee</code>, thì thực thể đó sẽ tạo thuộc tính <code>name</code> riêng trực tiếp trên chính thực thể đó (cụ thể đó là giá trị rỗng). Điều này có nghĩa là khi bạn thiết lập giá trị cho prototype của <code>WorkerBee</code> bằng một đối tượng kiểu <code>Employee</code>, thì <code>WorkerBee.prototype</code> có lưu giá trị riêng cho thuộc tính <code>name</code>. Vì vậy, khi JavaScript tìm kiếm thuộc tính <code>name</code> của đối tượng <code>amy</code> (tạo ra từ <code>WorkerBee</code>), JavaScript tìm kiếm giá riêng cho thuộc tính đó trong <code>WorkerBee.prototype</code>. Do đó nó không tìm kiếm xa hơn trong chuỗi prototype.</p> + +<p>Nếu bạn muốn thay đổi giá trị của một thuộc tính lúc thực thi và muốn giá trị mới đó áp dụng cho tất cả các thực thể được tạo ra, thì bạn không thể khởi tạo thuộc tính trong hàm dựng. Thay vào đó, ban thêm nó vào hàm vào trong thuộc tính prototype của hàm dựng. Ví dụ sau minh họa cách chúng ta đạt được mục đích này:</p> + +<pre class="brush: js">function Employee() { + this.dept = 'general'; // Note that this.name (a local variable) does not appear here +} +Employee.prototype.name = ''; // A single copy + +function WorkerBee() { + this.projects = []; +} +WorkerBee.prototype = new Employee; + +var amy = new WorkerBee; + +Employee.prototype.name = 'Unknown'; +</pre> + +<p>Trong trường hợp này thuộc tính <code>name</code> của <code>amy</code> nhận giá trị "Unknown".</p> + +<p>Tóm lại, nếu bạn muốn đặt giá trị mặc định cho thuộc tính và bạn muốn thay đổi giá trị mặc định lúc thực thi, bạn nên cài đặt thuộc tính trên prototype của hàm dựng, không phải tạo trực tiếp thuộc tính lúc thực thi hàm dựng.</p> + +<h3 id="Xác_định_mối_quan_hể_của_thực_thể">Xác định mối quan hể của thực thể</h3> + +<p>Việc tìm kiếm thuộc tính trong JavaScript sẽ được thực hiện trên chính danh sách các thuộc tính riêng trực tiếp của object trước, nếu thuộc tính không được tìm thấy, nó sẽ tìm trên object đặc biệt là <code>__proto__</code>. Việc kiểm tra sẽ được thực thi đệ qui, qui trình này được gọi là "Tìm kiếm trong chuỗi prototype".</p> + +<p>Thuộc tính đặc biệt <code>__proto__</code> được tạo ra khi một đối tượng được tạo ra. Nó chính là giá trị được gán cho thuộc tính <code>prototype</code> của hàm dựng. Ví vậy biểu thức <code>new Foo()</code> tạo ra một object với <code>__proto__ == <code class="moz-txt-verticalline">Foo.prototype</code></code>. Tiếp theo đó, những thay đổi trên thuộc tính <code class="moz-txt-verticalline">Foo.prototype</code> sẽ làm thay đổi thuộc tính cho tất cả đối tượng mà được tạo ra bởi <code>new Foo()</code>.</p> + +<p>Mỗi object đều cho thuộc tính <code>__proto__</code> và mỗi hàm đều có thuộc tính <code>prototype</code>. Vì vậy những đối tượng có mối liên hệ thông qua cơ chế 'thừa kế prototype' với những đối tượng khác. Bạn có thể kiểm tra sự thừa kế bằng cách so sánh thuộc tính <code>__proto__</code> của object với prototype của một hàm. JavaScript cung cấp một toán tử để thực hiện điều này là <code>instanceof</code>, Toán tử sẽ trả về kết quả true nếu đối tượng được kết thừa từ prototype của hàm. Như ví dụ sau:</p> + +<pre class="brush: js">var f = new Foo(); +var isTrue = (f instanceof Foo);</pre> + +<p>Để minh họa cụ thể hơn, chúng ta xem ví dụ sau. Giả định bạn đã có đoạn mã như định nghĩa trong <a href="#Inheriting_properties">Kế thừa thuộc tính</a>. Tạo một đối tượng <code>Engineer</code> như sau:</p> + +<pre class="brush: js">var chris = new Engineer('Pigman, Chris', ['jsd'], 'fiji'); +</pre> + +<p>Với đối tượng nay, những câu lệnh sau tất cả đều đúng:</p> + +<pre class="brush: js">chris.__proto__ == Engineer.prototype; +chris.__proto__.__proto__ == WorkerBee.prototype; +chris.__proto__.__proto__.__proto__ == Employee.prototype; +chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype; +chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null; +</pre> + +<p>Dựa trên những điểm trên, bạn có thể viết hàm <code>instanceOf</code> như sau:</p> + +<pre class="brush: js">function instanceOf(object, constructor) { + object = object.__proto__; + while (object != null) { + if (object == constructor.prototype) + return true; + if (typeof object == 'xml') { + return constructor.prototype == XML.prototype; + } + object = object.__proto__; + } + return false; +} +</pre> + +<div class="note"><strong>Lưu Ý:</strong> Đoạn lệnh trên dùng toán tử typeof để kiểm tra object để kiểm tra đó là XML object, đây là cách khắc phục lỗi của JavaScript cho đối tượng XML.</div> + +<p>Dùng hàm instanceOf trên, biểu thức luôn đúng:</p> + +<pre class="brush: js">instanceOf(chris, Engineer) +instanceOf(chris, WorkerBee) +instanceOf(chris, Employee) +instanceOf(chris, Object) +</pre> + +<p>Nhưng biểu thức sau thì sai:</p> + +<pre class="brush: js">instanceOf(chris, SalesPerson) +</pre> + +<h3 id="Thông_tin_toàn_cục_trong_hàm_dựng">Thông tin toàn cục trong hàm dựng</h3> + +<p>Khi bạn định nghĩa hàm dựng, bạn cần cẩn thận nếu bạn thiết lập giá trị cho biến toàn cục. Giả sử bạn muốn giá trị ID duy nhất được tự động gán cho mỗi employee mới. Bạn có thể sử dụng cách định nghĩa sau cho <code>Employee</code> sau:</p> + +<pre class="brush: js">var idCounter = 1; + +function Employee(name, dept) { + this.name = name || ''; + this.dept = dept || 'general'; + this.id = idCounter++; +} +</pre> + +<p>Với định nghĩa này, khi bạn tạo một <code>Employee</code> mới, hàm dựng gán giá trị ID kế tiếp và rồi tăng biến đếm toàn cục ID lên một đơn vị. Vì vậy, những câu lệnh tiếp theo sau đây, <code>victoria.id</code> là 1 và <code>harry.id</code> là 2:</p> + +<pre class="brush: js">var victoria = new Employee('Pigbert, Victoria', 'pubs'); +var harry = new Employee('Tschopik, Harry', 'sales'); +</pre> + +<p>Thoạt nhìn mọi thứ có vẽ tốt. Tuy nhiên, <code>idCounter</code> được tăng lên mỗi lần một đối tượng <code>Employee</code> được tạo ra cho mọi trường hợp cả những trường hợp không mong muốn. Nếu bạn tạo toàn bộ cây cấp bậc <code>Employee</code> như hình trong chương này, hàm dựng <code>Employee</code> được gọi mỗi là bạn cài đặt một prototype. Giả sử bạn có đoạn lệnh sau:</p> + +<pre class="brush: js">var idCounter = 1; + +function Employee(name, dept) { + this.name = name || ''; + this.dept = dept || 'general'; + this.id = idCounter++; +} + +function Manager(name, dept, reports) {...} +Manager.prototype = new Employee; + +function WorkerBee(name, dept, projs) {...} +WorkerBee.prototype = new Employee; + +function Engineer(name, projs, mach) {...} +Engineer.prototype = new WorkerBee; + +function SalesPerson(name, projs, quota) {...} +SalesPerson.prototype = new WorkerBee; + +var mac = new Engineer('Wood, Mac'); +</pre> + +<p>Giả sử ta không quan tâm những câu lệnh bên trong hàm dựng, thuộc tính <code>base</code> và gọi hàm <code>base</code> trong chuỗi prototype. Trong trường hợp này, ngay khi đối tượng <code>mac</code> được tạo, <code>mac.id</code> là 5.</p> + +<p>Tuy theo yêu cầu của ứng dụng, nó có thể là vấn đề quan trọng hoặc không khi biến đếm được tăng lên. Nếu bạn quan tâm tính chính xác của giá trị tăng thêm của biến đếm, Một giải pháp cho vấn đề này là:</p> + +<pre class="brush: js">function Employee(name, dept) { + this.name = name || ''; + this.dept = dept || 'general'; + if (name) + this.id = idCounter++; +} +</pre> + +<p>Khi bạn tạo một thực thể của <code>Employee</code> để sử dụng như prototype, bạn không cung cấp đối số cho hàm dựng. Việc sử dụng định nghĩa của hàm dựng, khi bạn không cung cấp đối số, hàm dựng không gán giá trị cho id và không cập nhật biến đếm. Vì vậy, để một đối tượng <code>Employee</code> được gán id, bạn phải chỉ định tên cho employee. Trong ví dụ này, mac.id sẽ là 1.</p> + +<p>Một cách khác, bạn có thể tạo một bản sao của đối tượng prototype của Employee để gán cho WorkerBee:</p> + +<pre class="brush: js">WorkerBee.prototype = Object.create(Employee.prototype); +// instead of WorkerBee.prototype = new Employee +</pre> + +<h3 id="Không_hỗ_trợ_đa_kế_thừa">Không hỗ trợ đa kế thừa</h3> + +<p>Một vài ngôn ngữ hướng đối tượng cho phép đa kế thừa. Nghĩa là một object có thể kế thừa những thuộc tính và giá rị từ những đối tượng cha không liên quan.</p> + +<p>Việc kế thừa những thuộc tính xảy ra lúc thực thi bởi JavaScript trong khi tìm kiếm chuỗi prototype của object cho một giá trị. Bởi vì một object chỉ có một prototype đơn, JavaScript không thể kế thừa động từ nhiều hơn một chuỗi prototype.</p> + +<p>Trong JavaScript, bạn có thể áp dụng nhiều hàm dựng trong hàm dựng. Điều này chứng minh tính khả thi của đa kế thừa. Xem xét ví dụ sau:</p> + +<pre class="brush: js">function Hobbyist(hobby) { + this.hobby = hobby || 'scuba'; +} + +function Engineer(name, projs, mach, hobby) { + this.base1 = WorkerBee; + this.base1(name, 'engineering', projs); + this.base2 = Hobbyist; + this.base2(hobby); + this.machine = mach || ''; +} +Engineer.prototype = new WorkerBee; + +var dennis = new Engineer('Doe, Dennis', ['collabra'], 'hugo'); +</pre> + +<p>Giả sử <code>WorkerBee</code> được định nghĩa như trên. Trong trường hợp này, đối tượng <code>dennis</code> có những thuộc tính sau:</p> + +<pre class="brush: js">dennis.name == 'Doe, Dennis'; +dennis.dept == 'engineering'; +dennis.projects == ['collabra']; +dennis.machine == 'hugo'; +dennis.hobby == 'scuba'; +</pre> + +<p>Vì vậy <code>dennis</code> có thuộc tính từ hàm dựng <code>Hobbyist</code>. Tuy nhiên, giả sử sau đó bạn thêm một thuộc tính vào prototype của hàm dựng của <code>Hobbyist</code>:</p> + +<pre class="brush: js">Hobbyist.prototype.equipment = ['mask', 'fins', 'regulator', 'bcd']; +</pre> + +<p>Đối tượng <code>dennis</code> không kế thừa thuộc tính mới này.</p> + +<div>{{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Using_promises")}}</div> diff --git a/files/vi/web/javascript/guide/expressions_and_operators/index.html b/files/vi/web/javascript/guide/expressions_and_operators/index.html new file mode 100644 index 0000000000..a843b8d769 --- /dev/null +++ b/files/vi/web/javascript/guide/expressions_and_operators/index.html @@ -0,0 +1,920 @@ +--- +title: Biểu thức và toán tử +slug: Web/JavaScript/Guide/Expressions_and_Operators +translation_of: Web/JavaScript/Guide/Expressions_and_Operators +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}</div> + +<p class="summary">Chương này mô tả biểu thức và toán tử của JavaScript, bao gồm toán tử gán, toán tử so sánh, arithmetic, thao tác bit, toán tử luận lý, chuỗi, toán tử ba ngôi và nhiều hơn nữa.</p> + +<p>Để xem danh sách đầy đủ và chi tiết các toán tử và biểu thức, mời truy cập vào <a href="/en-US/docs/Web/JavaScript/Reference/Operators">reference</a>.</p> + +<h2 id="Toán_tử">Toán tử</h2> + +<p>JavaScript có các loại toán tử như sau. Phần này mô tả về các toán tử và có bao gồm thông tin về thứ tự ưu tiên của chúng.</p> + +<ul> + <li><a href="#Toán_tử_gán">Toán tử gán</a></li> + <li><a href="#Toán_tử_so_sánh">Toán tử so sánh</a></li> + <li><a href="#Toán_tử_số_học">Toán tử số học</a></li> + <li><a href="#Bitwise">Toán tử thao tác bit</a></li> + <li><a href="#Logical">Toán tử luận lý</a></li> + <li><a href="#String">Toán tử chuỗi</a></li> + <li><a href="#Conditional">Toán tử điều kiện (ba ngôi)</a></li> + <li><a href="#Comma">Toán tử phẩy</a></li> + <li><a href="#Unary">Toán tử một ngôi</a></li> + <li><a href="#Relational">Toán tử quan hệ</a></li> +</ul> + +<p>JavaScript có cả toán tử <em>hai ngôi</em> và<em>một ngôi</em>, và một toán tử đặc biệt ba ngôi, toán tử quan hệ. Toán tử hai ngôi yêu cầu hai toán hạng, một toán hạng ở trước và một toán hạng ở sau toán tử:</p> + +<pre class="syntaxbox"><em>toán_hạng_1</em> <em>toán_tử</em> <em>toán_hạng_2</em> +</pre> + +<p>Chẳng hạn, <code>3+4</code> hoặc <code>x*y</code>.</p> + +<p>Toán tử một ngôi yêu cầu một toán tử, ở trước hoặc ở sau toán tử:</p> + +<pre class="syntaxbox"><em>toán_tử</em> <em>toán_hạng</em> +</pre> + +<p>hoặc</p> + +<pre class="syntaxbox"><em>toán_hạng</em> <em>toán_tử</em> +</pre> + +<p>Chẳng hạn, <code>x++</code> hoặc <code>++x</code>.</p> + +<h3 id="Toán_tử_gán"><a id="Assignment" name="Assignment">Toán tử gán</a></h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators">Toán tử gán</a> gán giá trị cho toán hạng bên trái nó dựa theo giá trị của toán hạng bên phải nó. Toná tử gán đơn giản là toán tử bằng (<code>=</code>), gán giá trị cho toán hạng bên trái nó bằng giá trị của toán hạng bên phải nó. Vậy, <code>x = y</code> tức là gán giá trị của <code>y</code> cho <code>x</code>.</p> + +<p>Ngoài ra còn có các toán tử gán kết hợp được liệt kê trong bảng dưới:</p> + +<table class="standard-table"> + <caption>Toán tử gán kết hợp</caption> + <thead> + <tr> + <th>Tên</th> + <th>Viết tắt</th> + <th>Ý nghĩa</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Assignment">Toán tử gán</a></td> + <td><code>x = y</code></td> + <td><code>x = y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Addition_assignment">Cộng xong rồi gán</a></td> + <td><code>x += y</code></td> + <td><code>x = x + y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Subtraction_assignment">Trừ xong rồi gán</a></td> + <td><code>x -= y</code></td> + <td><code>x = x - y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Multiplication_assignment">Nhân xong rồi gán</a></td> + <td><code>x *= y</code></td> + <td><code>x = x * y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Division_assignment">Chia xong rồi gán</a></td> + <td><code>x /= y</code></td> + <td><code>x = x / y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Remainder_assignment">Chia lấy dư xong rồi gán</a></td> + <td><code>x %= y</code></td> + <td><code>x = x % y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Exponentiation_assignment">Luỹ thừa rồi gán</a>{{experimental_inline}}</td> + <td><code>x **= y</code></td> + <td><code>x = x ** y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Left_shift_assignment">Dịch bit trái rồi gán</a></td> + <td><code>x <<= y</code></td> + <td><code>x = x << y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Right_shift_assignment">Dịch bit phải rồi gán</a></td> + <td><code>x >>= y</code></td> + <td><code>x = x >> y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Unsigned_right_shift_assignment">Dịch phải kiểu unsigned rồi gán</a></td> + <td><code>x >>>= y</code></td> + <td><code>x = x >>> y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_AND_assignment">AND bit rồi gán</a></td> + <td><code>x &= y</code></td> + <td><code>x = x & y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_XOR_assignment">XOR bit rồi gán</a></td> + <td><code>x ^= y</code></td> + <td><code>x = x ^ y</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Assignment_Operators#Bitwise_OR_assignment">OR bit rồi gán</a></td> + <td><code>x |= y</code></td> + <td><code>x = x | y</code></td> + </tr> + </tbody> +</table> + +<h4 id="Phân_rã">Phân rã</h4> + +<p>Với phép gán phức tạp hơn, cú pháp <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">phân rã rồi gán</a> là một biểu thức JavaScript cho phép phân tách dữ liệu từ mảng hoặc object sử dụng cú pháp sao chép cấu trúc của mảng hoặc object literal.</p> + +<pre class="brush: js">var foo = ['one', 'two', 'three']; + +// không dùng phân rã +var one = foo[0]; +var two = foo[1]; +var three = foo[2]; + +// dùng phân rã +var [one, two, three] = foo;</pre> + +<h3 id="Toán_tử_so_sánh"><a name="Comparison">Toán tử so sánh</a></h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators">Toán tử so sánh</a> so sánh toán hạng của nó và trả về giá trị luận lý dựa theo tính đúng sai của phép so sánh. Toán hạng có thể thuộc là số, chuỗi, luận lý, hoặc object. Chuỗi được so sánh theo thứ tự từ điển, qua giá trị mã Unicode. Trong nhiều trường hợp, nếu hai toán hạng không cùng kiểu, JavaScript sẽ tự động ép kiểu sao cho phù hợp. Hành vi này thường xảy ra khi so sánh dữ liệu kiểu số. Duy có hai toán tử so sánh, bao gồm <code>===</code> và <code>!==</code>, không tự động ép kiểu mà sẽ so sánh bằng chính xác. Bảng sau mô tả các toán tử so sánh bao gồm cả code mẫu:</p> + +<pre class="brush: js">var var1 = 3; +var var2 = 4; +</pre> + +<table class="standard-table"> + <caption>Toán tử so sánh</caption> + <thead> + <tr> + <th scope="col">Toán tử</th> + <th scope="col">Mô tả</th> + <th scope="col">Ví dụ trả về true/th></th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Equality">Bằng</a> (<code>==</code>)</td> + <td>Trả về <code>true</code> nếu các toán hạng bằng nhau.</td> + <td><code>3 == var1</code> + <p><code>"3" == var1</code></p> + <code>3 == '3'</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Inequality">Không bằng</a> (<code>!=</code>)</td> + <td>Trả về <code>true</code> nếu các toán hạng không bằng nhau.</td> + <td><code>var1 != 4<br> + var2 != "3"</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Identity">Bằng chính xác</a> (<code>===</code>)</td> + <td>Trả về <code>true</code> nếu các toán hạng bằng nhau và cùng kiểu. Xem thêm tại {{jsxref("Object.is")}} và <a href="/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness" title="/en-US/docs/Web/JavaScript/Guide/Sameness">sameness in JS</a>.</td> + <td><code>3 === var1</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Nonidentity">Không bằng chính xác</a> (<code>!==</code>)</td> + <td>Trả về <code>true</code> nếu các toán hạng không bằng nhau, hoặc khác kiểu.</td> + <td><code>var1 !== "3"<br> + 3 !== '3'</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Greater_than_operator">Lớn hơn</a> (<code>></code>)</td> + <td>Trả về <code>true</code> nếu toán hạng bên trái lớn hơn toán hạng bên phải.</td> + <td><code>var2 > var1<br> + "12" > 2</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Greater_than_or_equal_operator">Lớn hơn hoặc bằng</a> (<code>>=</code>)</td> + <td>Trả về <code>true</code> nếu toán hạng bên trái lớn hơn hoặc bằng toán hạng bên phải.</td> + <td><code>var2 >= var1<br> + var1 >= 3</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Less_than_operator">Nhỏ hơn</a> (<code><</code>)</td> + <td>Trả về <code>true</code> nếu toán hạng bên trái nhỏ hơn toán hạng bên phải.</td> + <td><code>var1 < var2<br> + "2" < 12</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Less_than_or_equal_operator">Nhỏ hơn hoặc bằng</a> (<code><=</code>)</td> + <td>Trả về <code>true</code> nếu toán hạng bên trái ?nhỏ hơn hoặc bằng toán hạng bên phải.</td> + <td><code>var1 <= var2<br> + var2 <= 5</code></td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>Lưu ý: </strong>(<strong>=></strong>) không phải là toán tử, mà là cú pháp của <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">Hàm mũi tên</a>.</p> +</div> + +<h3 id="Toán_tử_số_học"><a name="Arithmetic">Toán tử số học</a></h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators">Toán tử số học</a> nhận giá trị kiểu số (cả literal lẫn biến) là toán hạng của nó và trả về một giá trị kiểu số. Các toán tử số học thông thường là toán tử cộng (<code>+</code>), trừ (<code>-</code>), nhân (<code>*</code>), và chia (<code>/</code>). Những toán tử này hoạt động tương tự như trong các ngôn ngữ lập trình khác khi xử lý với số thực dấu phẩy động (nói chung, ?phép chia cho 0 sẽ trả về {{jsxref("Infinity")}}). Ví dụ:</p> + +<pre class="brush: js">1 / 2; // 0.5 +1 / 2 == 1.0 / 2.0; // this is true +</pre> + +<p>Ngoài những toán tử số học thông thường (+, -, * /), JavaScript cung cấp thêm các toán tử số học được liệt kê trong bảng sau:</p> + +<table class="fullwidth-table"> + <caption>Toán tử số học</caption> + <thead> + <tr> + <th scope="col">Toán tử</th> + <th scope="col">Mô tả</th> + <th scope="col">Ví dụ</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Remainder">Chia lấy dư</a> (<code>%</code>)</td> + <td>Toán tử hai ngôi. Trả về phần nguyên trong phép chia của hai toán hạng.</td> + <td>12 % 5 trả về 2.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Increment">Tăng</a> (<code>++</code>)</td> + <td>Toán tử một ngôi. Cộng thêm một đơn vị cho toán hạng. Nếu dùng như tiền tố (<code>++x</code>), trả về giá trị sau khi cộng thêm một; nếu dùng như hậu tố (<code>x++</code>), trả về giá trị trước khi cộng thêm một.</td> + <td>Nếu <code>x</code> bằng 3, rồi <code>++x</code> sẽ thiết lập giá trị của <code>x</code> lên 4 và trả về 4, trong khi <code>x++</code> trả về 3 và sau đó mới thiết lập giá trị của <code>x</code> lên 4.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Decrement">Giảm</a> (<code>--</code>)</td> + <td>Toán tử một ngôi. Trừ đi một đơn vị cho toán hạng. Giá trị trả về tương tự như toán tử tăng.</td> + <td>Nếu <code>x</code> bằng 3, rồi <code>--x</code> sẽ thiết lập giá trị của <code>x</code> về 2 và trả về 2, trong khi <code>x--</code> trả về 3 và sau đó mới thiết lập giá trị của <code>x</code> về 2.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_negation">Phủ định một ngôi</a> (<code>-</code>)</td> + <td>Toán tử một ngôi. Trả về giá trị phủ định của toán hạng.</td> + <td>Nếu <code>x</code> bằng 3, thì <code>-x</code> trả về -3.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_plus">Cộng một ngôi</a> (<code>+</code>)</td> + <td>Toán tử một ngôi. Ép kiểu toán hạng về dạng số học, nếu kiểu của toán hạng đó không phải là số.</td> + <td><code>+"3"</code> trả về <code>3</code>.<br> + <code>+true</code> trả về <code>1.</code></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Exponentiation">Toán tử luỹ thừa</a> (<code>**</code>) {{experimental_inline}}</td> + <td>Tính toán giá trị <code>cơ số</code> theo <code>luỹ thừa</code> số mũ, tức là, <code>cơ số<sup>số mũ</sup></code></td> + <td><code>2 ** 3</code> trả về <code>8</code>.<br> + <code>10 ** -1</code> trả về <code>0.1</code>.</td> + </tr> + </tbody> +</table> + +<h3 id="Toán_tử_thao_tác_bit"><a id="Bitwise" name="Bitwise">Toán tử thao tác bit</a></h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators">Toán tử thao tác bit</a> coi toán hạng của nó là một tập 32 bit (gồm 0 và 1), thay vì là kiểu thập phân, thập lục phân, hay bát phân. Chẳng hạn, số thập phân 9 được biểu diễn trong hệ nhị phân là 1001. Toán tử thao tác bit xử lý phép toán dựa theo dạng biểu diễn nhị phân ấy, nhưng trả về giá trị kiểu số thông thường trong JavaScript.</p> + +<p>Bảng tóm tắt các toán tử thao tác bit của JavaScript.</p> + +<table class="standard-table"> + <caption>Toán tử thao tác bit</caption> + <thead> + <tr> + <th scope="col">Toán tử</th> + <th scope="col">Cách dùng</th> + <th scope="col">Mô tả</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_AND">Toán tử AND bit</a></td> + <td><code>a & b</code></td> + <td>trả về a one in each bit position for which the corresponding bits of both operands are ones.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_OR">Toán tử OR bit</a></td> + <td><code>a | b</code></td> + <td>trả về a zero in each bit position for which the corresponding bits of both operands are zeros.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_XOR">Toán tử XOR bit</a></td> + <td><code>a ^ b</code></td> + <td>trả về a zero in each bit position for which the corresponding bits are the same.<br> + [trả về a one in each bit position for which the corresponding bits are different.]</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT">Toán tử NOT bit</a></td> + <td><code>~ a</code></td> + <td>Inverts the bits of its operand.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Left_shift">Dịch trái</a></td> + <td><code>a << b</code></td> + <td>Shifts <code>a</code> in binary representation <code>b</code> bits to the left, shifting in zeros from the right.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Right_shift">Dịch phải giữ nguyên dấu</a></td> + <td><code>a >> b</code></td> + <td>Shifts <code>a</code> in binary representation <code>b</code> bits to the right, discarding bits shifted off.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Unsigned_right_shift">Dịch phải với 0</a></td> + <td><code>a >>> b</code></td> + <td>Shifts <code>a</code> in binary representation <code>b</code> bits to the right, discarding bits shifted off, and shifting in zeros from the left.</td> + </tr> + </tbody> +</table> + +<h4 id="Bitwise_Logical_Operators" name="Bitwise_Logical_Operators">Toán tử luận lý bit</h4> + +<p>Về lý thuyết, cơ chế hoạt động của toán tử luận lý bit được giải thích như sau:</p> + +<ul> + <li>Toán hạng được chuyển đổi về dạng số nguyên 32-bit và biểu diễn bằng một dãy bit (0 và 1). Số dài hơn 32 bit sẽ bị cắt đi một số bit. Chẳng hạn, số nguyên sau đây, dài hơn 32 bit sẽ được chuyển đổi về dạng số nguyên 32 bit: + <pre>Trước: 11100110111110100000000000000110000000000001 +Sau: 10100000000000000110000000000001</pre> + </li> + <li>Mỗi bit của toán hạng thứ nhất sẽ dóng với bit tương ứng của toán hạng thứ hai.</li> + <li>Toán tử sẽ áp dụng với từng cặp bit và trả.</li> +</ul> + +<p>Chẳng hạn, biểu diễn nhị phân của 9 là 1001, và biểu diễn nhị phân của 15 là 1111. Vậy nếu áp dụng toán tử luận lý bit vào các giá trị này, thì kết quả trả về sẽ được như trong bảng sau:</p> + +<table class="standard-table"> + <caption>Ví dụ về toán tử thao tác bit</caption> + <thead> + <tr> + <th scope="col">Biểu thức</th> + <th scope="col">Kết quả</th> + <th scope="col">Mô tả nhị phân</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>15 & 9</code></td> + <td><code>9</code></td> + <td><code>1111 & 1001 = 1001</code></td> + </tr> + <tr> + <td><code>15 | 9</code></td> + <td><code>15</code></td> + <td><code>1111 | 1001 = 1111</code></td> + </tr> + <tr> + <td><code>15 ^ 9</code></td> + <td><code>6</code></td> + <td><code>1111 ^ 1001 = 0110</code></td> + </tr> + <tr> + <td><code>~15</code></td> + <td><code>-16</code></td> + <td><code>~</code><code>00000000...</code><code>00001111 = </code><code>1111</code><code>1111</code><code>...</code><code>11110000</code></td> + </tr> + <tr> + <td><code>~9</code></td> + <td><code>-10</code></td> + <td><code>~</code><code>00000000</code><code>...</code><code>0000</code><code>1001 = </code><code>1111</code><code>1111</code><code>...</code><code>1111</code><code>0110</code></td> + </tr> + </tbody> +</table> + +<p>Chú ý: tất cả 32 bit được đảo ngược bởi toán tử luận lý NOT có bit trái nhất đặt thành 1 để biểu diễn số âm (biểu diễn bù hai). <code>~x</code> thực thi ra cùng một kết quả như <code>-x - 1</code>.</p> + +<h4 id="Bitwise_Shift_Operators" name="Bitwise_Shift_Operators">Toán tử dịch bit</h4> + +<p>Toán tử dịch bit nhận hai toán hạng: toán hạng thứ nhất là số lượng bit được dịch, còn toán hạng thứ hai chỉ ra vị trí bit để bắt đầu dịch. Hướng dịch bit phụ thuộc vào toán tử được sử dụng.</p> + +<p>Toán tử dịch bit chuyển đổi toán hạng của nó thành dạng số nguyên 32-bit và trả về kết quả cùng kiểu với toán hạng bên trái.</p> + +<p>Toán tử dịch bit được liệt kê theo danh sách sau.</p> + +<table class="fullwidth-table"> + <caption>Toán tử dịch bit</caption> + <thead> + <tr> + <th scope="col">Toán tử</th> + <th scope="col">Mô tả</th> + <th scope="col">Ví dụ</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#<<_(Left_shift)">Dịch trái</a><br> + (<code><<</code>)</td> + <td>Dịch toán hạng thứ nhất theo một lượng bằng toán hạng thứ hai sang trái. Các bit dịch trái bị tràn sẽ bị loại bỏ. Các bit 0 được dịch vào từ bên phải.</td> + <td><code>9<<2</code> trả về 36, bởi vì 1001 dịch 2 bit sang trái sẽ thành 100100, tương ứng với 36.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#>>_(Sign-propagating_right_shift)">Dịch phải bit giữ nguyên dấu</a> (<code>>></code>)</td> + <td>Dịch toán hạng thứ nhất theo một lượng bằng toán hạng thứ hai sang phải. Các bit dịch phải bị tràn sẽ bị loại bỏ. Bản sao của bit trái nhất được dịch vào từ trái.</td> + <td><code>9>>2</code> trả về 2, bởi vì 1001 dịch 2 bit sang phải sẽ thành 10, tương ứng với 2. Tương tự, <code>-9>>2</code> trả về -3, bởi vì dấu vẫn được giữ nguyên.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#>>>_(Zero-fill_right_shift)">Dịch phải bit với 0</a> (<code>>>></code>)</td> + <td>Dịch toán hạng thứ nhất theo một lượng bằng toán hạng thứ hai sang phải. Các bit dịch phải bị tràn sẽ bị loại bỏ. Bit 0 được dịch vào từ trái sang.</td> + <td><code>19>>>2</code> trả về 4, bởi vì 10011 dịch 2 bit sang phải sẽ thành 100, tương ứng với 4. Với số không âm, toán tử này tương tự với dịch phải giữ nguyên dấu.</td> + </tr> + </tbody> +</table> + +<h3 id="Toán_tử_luận_lý"><a id="Logical" name="Logical">Toán tử luận lý</a></h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators">Toán tử logic</a> thường được dùng với giá trị Boolean (kiểu logic); khi đó, chúng trả về giá trị Boolean. Tuy nhiên, toán tử <code>&&</code> và <code>||</code> thực tế trả về giá trị của một trong những toán hạng xác định, nên nếu hai toán tử này được dùng với giá trị không phải kiểu Boolean, chúng có thể trả về một giá trị không phải Boolean. Toán tử logic được mô tả trong bảng dưới.</p> + +<table class="fullwidth-table"> + <caption>Toán tử logic</caption> + <thead> + <tr> + <th scope="col">Toán tử</th> + <th scope="col">Cách dùng</th> + <th scope="col">Mô tả</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_AND">Logic AND</a><code> </code>(<code>&&</code>)</td> + <td><code>expr1 && expr2</code></td> + <td>Trả về <code>expr1</code> nếu nó có thể biến đổi thành <code>false</code>; ngược lại, trả về <code>expr2</code>. Như vậy, khi dùng với giá trị Boolean, <code>&&</code> trả về <code>true</code> nếu cả hai toán hạng đều là true; ngược lại, trả về <code>false</code>.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_OR">Logic OR </a>(<code>||</code>)</td> + <td><code>expr1 || expr2</code></td> + <td>Trả về <code>expr1</code> nếu nó có thể biến đổi thành <code>true</code>; ngược lại, trả về <code>expr2</code>. Vì vậy, khi dùng với giá trị Boolean, <code>||</code> trả về <code>true</code> nếu cả hai toán hạng đều là true; nếu cả hai false, trả về <code>false</code>.</td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_NOT">Logic NOT </a>(<code>!</code>)</td> + <td><code>!expr</code></td> + <td>Trả về <code>false</code> nếu toán hạng đứng ngay sau nó có thể biến đổi thành <code>true</code>; ngược lại, trả về <code>true</code>.</td> + </tr> + </tbody> +</table> + +<p>Ví dụ về các biểu thức có thể biến đổi thành <code>false</code> là những biểu thức khi thực thi trả về null, 0, NaN, chuỗi rỗng (""), hoặc undefined.</p> + +<p>Sau đây là các ví dụ cho toán tử <code>&&</code> (luận lý AND).</p> + +<pre class="brush: js">var a1 = true && true; // t && t trả về true +var a2 = true && false; // t && f trả về false +var a3 = false && true; // f && t trả về false +var a4 = false && (3 == 4); // f && f trả về false +var a5 = 'Cat' && 'Dog'; // t && t trả về Dog +var a6 = false && 'Cat'; // f && t trả về false +var a7 = 'Cat' && false; // t && f trả về false +</pre> + +<p>Sau đây là các ví dụ cho toán tử || (luận lý OR).</p> + +<pre class="brush: js">var o1 = true || true; // t || t trả về true +var o2 = false || true; // f || t trả về true +var o3 = true || false; // t || f trả về true +var o4 = false || (3 == 4); // f || f trả về false +var o5 = 'Cat' || 'Dog'; // t || t trả về Cat +var o6 = false || 'Cat'; // f || t trả về Cat +var o7 = 'Cat' || false; // t || f trả về Cat +</pre> + +<p>Sau đây là các ví dụ cho toán tử ! (luận lý NOT).</p> + +<pre class="brush: js">var n1 = !true; // !t trả về false +var n2 = !false; // !f trả về true +var n3 = !'Cat'; // !t trả về false +</pre> + +<h4 id="Short-Circuit_Evaluation" name="Short-Circuit_Evaluation">Thực thi đoản-mạch</h4> + +<p>Vì các biểu thức luận lý được thực thi từ trái sang phải, ta có thể dùng chúng để thử tính "đoán-mạch" qua các quy định sau:</p> + +<ul> + <li><code>false</code> && <em>bất cứ gì</em> là thực thi đoản-mạch ra false.</li> + <li><code>true</code> || <em>bất cứ gì</em> là thực thi đoản-mạch ra true.</li> +</ul> + +<p>Quy định luận lý đảm bảo rằng các thực thi trên luôn đúng. Chú ý phần <em>bất cứ gì</em> trong các biểu thức trên không được thực thi, bởi vậy sẽ không xảy ra bất cứ tác dụng phụ nào.</p> + +<h3 id="Toán_tử_chuỗi"><a id="String" name="String">Toán tử chuỗi</a></h3> + +<p>Ngoài toán tử so sánh, có thể dùng để so sánh chuỗi, toán tử ghép (+) ghép hai giá trị chuỗi lại với nhau, trả về một chuỗi mới là hợp của hai chuỗi cũ.</p> + +<p>Chẳng hạn,</p> + +<pre class="brush: js">console.log('my ' + 'string'); // console logs the string "my string".</pre> + +<p>Toán tử gán rút gọn += cũng có thể dùng để ghép chuỗi.</p> + +<p>Chẳng hạn,</p> + +<pre class="brush: js">var mystring = 'alpha'; +mystring += 'bet'; // "alphabet" sẽ ghép với giá trị này trước khi gán vào mystring.</pre> + +<h3 id="Toán_tử_điều_kiện_(ba_ngôi)"><a id="Conditional" name="Conditional">Toán tử điều kiện (ba ngôi)</a></h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">Toán tử điều kiện</a> là toán tử duy nhất của JavaScript cần tới ba toán hạng. Kết quả có thể là một trong hai giá trị tuỳ theo điều kiện. Cú pháp:</p> + +<pre class="syntaxbox"><em>điều_kiện</em> ? <em>giá_trị_1</em> : <em>giá_trị_2</em> +</pre> + +<p>Nếu <code>điều_kiện</code> trả về true, toán tử có giá trị <code>giá_trị_1</code>. Ngược lại toán tử có giá trị <code>giá_trị_2</code>. Bạn có thể dùng toán tử điều kiện ở bất cứ đâu như một toán tử bình thường.</p> + +<p>Chẳng hạn,</p> + +<pre class="brush: js">var status = (age >= 18) ? 'adult' : 'minor'; +</pre> + +<p>Đoạn code này gán giá trị "adult" cho biến <code>status</code> nếu <code>age</code> lớn hơn hoặc bằng 18. Ngược lại, nó gán giá trị "minor" cho <code>status</code>.</p> + +<h3 id="Comma_operator" name="Comma_operator"><a name="Comma">Toán tử dấu phẩy</a></h3> + +<p>Toán tử <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator">dấu phẩy</a> (<code>,</code>) đơn thuần tính toán cả hai giá trị toán hạng của nó và trả về giá trị của toán hạng cuối. Toán tử này được dùng chủ yếu trong vòng lặp <code>for</code>, để cho phép cập nhật nhiều biến cùng lúc sau mỗi lần thực hiện vòng lặp.</p> + +<p>Chẳng hạn, nếu <code>a</code> là một mảng 2-chiều với 10 phần tử mỗi chiều, đoạn code sau dùng toán tử dấu phẩy để cập nhật hai biến cùng một lúc. Console in ra giá trị của các phần tử nằm trong đường chéo:</p> + +<pre class="brush: js">var x = [0,1,2,3,4,5,6,7,8,9] +var a = [x, x, x, x, x]; + +for (var i = 0, j = 9; i <= j; i++, j--) + console.log('a[' + i + '][' + j + ']= ' + a[i][j]); +</pre> + +<h3 id="Toán_tử_một_ngôi"><a id="Unary" name="Unary">Toán tử một ngôi</a></h3> + +<p>Toán tử một ngôi là phép toán chỉ có duy nhất một toán hạng.</p> + +<h4 id="delete" name="delete"><code>delete</code></h4> + +<p>Toán tử <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/delete">delete</a></code> xoá một object, một thuộc tính của object, hoặc một phần tử ở chỉ mục xác định trong mảng. Cú pháp là:</p> + +<pre class="brush: js">delete objectName; +delete objectName.property; +delete objectName[index]; +delete property; // chỉ được khi cài trong lệnh with +</pre> + +<p>Với <code>objectName</code> là tên của object, <code>property</code> là thuộc tính đang tồn tại, và <code>index</code> là giá trị nguyên của chỉ mục tương ứng với vị trí của thuộc tính trong mảng.</p> + +<p>Dạng thứ tư chỉ hoạt động khi được cài trong lệnh <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/with">with</a></code>, để xoá một thuộc tính khỏi object.</p> + +<p>Bạn có thể dùng toán tử <code>delete</code> để xoá biến được khởi tạo ngầm nhưng không thể xoá được các biến được khởi tạo bằng lệnh <code>var</code>.</p> + +<p>Nếu toán tử <code>delete</code> thành công, nó đặt thuộc tính hoặc phần tử đó thành <code>undefined</code>. Toán tử <code>delete</code> trả về <code>true</code> nếu phép toán khả thi; nó trả về <code>false</code> nếu phép toán bất khả thi.</p> + +<pre class="brush: js">x = 42; +var y = 43; +myobj = new Number(); +myobj.h = 4; // tạo thuộc tính h +delete x; // trả về true (có thể xoá nếu khởi tạo ngầm) +delete y; // trả về false (không thể xoá nếu khởi tạo bằng var) +delete Math.PI; // trả về false (không thể xoá thuộc tính tiền định nghĩa) +delete myobj.h; // trả về true (có thể xoá thuộc tính người dùng định nghĩa) +delete myobj; // trả về true (có thể xoá nếu khợi tạo ngầm) +</pre> + +<h5 id="Xoá_phần_tử_mảng">Xoá phần tử mảng</h5> + +<p>Khi bạn xoá một phần tử của mảng, chiều dài mảng không bị ảnh hưởng. Chẳng hạn, nếu bạn xoá <code>a[3]</code>, <code>a[4]</code> vẫn là <code>a[4]</code> và <code>a[3]</code> là undefined.</p> + +<p>Khi toán tử <code>delete</code> loại bỏ một phần tử khỏi mảng, phần tử đó không còn tồn tại trong mảng. Trong ví dụ sau, <code>trees[3]</code> đã được loại bỏ bởi <code>delete</code>. Tuy nhiên, <code>trees[3]</code> vẫn có thể được trỏ tới và trả về <code>undefined</code>.</p> + +<pre class="brush: js">var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']; +delete trees[3]; +if (3 in trees) { + // sẽ không chạy vào đây +} +</pre> + +<p>Nếu bạn muốn kiểm tra sự tồn tại của một phần tử trong mảng nhưng có giá trị là undefined, hãy dùng từ khoá <code>undefined</code> thay cho toán tử <code>delete</code>. Trong ví dụ tiếp sau đây, <code>trees[3]</code> được gán giá trị <code>undefined</code>, nhưng phần tử của mảng vẫn tồn tại:</p> + +<pre class="brush: js">var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']; +trees[3] = undefined; +if (3 in trees) { + // sẽ chạy vào đây +} +</pre> + +<h4 id="typeof" name="typeof"><code>typeof</code></h4> + +<p>Toán tử <a href="/en-US/docs/Web/JavaScript/Reference/Operators/typeof"><code>typeof</code></a> có thể dùng theo cả hai cách dưới đây:</p> + +<pre class="syntaxbox">typeof operand +typeof (operand) +</pre> + +<p>Toán tử <code>typeof</code> trả về một chuỗi ký tự thể hiện kiểu của toán hạng. <code>operand</code> có thể là chuỗi ký tự, biến, từ khoá, hoặc object cần xác định kiểu. Không bắt buộc phải thêm dấu ngoặc tròn.</p> + +<p>Giả sử bạn có các biến sau:</p> + +<pre class="brush: js">var myFun = new Function('5 + 2'); +var shape = 'round'; +var size = 1; +var foo = ['Apple', 'Mango', 'Orange']; +var today = new Date(); +</pre> + +<p>Toán tử <code>typeof</code> trả về kết quả lần lượt cho từng biến:</p> + +<pre class="brush: js">typeof myFun; // trả về "function" +typeof shape; // trả về "string" +typeof size; // trả về "number" +typeof foo; // trả về "object" +typeof today; // trả về "object" +typeof doesntExist; // trả về "undefined" +</pre> + +<p>Với từ khoá <code>true</code> và <code>null</code>, toán tử <code>typeof</code> trả về kết quả sau:</p> + +<pre class="brush: js">typeof true; // trả về "boolean" +typeof null; // trả về "object" +</pre> + +<p>Với số hoặc chuỗi ký tự, toán tử <code>typeof</code> trả về kết quả sau:</p> + +<pre class="brush: js">typeof 62; // trả về "number" +typeof 'Hello world'; // trả về "string" +</pre> + +<p>Với giá trị thuộc tính, toán tử <code>typeof</code> trả về kiểu dữ liệu mà thuộc tính đó bao hàm:</p> + +<pre class="brush: js">typeof document.lastModified; // trả về "string" +typeof window.length; // trả về "number" +typeof Math.LN2; // trả về "number" +</pre> + +<p>Với phương thức hoặc hàm, toán tử <code>typeof</code> trả về kết quả như sau:</p> + +<pre class="brush: js">typeof blur; // trả về "function" +typeof eval; // trả về "function" +typeof parseInt; // trả về "function" +typeof shape.split; // trả về "function" +</pre> + +<p>Với các object tiền định nghĩa, toán tử <code>typeof</code> trả về kết quả như sau:</p> + +<pre class="brush: js">typeof Date; // trả về "function" +typeof Function; // trả về "function" +typeof Math; // trả về "object" +typeof Option; // trả về "function" +typeof String; // trả về "function" +</pre> + +<h4 id="void" name="void"><code>void</code></h4> + +<p>Toán tử <a href="/en-US/docs/Web/JavaScript/Reference/Operators/void"><code>void</code> operator</a> có thể dùng theo cả hai cách dưới đây:</p> + +<pre class="syntaxbox">void (expression) +void expression +</pre> + +<p>Toán tử <code>void</code> xác định biểu thực cần thực hiện mà không trả về giá trị nào. <code>expression</code> là một biểu thức JavaScript cần thực hiện. Dấu ngoặc tròn bao quanh expression là không bắt buộc, nhưng sẽ rất phong cách nếu dùng chúng.</p> + +<p>Bạn có thể dùng toán tử <code>void</code> để xác định biểu thức cần thực thi trong một siêu liên kết. Biểu thức sẽ được thực hiện nhưng không văn bản hiện tại sẽ không tải lại tại chỗ.</p> + +<p>Đoạn code sau tạo ra một siêu liên kết không thực hiện bất cứ điều gì khi có người dùng nhấn vào. Khi người dùng nhấn vào, <code>void(0)</code> thực hiện thành <code>undefined</code>, vốn không có hiệu ứng gì trong JavaScript.</p> + +<pre class="brush: html"><a href="javascript:void(0)">Click here to do nothing</a> +</pre> + +<p>Đoạn code sẽ tiến hành hoàn tất mẫu đơn khi người dùng bấm vào siêu liên kết.</p> + +<pre class="brush: html"><a href="javascript:void(document.form.submit())"> +Click here to submit</a></pre> + +<h3 id="Toán_tử_quan_hệ"><a name="Relational">Toán tử quan hệ</a></h3> + +<p>Toán tử quan hệ so sánh các toán hạng của nó và trả về giá trị <code>Boolean</code> tuỳ thuộc phép so sánh có true hay không.</p> + +<h4 id="in"><code>in</code></h4> + +<p>Toán tử <a href="/en-US/docs/Web/JavaScript/Reference/Operators/in"><code>in</code></a> trả về <code>true</code> nếu thuộc tính nhất định có trong object nhất định. Cú pháp là:</p> + +<pre class="brush: js">propNameOrNumber in objectName +</pre> + +<p>với <code>propNameOrNumber</code> là chuỗi ký tự hoặc số đại diện cho tên của thuộc tính hoặc chỉ mục mảng, và <code>objectName</code> là tên của object.</p> + +<p>Các ví dụ dưới đây chỉ ra vài cách dùng toán tử <code>in</code>.</p> + +<pre class="brush: js">// Arrays +var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple']; +0 in trees; // trả về true +3 in trees; // trả về true +6 in trees; // trả về false +'bay' in trees; // trả về false (bạn phải xác định được chỉ mục của mảng, + // không phải giá trị tại vị trí chỉ mục đó) +'length' in trees; // trả về true (length là một thuộc tính của Array) + +// object dựng sẵn +'PI' in Math; // trả về true +var myString = new String('coral'); +'length' in myString; // trả về true + +// object tự tạo +var mycar = { make: 'Honda', model: 'Accord', year: 1998 }; +'make' in mycar; // trả về true +'model' in mycar; // trả về true +</pre> + +<h4 id="instanceof" name="instanceof"><code>instanceof</code></h4> + +<p>Toán tử <a href="/en-US/docs/Web/JavaScript/Reference/Operators/instanceof"><code>instanceof</code></a> trả về <code>true</code> nếu một object nhất định có kiểu của object nhất định. Cú pháp là:</p> + +<pre class="syntaxbox">objectName instanceof objectType +</pre> + +<p>với <code>objectName</code> là tên của object để so sánh với <code>objectType</code>, và <code>objectType</code> là kiểu của object, như là {{jsxref("Date")}} hay {{jsxref("Array")}}.</p> + +<p>Dùng <code>instanceof</code> khi bạn cần xác nhận kiểu của một object trong runtime (thời gian chạy). Chẳng hạn, khi bắt ngoại lệ, bạn có thể tìm tới từng ngoại lệ riêng biện tuỳ thuộc vào kiểu ngoại lệ được quăng (throw) ra.</p> + +<p>Chẳng hạn, đoạn code dưới đây dùng <code>instanceof</code> để xác định xem liệu <code>theDay</code> có phải là một <code>Date</code> object hay không. Bởi vì <code>theDay</code> là một <code>Date</code> object, các lệnh trong sau điều kiện <code>if</code> được thực thi.</p> + +<pre class="brush: js">var theDay = new Date(1995, 12, 17); +if (theDay instanceof Date) { + // lệnh sẽ được thực thi +} +</pre> + +<h3 id="Thứ_tự_thực_hiện_toán_tử">Thứ tự thực hiện toán tử</h3> + +<p><em>Thứ tự thực hiện</em> của toán tử xác định thứ tự thực hiện trong một biểu thức. Bạn có thể vượt quyền ưu tiên bằng cách dùng dấu ngoặc tròn.</p> + +<p>Bảng sau chỉ ra thứ tự thực hiện toán tử, từ cao nhất tới thấp nhất.</p> + +<table class="standard-table"> + <caption>Thứ tự thực hiện các toán tử</caption> + <thead> + <tr> + <th scope="col">?Loại toán tử</th> + <th scope="col">Individual operators</th> + </tr> + </thead> + <tbody> + <tr> + <td>member</td> + <td><code>. []</code></td> + </tr> + <tr> + <td>gọi / tạo mới instance</td> + <td><code>() new</code></td> + </tr> + <tr> + <td>phủ định/tăng</td> + <td><code>! ~ - + ++ -- typeof void delete</code></td> + </tr> + <tr> + <td>nhân/chia</td> + <td><code>* / %</code></td> + </tr> + <tr> + <td>cộng/trừ</td> + <td><code>+ -</code></td> + </tr> + <tr> + <td>dịch bit</td> + <td><code><< >> >>></code></td> + </tr> + <tr> + <td>quan hệ</td> + <td><code>< <= > >= in instanceof</code></td> + </tr> + <tr> + <td>bằng</td> + <td><code>== != === !==</code></td> + </tr> + <tr> + <td>bitwise-and</td> + <td><code>&</code></td> + </tr> + <tr> + <td>bitwise-xor</td> + <td><code>^</code></td> + </tr> + <tr> + <td>bitwise-or</td> + <td><code>|</code></td> + </tr> + <tr> + <td>logical-and</td> + <td><code>&&</code></td> + </tr> + <tr> + <td>logical-or</td> + <td><code>||</code></td> + </tr> + <tr> + <td>điều kiện</td> + <td><code>?:</code></td> + </tr> + <tr> + <td>gán</td> + <td><code>= += -= *= /= %= <<= >>= >>>= &= ^= |=</code></td> + </tr> + <tr> + <td>?dấu phẩy</td> + <td><code>,</code></td> + </tr> + </tbody> +</table> + +<p>Bảng thứ tự thực hiện chi tiết hơn có thể tìm được trong <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table">JavaScript Reference</a>.</p> + +<h2 id="Biểu_thức">Biểu thức</h2> + +<p><em>Biểu thức</em> là đơn vị code hợp lệ mà giải được ra một giá trị.</p> + +<p>Mọi biểu thức đúng cú pháp đều trả về vài giá trị nào đó nhưng về mặt lý thuyết, có hai kiểu biểu thức: kèm tác dụng phụ (chẳng hạn: những biểu thức gán giá trị cho biến nào đó) và những biểu thức thực hiện gì đấy rồi trả về giá trị.</p> + +<p>Biểu thức <code>x = 7</code> là ví dụ cho kiểu thứ nhất. Biểu thức này dùng <em>toán tử =</em> để gán giá trị cho biến <code>x</code>. Tự biểu thức trả về 7.</p> + +<p>Đoạn code <code>3 + 4</code> là ví dụ cho kiểu biểu thức thứ hai. Biểu thức này dùng toán tử + để thêm bốn vào ba mà không gán kết quả, bảy, cho một biến nào.<br> + <br> + JavaScript có các loại biểu thức sau đây:</p> + +<ul> + <li>Số học: tính toán thành một số, chẳng hạn 3.14159. (Thường dùng với <a href="#Arithmetic">toán tử số học</a>.)</li> + <li>Chuỗi ký tự: tính toán thành một chuỗi ký tự, chẳng hạn, "Fred" hoặc "234". (Thường dùng với <a href="#String">toán tử chuỗi</a>.)</li> + <li>Logic: tính toán thành true hoặc false. (Thường đi cùng với <a href="#Logical">toán tử luận lý</a>.)</li> + <li>Biểu thức nguyên thuỷ: Từ khoá căn bản và biểu thức chung trong JavaScript.</li> + <li>Biểu thức vế-trái: Giá trị bên trái là đích của phép gán.</li> +</ul> + +<h3 id="Biểu_thức_nguyên_thuỷ">Biểu thức nguyên thuỷ</h3> + +<p>Từ khoá căn bản và biểu thức chung trong JavaScript.</p> + +<h4 id="this" name="this"><code>this</code></h4> + +<p>Dùng từ khoá <a href="/en-US/docs/Web/JavaScript/Reference/Operators/this"><code>this</code></a> để trỏ đến object hiện tại. Tổng quát, <code>this</code> trỏ tới object đang gọi trong một phương thức. Có thể dùng <code>this</code> cùng với dấu chấm hoặc dấu ngoặc vuông:</p> + +<pre class="syntaxbox">this['propertyName'] +this.propertyName +</pre> + +<p>Giả sử hàm <code>validate</code> xác thực thuộc tính <code>value</code> của object, truyền vào cận trên và cận dưới của nó:</p> + +<pre class="brush: js">function validate(obj, lowval, hival) { + if ((obj.value < lowval) || (obj.value > hival)) + console.log('Invalid Value!'); +} +</pre> + +<p>Bạn có thể gọi <code>validate</code> trong mỗi bộ xử lý sự kiện <code>onChange</code> trong form, dùng <code>this</code> để truyền vào phần tử của form, như trong ví dụ sau:</p> + +<pre class="brush: html"><p>Enter a number between 18 and 99:</p> +<input type="text" name="age" size=3 onChange="validate(this, 18, 99);"> +</pre> + +<h4 id="Toán_tử_nhóm">Toán tử nhóm</h4> + +<p>Toán tử nhóm <code>( )</code> kiểm soát thứ tự thực hiện trong biểu thức. Chẳng hạn, bạn có thể cho phép nhân và chia thực hiện sau khi cộng và trừ.</p> + +<pre class="brush:js">var a = 1; +var b = 2; +var c = 3; + +// thứ tự mặc định +a + b * c // 7 +// mặc định sẽ thực hiện như thế này +a + (b * c) // 7 + +// giờ vượt thứ tự nào +// cộng trước rồi mới nhân +(a + b) * c // 9 + +// tương tự như +a * c + b * c // 9 +</pre> + +<h3 id="Toán_tử_vế-trái">Toán tử vế-trái</h3> + +<p>Giá trị bên trái là đích của phép gán.</p> + +<h4 id="new" name="new"><code>new</code></h4> + +<p>Bạn có thể dùng toán tử <a href="/en-US/docs/Web/JavaScript/Reference/Operators/new"><code>new</code></a> để tạo ra một instance thuộc kiểu object mà người-dùng-định-nghĩa hoặc một trong những kiểu object dựng-sẵn. Dùng <code>new</code> như sau:</p> + +<pre class="brush: js">var objectName = new objectType([param1, param2, ..., paramN]); +</pre> + +<h4 id="super">super</h4> + +<p>Từ khoá <a href="/en-US/docs/Web/JavaScript/Reference/Operators/super">super</a> được dùng để gọi hàm thuộc cha của object. Thường dùng bởi <a href="/en-US/docs/Web/JavaScript/Reference/Classes">classes</a> để gọi phương thức khởi tạo của lớp cha, chẳng hạn.</p> + +<pre class="syntaxbox">super([arguments]); // gọi phương thức khởi tạo của lớp cha. +super.functionOnParent([arguments]); +</pre> + +<h4 id="Toán_tử_Spread">Toán tử Spread</h4> + +<p>Toán tử <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator">spread</a> cho phép biểu thức mở rộng tại chỗ khi có nhiều tham số (khi gọi hàm) hoặc nhiều phần tử (với array literal).</p> + +<p><strong>Ví dụ:</strong> Nếu bạn có một mảng và muốn tạo một mảng mới với mảng cũ là một thành phần trong nó, cú pháp của array literal không bao giờ là đủ và bạn bắt buộc phải code chay, dùng tổ hợp <code>push</code>, <code>splice</code>, <code>concat</code>, vân vân. Với cú pháp spread, việc này súc tích hơn hẳn:</p> + +<pre class="brush: js">var parts = ['shoulders', 'knees']; +var lyrics = ['head', ...parts, 'and', 'toes'];</pre> + +<p>Tương tự, toán tử spread cũng hoạt động với lời gọi hàm:</p> + +<pre class="brush: js">function f(x, y, z) { } +var args = [0, 1, 2]; +f(...args);</pre> + +<div>{{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}</div> diff --git a/files/vi/web/javascript/guide/functions/index.html b/files/vi/web/javascript/guide/functions/index.html new file mode 100644 index 0000000000..069a43ef80 --- /dev/null +++ b/files/vi/web/javascript/guide/functions/index.html @@ -0,0 +1,668 @@ +--- +title: Functions +slug: Web/JavaScript/Guide/Functions +tags: + - Bắt đầu + - Hướng dẫn + - JavaScript + - hàm +translation_of: Web/JavaScript/Guide/Functions +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}</div> + +<p class="summary">Functions are one of the fundamental building blocks in JavaScript. A function is a JavaScript procedure—a set of statements that performs a task or calculates a value. To use a function, you must define it somewhere in the scope from which you wish to call it.</p> + +<p>See also the <a href="/en-US/docs/Web/JavaScript/Reference/Functions">exhaustive reference chapter about JavaScript functions</a> to get to know the details.</p> + +<h2 id="Định_nghĩa_hàm">Định nghĩa hàm</h2> + +<h3 id="Khai_báo_hàm">Khai báo hàm</h3> + +<p><strong>Định nghĩa hàm</strong> (hay còn gọi là <strong>khai báo hằm</strong>, hoặc <strong>lệnh hàm</strong>) bao gồm từ khóa <a href="/en-US/docs/Web/JavaScript/Reference/Statements/function" title="function"><code>function</code></a>, theo sau nó là:</p> + +<ul> + <li>Tên của hàm.</li> + <li>Danh sách các tham số truyền vào hàm, được đặt trong ngoặc đơn và cách nhau bởi dấu phẩy.</li> + <li>Các câu lệnh của JavaScript để tạo ra một hàm, được đặt trong ngoặc nhọn <code>{...}</code>.</li> +</ul> + +<p>Ví dụ, để định nghĩa một hàm có tên là <code>square</code>:</p> + +<pre class="brush: js">function square(number) { + return number * number; +} +</pre> + +<p>Hàm <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">square</span></font> nhận 1 tham số, có tên là <code>number</code>. Hàm này bao gồm một câu lệnh mà nó sẽ trả về tham số (<font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">number</span></font>) nhân với chính nó. Câu lệnh <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/return" title="return">return</a></code> chỉ định giá trị được trả lại bới hàm.</p> + +<pre class="brush: js">return number * number; +</pre> + +<p>Các tham số nguyên thủy (primitive parameters - ví dụ như một số) được truyền vào hàm <strong>bằng giá trị</strong>; giá trị được truyền vào hàm, nhưng nếu hàm thay đổi giá trị của tham số, <strong>sự thay đổi này sẽ không ánh xạ trên phạm vi global hoặc trên hàm gọi đến nó</strong> (nó sẽ không thay đổi giá trị của tham số được truyền vào ở phạm vi bên ngoài hàm).</p> + +<p>Nếu bạn truyền vào hàm một tham số là object (một giá trị non-primitive), ví dụ như một mảng {{jsxref("Array")}} hoặc một object được user tự định nghĩa, và hàm thay đổi các thuộc tính của object, thay đổi đó sẽ có hiệu lực ngay cả ở phạm vi bên ngoài của hàm, giống như ví dụ dưới đây:</p> + +<pre class="brush: js">function myFunc(theObject) { + theObject.make = "Toyota"; +} + +var mycar = {make: "Honda", model: "Accord", year: 1998}; +var x, y; + +x = mycar.make; // x nhận giá trị "Honda" + +myFunc(mycar); +y = mycar.make; // y nhận giá trị "Toyota" + // (thuộc tính make đã bị thay đổi bởi hàm myFunc) +</pre> + +<h3 id="Biểu_thức_hàm_hàm_trong_biến">Biểu thức hàm (hàm trong biến)</h3> + +<p>Trong khi việc khai báo hàm ở trên là một câu lệnh về mặt cú pháp, các hàm cũng có thể tạo ra bằng một biểu thức hàm (<a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function">function expression</a>). Một hàm như vậy có thể <strong>nặc danh</strong>; nó không cần phải có tên. Ví dụ, hàm <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">square</span></font> có thể được khai báo như sau:</p> + +<pre class="brush: js">const square = function(number) { return number * number }; // square lúc này là một hằng giúp nặc danh cho hàm gán cho nó +var x = square(4) // x nhận giá trị 16</pre> + +<p>Tuy nhiên, một cái tên <em>có thể</em> được cung cấp trong một biểu thức hàm. Việc cung cấp tên cho phép hàm có thể chạy chính nó, hoặc có thể sử dụng hệ thống debug để nhận dạng hàm trong stack traces.</p> + +<pre class="brush: js">const factorial = function fac(n) { return n < 2 ? 1 : n * fac(n-1) }; + +console.log(factorial(3)); +</pre> + +<p>Các biểu thức hàm rất tiện lợi trong việc truyền một hàm vào một hàm khác dưới vai trò một đối số (argument). Ví dụ sau cho thấy hàm <code>map</code> sẽ nhận một hàm khác là đối số đầu tiên và đối số thứ hai là một mảng.</p> + +<pre class="brush: js">function map(f,a) { + var result = [], // Create a new Array + i; + for (i = 0; i != a.length; i++) + result[i] = f(a[i]); + return result; +} +</pre> + +<p>Trong đoạn code dưới đây, hàm <code>map</code> nhận vào một hàm khác đã được định nghĩa bằng một biểu thức hàm, và <code>map</code> sẽ thực thi nó trên mọi phần tử của mảng (được truyền vào như một đối số thứ hai):</p> + +<pre class="brush: js">map(function(x) {return x * x * x}, [0, 1, 2, 5, 10]); +</pre> + +<p>Kết quả trả về: [<code>0, 1, 8, 125, 1000]</code>.</p> + +<p>Trong JavaScript, một hàm có thể được định nghĩa dựa trên một điều kiện. Ví dụ, việc định nghĩa hàm dưới đây sẽ định nghĩa hàm <code>myFunc</code> chỉ khi <code>num</code> bằng 0.</p> + +<pre class="brush: js">var myFunc; +if (num == 0){ + myFunc = function(theObject) { + theObject.make = "Toyota" + } +}</pre> + +<p>Ngoài các cách định nghĩa hàm đã được mô tả, bạn cũng có thể sử dụng {{jsxref("Function")}} constructor to create functions from a string at runtime, much like {{jsxref("eval", "eval()")}}.</p> + +<p>Một <strong>phương thức</strong> là một hàm mà hàm đó chính là thuộc tính của một object. Xem thêm về object và phương thức tại đây <a href="/en-US/docs/Web/JavaScript/Guide/Working_with_Objects" title="en-US/docs/JavaScript/Guide/Working with Objects">Working with objects</a>.</p> + +<h2 id="Gọi_hàm">Gọi hàm</h2> + +<p><em>Việc định nghĩa</em> một hàm sẽ không <em>thực thi</em> nó. Định nghĩa một hàm đơn giản chỉ là đặt tên cho hàm và chỉ định những việc cụ thể sẽ làm khi hàm đó được gọi.</p> + +<p><strong>Gọi </strong>hàm thực chất là thi hành các hành động cụ thể với các tham số được chỉ định. Ví dụ, nếu bạn định nghĩa hàm <code>square</code>, bạn có thể gọi nó như sau:</p> + +<pre class="brush: js">square(5); +</pre> + +<p>Câu lệnh bên trên gọi hàm với một đối số của <code>5</code>. Hàm thực thi các câu lệnh của nó và trả về giá trị <code>25</code>.</p> + +<p>Các hàm phải đặt <em>trong phạm vi (</em><em>in scope)</em> khi nó được gọi, nhưng việc khai báo hàm có thể được hoisted (câu lệnh khai báo hàm xuất hiện bên dưới dòng gọi hàm trong đoạn code), như ví dụ này:</p> + +<pre class="brush: js">console.log(square(5)); +/* ... */ +function square(n) { return n*n } +</pre> + +<p>Phạm vi (scope) của một hàm là khoảng không gian bên trong hàm mà nó được khai báo (hoặc là cả chương trình, nếu nó được khai bảo ở top level, tức là nó không nằm trong hàm náo khác).</p> + +<div class="note"> +<p><strong>Ghi chú:</strong> Điều này chỉ đúng khi định nghĩa một hàm bằng cách sử dụng các cú pháp ở trên (ví dụ <code>function funcName(){}</code>). Đoạn code bên dưới sẽ không hoạt động.</p> + +<p>Điều này có nghĩa rằng function hoisting chỉ hoạt động với cách khai báo hàm thông thường (function declarations) - function hoisting không hoạt động đối với hàm được khai báo bằng biểu thức hàm (function expression).</p> +</div> + +<pre class="brush: js example-bad">console.log(square); // ReferenceError: square is not defined +console.log(square(5)); // ReferenceError: square is not defined +square = function (n) { + return n * n; +} +</pre> + +<p>Các đối số của một hàm không bị giới hạn trong phạm vi các chuỗi và các số. Bạn có thể truyền các object hoàn chỉnh vào một hàm. Hàm <code>show_props()</code>(được định nghĩa trong <a href="/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Objects_and_Properties" title="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Working_with_Objects#Objects_and_Properties">Working with objects</a>) là một ví dụ của một hàm mà nó nhận một object như là một đối số.</p> + +<p>Một hàm có thể gọi chính nó. Ví dụ, đây là một hàm tính giai thừa đệ quy:</p> + +<pre class="brush: js">function factorial(n){ + if ((n == 0) || (n == 1)) + return 1; + else + return (n * factorial(n - 1)); +} +</pre> + +<p>Bạn có thể tính giai thừa của <code>1</code> tới <code>5</code> như sau:</p> + +<pre class="brush: js">var a, b, c, d, e; +a = factorial(1); // a gets the value 1 +b = factorial(2); // b gets the value 2 +c = factorial(3); // c gets the value 6 +d = factorial(4); // d gets the value 24 +e = factorial(5); // e gets the value 120 +</pre> + +<p>Có những cách khác để gọi hàm. Có nhiều trường hợp mà tại đó một hàm cần phải được gọi một cách tự động, hoặc làm thay đổi số lượng đối số truyền vào một hàm, hoặc trong trường hợp mà việc gọi hàm cần được gắn với một object nhất định được quyết định tại thời điểm runtime.</p> + +<p>Điều đó lại hóa ra là <em>các hàm tự bản thân chúng là các object</em>, và kết quả là, những object này có các phương thức. (Xem {{jsxref("Function")}} object). Một trong số chúng, phương thức {{jsxref("Function.apply", "apply()")}}, có thể được dùng để đạt được mục tiêu này.</p> + +<h2 class="deki-transform" id="Phạm_vi_của_hàm_function_scope">Phạm vi của hàm (function scope)</h2> + +<p>Các biến được định nghĩa bên trong một hàm không thể được truy cập từ nơi nào khác bên ngoài hàm, bởi vì biến đó được định nghĩa chỉ trong phạm vi của hàm. Tuy nhiên, một hàm có thể truy cập đến mọi biến và mọi hàm khác trong cùng phạm vi mà nó được định nghĩa.</p> + +<p>Nói cách khác, một hàm được định nghĩa trong phạm vi global có thể truy cập tới tất cả các biến đã được định nghĩa trong phạm vi global. Một hàm được định nghĩa bên trong một hàm khác có thể truy cập đến tất cả biến được định nghĩa bên trong hàm cha của nó, và bất cứ biến nào khác mà hàm cha của nó có quyền truy cập đến.</p> + +<pre class="brush: js">// Các biến sau được định nghĩa trong phạm vi global scope +var num1 = 20, + num2 = 3, + name = "Chamahk"; + +// Hàm này được định nghĩa trong phạm vi global scope +function multiply() { + return num1 * num2; +} + +multiply(); // Returns 60 + +// Một ví dụ hàm lồng nhau +function getScore () { + var num1 = 2, + num2 = 3; + + function add() { + return name + " scored " + (num1 + num2); + } + + return add(); +} + +getScore(); // Returns "Chamahk scored 5" +</pre> + +<h2 id="Phạm_vi_và_ngăn_xếp_của_hàm">Phạm vi và ngăn xếp của hàm</h2> + +<h3 id="Recursion">Recursion</h3> + +<p>Một hàm có thể tham chiếu và gọi chính nó. Có 3 cách để một hàm có thể tham chiếu đến chính nó:</p> + +<ol> + <li>Dùng tên của hàm</li> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee">arguments.callee</a></code></li> + <li>Một biến in-scope mà có tham chiếu đến hàm.</li> +</ol> + +<p>Ví dụ, xem xét việc định nghĩa hàm sau đây:</p> + +<pre class="brush: js">var foo = function bar() { + // statements go here +}; +</pre> + +<p>Bên trong phần body của hàm, các điều sau là tương tự nhau:</p> + +<ol> + <li><code>bar()</code></li> + <li><code>arguments.callee()</code></li> + <li><code>foo()</code></li> +</ol> + +<p>Một hàm mà gọi chính nó được gọi là (<em>hàm đệ quy)</em> <em>recursive function</em>. Trong một số cách hiểu, thì đệ quy (recursion) cũng tương tự như một vòng lặp. Cả hai đều là thực thi một đoạn code lặp đi lặp lại nhiều lần, và cả hai đều yêu cầu điều kiện xác định để chạy (để tránh lặp vô tận, hoặc recursion vô tận). Ví dụ, vòng lặp sau đây... </p> + +<pre class="brush: js">var x = 0; +while (x < 10) { // "x < 10" là điều kiện lặp + // thực thi việc sau + x++; +} +</pre> + +<p>...có thể được chuyển đổi sang một hàm đệ quy:</p> + +<pre class="brush: js">function loop(x) { + if (x >= 10) // "x >= 10" là điều kiện thoát ra (tương đương với "!(x < 10)") + return; + // do stuff + loop(x + 1); // the recursive call +} +loop(0); +</pre> + +<p>Tuy nhiên, một số thuật toán không phải là các vòng lặp chỉ đơn giản là được lặp đi lặp lại. Ví dụ, việc lấy tất cả các nodes của một cấu trúc tree (như <a href="/en-US/docs/DOM">DOM</a>) sẽ được thực hiện dễ dàng hơn thông qua đệ quy:</p> + +<pre class="brush: js">function walkTree(node) { + if (node == null) // + return; + // do something with node + for (var i = 0; i < node.childNodes.length; i++) { + walkTree(node.childNodes[i]); + } +} +</pre> + +<p>So với hàm <code>loop</code>, mỗi một lần gọi đệ quy sẽ tạo ra nhiều lần gọi đệ quy tại đây.</p> + +<p>Bạn có thể chuyển đổi bất kỳ thuật toán đệ quy nào sang một dạng non-recursive, nhưng logic thường sẽ phức tạp hơn rất nhiều, và làm như vậy cũng đòi hỏi sử dụng một ngăn xếp (a stack).</p> + +<p>Thực tế, việc đệ quy bản thân nó khi đệ quy có sử dụng một ngăn xếp: gọi là ngăn xếp hàm (function stack). Lối thực thi dạng ngăn xếp này có thể được tìm thấy trong ví dụ dưới đây:</p> + +<pre class="brush: js">function foo(i) { + if (i < 0) + return; + console.log('begin:' + i); + foo(i - 1); + console.log('end:' + i); +} +foo(3); + +// Output: + +// begin:3 +// begin:2 +// begin:1 +// begin:0 +// end:0 +// end:1 +// end:2 +// end:3</pre> + +<h3 id="Hàm_lồng_nhau_và_các_closures">Hàm lồng nhau và các closures</h3> + +<p>Bạn có thể lồng một hàm bên trong một hàm khác. Hàm con (bên trong) được là private cho hàm chứa nó (hàm bao bên ngoài).</p> + +<p>Điều đó cũng định hình nên một <em>closure</em>. Một closure là một biểu thức (thường thì chính là một hàm) mà biểu thức đó có thể có các biến tự do kết hợp với môi trường trói buộc chúng (hay nói cách khác là môi trường giúp "close" biểu thức).</p> + +<p>Vì một hàm con là một closure, có nghĩa rằng hàm con có thể "thừa kế" các tham số và các biến của hàm cha. Nói cách khác, một hàm con sẽ chứa scope của hàm cha.</p> + +<p>Tóm tắt lại:</p> + +<ul> + <li>Hàm con chỉ có thể được truy cập từ các câu lệnh đặt bên trong hàm cha.</li> + <li>Hàm con sẽ định hình nên một closure: hàm con có thể sử dụng các đối số và các biến của hàm cha, trong khi hàm cha không thể sử dụng các đối số và các biến của hàm con.</li> +</ul> + +<p>Ví dụ sau chỉ ra các hàm được lồng nhau:</p> + +<pre class="brush: js">function addSquares(a,b) { + function square(x) { + return x * x; + } + return square(a) + square(b); +} +a = addSquares(2,3); // returns 13 +b = addSquares(3,4); // returns 25 +c = addSquares(4,5); // returns 41 +</pre> + +<p>Vì hàm con định hình nên một closure, bạn có thể gọi hàm cha đồng thời chỉ định các đối số cho cả hàm cha và hàm con.</p> + +<pre class="brush: js">function outside(x) { + function inside(y) { + return x + y; + } + return inside; +} +fn_inside = outside(3); // Kết quả trả về hàm inside(y) +result = fn_inside(5); // Trả về 8 + +result1 = outside(3)(5); // Trả về 8, các đối số được thêm đồng thời cùng lúc +</pre> + +<h3 id="Sự_bảo_tồn_của_các_biến">Sự bảo tồn của các biến</h3> + +<p>Để ý cách mà <code>x</code> được bảo tồn sau khi hàm <code>inside</code> returne. Một closure phải bảo tồn các đối số và các biến bên trong mọi scope mà nó tham chiếu. Vì mỗi lần gọi hàm mang đến các tham số đôi khi khác nhau, nên một closure mới sẽ được tạo ra cho mỗi lần gọi hàm <code>outside</code>. Bộ nhớ bảo tồn này chỉ có thể được giải phóng khi hàm <code>inside</code> được return không còn khả dụng.</p> + +<p>Điều này không khác gì so với lưu trữ các sự tham chiếu bên trong các object khác, nhưng điều này ít rõ ràng hơn vì nó không thiết lập các sự tham chiếu một cách trực tiếp và cũng không thể kiểm tra được chúng.</p> + +<h3 id="Các_hàm_lồng_nhau_nhiều_cấp">Các hàm lồng nhau nhiều cấp</h3> + +<p>Các hàm có thể được lồng nhau nhiều cấp. Ví dụ:</p> + +<ul> + <li>Một hàm (<code>A</code>) chứa một hàm (<code>B</code>), hàm (<code>B</code>) này chứa một hàm (<code>C</code>)</li> + <li>Ở đây, cả hai hàm <code>B</code> và <code>C</code> định hình nên các closures.Vì thế, <code>B</code> có thể truy cập đến <code>A</code>, và <code>C</code> có thể truy cập đến <code>B</code>.</li> + <li>Ngoài ra, vì <code>C</code> có thể truy cập đến <code>B</code> mà <code>B</code> truy cập được đến <code>A</code>, nên <code>C</code> cũng có thể truy cập đến <code>A</code>.</li> +</ul> + +<p>Do đó, các closures có thể chứa nhiều scope đa cấp; các closures sẽ bao gồm luôn cả phạm vi scope của các hàm chưa nó, việc bao gồm này có hình thức đệ quy. Đây gọi là <em>scope chaining.</em> (Lí do tại sao gọi là "chaining" sẽ giải thích sau).</p> + +<p>Cân nhắc ví dụ sau:</p> + +<pre class="brush: js">function A(x) { + function B(y) { + function C(z) { + console.log(x + y + z); + } + C(3); + } + B(2); +} +A(1); // logs 6 (1 + 2 + 3) +</pre> + +<p>Trong ví dụ này, <code>C</code> truy cập đến <code>y</code> của <code>B</code> và <code>x</code> của <code>A</code>. Điều này có thể đạt được bởi vì: </p> + +<ol> + <li><code>B</code> định hình một closure mà closure này bao gồm <code>A</code>, ví dụ <code>B</code> có thể truy cập đến các đối số và biến của <code>A</code>.</li> + <li><code>C</code> định hình nên một closure mà closure này bao gồm <code>B</code>.</li> + <li>Vì closure của <code>B</code> bao gồm <code>A</code>, closure của <code>C</code> bao gồm <code>A</code>, <code>C</code> có thể truy cập đến biến và đối số của cả hai hàm <code>A</code> và <code>B</code>. Nói cách khác, <code>C</code> <em>chains </em>the scopes của <code>B</code> và <code>A</code>, <em>theo đúng thứ tự đó</em>.</li> +</ol> + +<p>Tuy nhiên nếu chạy ngược lại thì không đúng. <code>A</code> không thể truy cập đến <code>C</code>, vì <code>A</code> không thể truy cập đén các đối số và biến của <code>B</code>, mà <code>C</code> chính là một biến của <code>B</code>. Vì vậy <code>C</code> duy trì quyền truy cập private chỉ riêng đối với <code>B</code>.</p> + +<h3 id="Xung_đột_tên_gọi">Xung đột tên gọi</h3> + +<p>Khi hai đối số hoặc biến trong một scope của một closure có tên giống nhau, sẽ xảy ra <em>xung đột tên gọi,</em> scope nào nằm ở trong sâu hơn thì được ưu tiên. Cho nên, scope trong cùng sẽ mang ưu tiên cao nhất, trong khi scope ngoài cùng ưu tiên thấp nhất. Đây chính là scope chain (chuỗi xích phạm vi). Mắc xích đầu tiên của chain là scope trong cùng, và mắc xích cuối cùng của chain là scope ngoài cùng. Xem xét ví dụ sau:</p> + +<pre class="brush: js">function outside() { + var x = 10; + function inside(x) { + return x; + } + return inside; +} +result = outside()(20); // returns 20 thay vì 10 +</pre> + +<p>Xung đột tên gọi xảy ra tại câu lệnh <code>return x</code> giữa tham số <code>x</code> của hàm <code>inside</code> và tham số <code>x</code> của hàm <code>outside</code>. Scope chain ở đây là {<code>inside</code>, <code>outside</code>, global object}. Vì vậy tham số <code>x</code> của <code>inside</code> được ưu tiên hơn <code>x</code> của <code>outside</code>, và 20 (giá trị <code>x</code> của <code>insisde</code>) được trả về thay vì 10.</p> + +<h2 id="Closures">Closures</h2> + +<p>Closures là một trong những chức năng quyền lực nhất của JavaScript. JavaScript cho phép lồng các function vào nhau, và cấp quyền cho function con, để function con có toàn quyền truy cập vào tất cả các biến và function được định nghĩa bên trong function cha (và tất cả biến và function mà function cha được cấp quyền truy cập đến).</p> + +<p>Tuy nhiên, function cha không có quyền truy cập đến các biến và function được định nghĩa bên trong function con. Điều này tạo nên một dạng bảo mật khép kín cho các biến của function con.</p> + +<p>Bên cạnh đó, vì function con có quyền truy cập đến scope của function cha, các biến và function được định nghĩa bên trong function cha sẽ vẫn tồn tại dù việc thực thi function cha đã kết thúc, nếu function con xoay sở để tồn tại lâu hơn thời gian sống của function cha. Một closure được tạo ra khi một function con bằng cách nào đó trở nên khả dụng với bất kỳ scope nào bên ngoài function cha.</p> + +<pre class="brush: js">var pet = function(name) { // Function cha định nghĩa một biến tên là "name" + var getName = function() { + return name; // Function con có quyền truy cập đến biến "name" của function cha + } + return getName; // Trả về function con, theo đó làm function con bị phơi bày ra phạm vi scope bên ngoài (không còn bị giới hạn bên trong function cha nữa) +}, +myPet = pet("Vivie"); + +myPet(); // Returns "Vivie" +</pre> + +<p>Thực tế sẽ phức tạp hơn nhiều so với đoạn code bên trên. Nó có thể trả về một object bao gồm các phương thức phục vụ cho việc điều khiển các biến bên trong một function cha.</p> + +<pre class="brush: js">var createPet = function(name) { + var sex; + + return { + setName: function(newName) { + name = newName; + }, + + getName: function() { + return name; + }, + + getSex: function() { + return sex; + }, + + setSex: function(newSex) { + if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) { + sex = newSex; + } + } + } +} + +var pet = createPet("Vivie"); +pet.getName(); // Vivie + +pet.setName("Oliver"); +pet.setSex("male"); +pet.getSex(); // male +pet.getName(); // Oliver +</pre> + +<p>Tron đoạn code trên, các function con có thể truy cập vào biến <code>name</code> của function cha, và không có cách nào khác để truy cập vào các biến của function con ngoại trừ thông qua function con. Các biến bên trong của function con đóng vai trò như kho lưu trữ an toàn cho các đối số và biến bên ngoài. Chúng giữ dữ liệu một cách kiên định, và nội bộ, để function con xử lý. Các functions thậm chí không cần phải gán vào bất kỳ biến nào, và cũng không cần tên.</p> + +<pre class="brush: js">var getCode = (function(){ + var secureCode = "0]Eal(eh&2"; // Đoạn code chúng ta không muốn những thứ bên ngoài có thể thay đổi nó... + + return function () { + return secureCode; + }; +})(); + +getCode(); // Returns the secureCode +</pre> + +<p><strong>Lưu ý</strong>: Có một vài cạm bẫy cần đề phòng khi sử dụng các closures!</p> + +<p>Nếu một function bị bọc kín định nghĩa một biến với tên trùng với tên của function bên ngoài, từ đó sẽ không có cách nào khác để tham chiếu đến biến của function bên ngoài nữa. (Lúc này biến của function bên trong đã ghi đè lên biến bên ngoài, cho đến khi chương trình thoát khỏi scope bên trong.)</p> + +<pre class="brush: js">var createPet = function(name) { // Outer function defines a variable called "name" + return { + setName: function(name) { // Enclosed function also defines a variable called "name" + name = name; // ??? How do we access the "name" defined by the outer function ??? + } + } +} +</pre> + +<p>The magical <code>this</code> variable is very tricky in closures. They have to be used carefully, as what <code>this</code> refers to depends completely on where the function was called, rather than where it was defined.</p> + +<h2 id="Sử_dụng_arguments_object">Sử dụng arguments object</h2> + +<p>Các đối số của một function được giữ dưới dạng một object dạng mảng. Trong phạm vi function, bạn có thể định vị các đối số được truyền vào function bằng cách sau:</p> + +<pre class="brush: js">arguments[i] +</pre> + +<p>trong đó <code>i</code> là số thứ tự của đối số, bắt đầu từ 0. Vì vậy, đối số đầu tiên được truyền vào một function sẽ là <code>arguments[0]</code>. Tổng số đối số được xác định bằng <code>arguments.length</code>.</p> + +<p>Sử dụng các <code>arguments</code> object, bạn có thể gọi một function với số đối số nhiều hơn số đối số được chấp nhận thông qua khai báo chính thức. Điều này sẽ hữu ích khi bạn không biết trước có bao nhiêu đối số sẽ được truyền vào function. Bạn có thể sử dụng <code>arguments.length</code> để xác định số lượng đối số thực tế được truyền vào function, và sau đó truy cập đến từng đối số bằng cách dùng <code>arguments</code> object. </p> + +<p>Ví dụ, xem xét một function có chức năng nối các string với nhau. Đối số chính thức duy nhất cho function là một string, và string này xác định những ký tự nào sẽ tách các phần tử ra để nối. Function được định nghĩa như sau:</p> + +<pre class="brush: js">function myConcat(separator) { + var result = "", // initialize list + i; + // iterate through arguments + for (i = 1; i < arguments.length; i++) { + result += arguments[i] + separator; + } + return result; +} +</pre> + +<p>Bạn có thể truyền vào bao nhiêu đối số vào function này cũng được, và nó sẽ nối từng đối số với nhau tạo thành một "list" có kiểu string.</p> + +<pre class="brush: js">// returns "red, orange, blue, " +myConcat(", ", "red", "orange", "blue"); + +// returns "elephant; giraffe; lion; cheetah; " +myConcat("; ", "elephant", "giraffe", "lion", "cheetah"); + +// returns "sage. basil. oregano. pepper. parsley. " +myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley"); +</pre> + +<div class="note"> +<p><strong>Ghi chú:</strong> Biến <code>arguments</code> nhìn giống mảng, nhưng nó không phải là một mảng. Nó giống mảng ở chỗ bên trong nó có các index được đánh số và nó có một thuộc tính <code>length</code>. Tuy nhiên, nó <em>không</em> sở hữu bất kỳ phương thức nào để thao tác sử dụng mảng.</p> +</div> + +<p>Xem {{jsxref("Function")}} object trong JavaScript reference để biết thêm.</p> + +<h2 id="Các_tham_số_của_function">Các tham số của function</h2> + +<p>Kể từ ES6, xuất hiện 2 dạng tham số mới: <em>default parameters</em> và <em>rest parameters</em></p> + +<h3 id="Default_parameters">Default parameters</h3> + +<p>Trong JavaScript, các tham số của function được mặc định là <code>undefined</code>. Tuy nhiên, trong một số trường hợp nó có thể hữu ích để thiết lập một giá trị mặc định khác. Đây chính xác là điều mà default parameters sẽ làm.</p> + +<h4 id="Khi_không_có_default_parameters_trước_ES6">Khi không có default parameters (trước ES6)</h4> + +<p>Trong quá khứ, chiến thuật thông thường để thiết lập các giá trị mặc định là kiểm định giá trị của các tham số bên trong body của function và gán giá trị cho nó nếu nó là <code>undefined</code>.</p> + +<p>Trong ví dụ sau, nếu không có giá trị nào được truyền cho <code>b</code>, giá trị của nó sẽ là <code>undefined</code> khi thực hiện tính toán <code>a*b</code>, và việc gọi hàm <code>multiply</code> sẽ trả về <code>NaN</code>. Tuy nhiên, điều này bị ngăn chặn bởi dòng thứ 2 trong ví dụ này:</p> + +<pre class="brush: js">function multiply(a, b) { + b = typeof b !== 'undefined' ? b : 1; + + return a*b; +} + +multiply(5); // 5 +</pre> + +<h4 id="Khi_có_default_parameters_sau_ES6">Khi có default parameters (sau ES6)</h4> + +<p>Với <em>default parameters</em>, việc kiểm tra thủ công bên trong body của function không còn cần thiết. Bạn có thể đơn giản chỉ là đặt <code>1</code> vào làm giá trị mặc định cho <code>b</code> ngay tại head của function:</p> + +<pre class="brush: js">function multiply(a, b = 1) { + return a*b; +} + +multiply(5); // 5</pre> + +<p>Để chi tiết hơn, xem <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters">default parameters</a> trong phần tham khảo.</p> + +<h3 id="Rest_parameters">Rest parameters</h3> + +<p>Cú pháp <a href="/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest parameter</a> cho phép chúng ta dùng 1 mảng để đại diện cho số lượng vô hạn các đối số.</p> + +<p>Trong ví dụ sau, hàm <code>multiply</code> sử dụng <em>rest parameters</em> để thu thập các đối số kể từ đối số hứ hai trở về đến hết. Hàm này sau đó sẽ nhân những đối số này với đối số đầu tiên.</p> + +<pre class="brush: js">function multiply(multiplier, ...theArgs) { + return theArgs.map(x => multiplier * x); +} + +var arr = multiply(2, 1, 2, 3); +console.log(arr); // [2, 4, 6]</pre> + +<h2 id="Arrow_functions">Arrow functions</h2> + +<p>Một <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">arrow function expression</a> (trước đây, và hiện tại được biết đến một cách không còn đúng là <strong>fat arrow function</strong>) có một cú pháp ngắn hơn function expressions và không có <code>this</code>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments">arguments</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super">super</a>, or <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target">new.target</a> của chính nó. Các arrow function luôn luôn là nặc danh. Xem "<a href="https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/">ES6 In Depth: Arrow functions</a>".</p> + +<p>Có 2 yếu tố dẫn đến việc giới thiệu arrow function: các <em>function ngắn hơn</em> và sự <em>non-binding</em> của <code>this</code> (lexical <code>this</code>).</p> + +<h3 id="Các_function_ngắn_hơn">Các function ngắn hơn</h3> + +<p>Trong một mẫu function, các function ngắn hơn được khuyến khích. So sánh:</p> + +<pre>var a = [ + 'Hydrogen', + 'Helium', + 'Lithium', + 'Beryllium' +]; + +var a2 = a.map(function(s) { return s.length; }); + +console.log(a2); // logs [8, 6, 7, 9] + +var a3 = a.map(s => s.length); + +console.log(a3); // logs [8, 6, 7, 9]</pre> + +<h3 id="No_separate_this_Lexical_this">No separate <code>this</code> (Lexical <code>this</code>)</h3> + +<p>Trước khi có arrow functions, mọi function mới sẽ tự định nghĩa giá trị <code>this</code> của nó (a new object in the case of a constructor, undefined in <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode">strict mode</a> function calls, the base object if the function is called as an "object method", etc.). Điều này đã được chứng minh là không lý tưởng đối với phong cách lập trình hướng đối tượng.</p> + +<pre class="brush: js">function Person() { + // Constructor của Person() tự định nghĩa `<code>this`</code>. + this.age = 0; + + setInterval(function growUp() { + // Trong nonstrict mode, hàm growUp() định nghĩa `this` + // như là một global object, và global object này khác với `this` + // được định nghĩa bởi Person() constructor. + this.age++; + }, 1000); +} + +var p = new Person();</pre> + +<p>Trong ECMAScript 3/5, vấn đề này được sửa chữa bằng cách gán giá trị bên trong <code>this</code> cho một biến mà biến đó có thể được đóng hoàn toàn.</p> + +<pre class="brush: js">function Person() { + var self = this; // Some choose `that` instead of `self`. + // Choose one and be consistent. + self.age = 0; + + setInterval(function growUp() { + // The callback refers to the `self` variable of which + // the value is the expected object. + self.age++; + }, 1000); +} + +var p = new Person(); +</pre> + +<h2 id="Predefined_functions">Predefined functions</h2> + +<p>JavaScript has several top-level, built-in functions:</p> + +<dl> + <dt>{{jsxref("Global_Objects/eval", "eval()")}}</dt> + <dd> + <p>The <code><strong>eval()</strong></code> method evaluates JavaScript code represented as a string.</p> + </dd> + <dt>{{jsxref("Global_Objects/uneval", "uneval()")}} {{non-standard_inline}}</dt> + <dd> + <p>The <code><strong>uneval()</strong></code> method creates a string representation of the source code of an {{jsxref("Object")}}.</p> + </dd> + <dt>{{jsxref("Global_Objects/isFinite", "isFinite()")}}</dt> + <dd> + <p>The global <code><strong>isFinite()</strong></code> function determines whether the passed value is a finite number. If needed, the parameter is first converted to a number.</p> + </dd> + <dt>{{jsxref("Global_Objects/isNaN", "isNaN()")}}</dt> + <dd> + <p>The <code><strong>isNaN()</strong></code> function determines whether a value is {{jsxref("Global_Objects/NaN", "NaN")}} or not. Note: coercion inside the <code>isNaN</code> function has <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN#Description">interesting</a> rules; you may alternatively want to use {{jsxref("Number.isNaN()")}}, as defined in ECMAScript 6, or you can use <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/typeof">typeof</a></code> to determine if the value is Not-A-Number.</p> + </dd> + <dt>{{jsxref("Global_Objects/parseFloat", "parseFloat()")}}</dt> + <dd> + <p>The <code><strong>parseFloat()</strong></code> function parses a string argument and returns a floating point number.</p> + </dd> + <dt>{{jsxref("Global_Objects/parseInt", "parseInt()")}}</dt> + <dd> + <p>The <code><strong>parseInt()</strong></code> function parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems).</p> + </dd> + <dt>{{jsxref("Global_Objects/decodeURI", "decodeURI()")}}</dt> + <dd> + <p>The <code><strong>decodeURI()</strong></code> function decodes a Uniform Resource Identifier (URI) previously created by {{jsxref("Global_Objects/encodeURI", "encodeURI")}} or by a similar routine.</p> + </dd> + <dt>{{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent()")}}</dt> + <dd> + <p>The <code><strong>decodeURIComponent()</strong></code> method decodes a Uniform Resource Identifier (URI) component previously created by {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} or by a similar routine.</p> + </dd> + <dt>{{jsxref("Global_Objects/encodeURI", "encodeURI()")}}</dt> + <dd> + <p>The <code><strong>encodeURI()</strong></code> method encodes a Uniform Resource Identifier (URI) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two "surrogate" characters).</p> + </dd> + <dt>{{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent()")}}</dt> + <dd> + <p>The <code><strong>encodeURIComponent()</strong></code> method encodes a Uniform Resource Identifier (URI) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two "surrogate" characters).</p> + </dd> + <dt>{{jsxref("Global_Objects/escape", "escape()")}} {{deprecated_inline}}</dt> + <dd> + <p>The deprecated <code><strong>escape()</strong></code> method computes a new string in which certain characters have been replaced by a hexadecimal escape sequence. Use {{jsxref("Global_Objects/encodeURI", "encodeURI")}} or {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} instead.</p> + </dd> + <dt>{{jsxref("Global_Objects/unescape", "unescape()")}} {{deprecated_inline}}</dt> + <dd> + <p>The deprecated <code><strong>unescape()</strong></code> method computes a new string in which hexadecimal escape sequences are replaced with the character that it represents. The escape sequences might be introduced by a function like {{jsxref("Global_Objects/escape", "escape")}}. Because <code>unescape()</code> is deprecated, use {{jsxref("Global_Objects/decodeURI", "decodeURI()")}} or {{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent")}} instead.</p> + </dd> +</dl> + +<p>{{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}</p> diff --git a/files/vi/web/javascript/guide/gioi-thieu/index.html b/files/vi/web/javascript/guide/gioi-thieu/index.html new file mode 100644 index 0000000000..f8fddcf666 --- /dev/null +++ b/files/vi/web/javascript/guide/gioi-thieu/index.html @@ -0,0 +1,137 @@ +--- +title: Giới thiệu +slug: Web/JavaScript/Guide/Gioi-thieu +tags: + - Guide + - JavaScript +translation_of: Web/JavaScript/Guide/Introduction +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}</div> + +<p class="summary">Trong phần này: giới thiệu về JavaScript và thảo luận về một số khái niệm cơ bản của JavaScript.</p> + +<h2 id="Kiến_thức_nền_tảng_cần_có">Kiến thức nền tảng cần có</h2> + +<p>Để đến với JavaScript, chúng tôi giả sử rằng bạn đã có một số hiểu biết nền tảng:</p> + +<ul> + <li>Có hiểu biết chung về Internet và World Wide Web ({{Glossary("WWW")}}).</li> + <li>Đã biết và có thể làm việc được với HyperText Markup Language ({{Glossary("HTML")}}).</li> + <li>Có một số kinh nghiệm về lập trình. Nếu bạn là một người mới tìm hiểu về lập trình, bạn nên đi theo những hướng dẫn có tại trang thông tin chính về <a href="/en-US/docs/Web/JavaScript" title="/en-US/docs/">JavaScript.</a></li> +</ul> + +<h2 id="Bạn_có_thể_tìm_thêm_thông_tin_về_JavaScript_ở_đâu">Bạn có thể tìm thêm thông tin về JavaScript ở đâu?</h2> + +<p>Tài liệu về JavaScript tại MDN bao gồm:</p> + +<ul> + <li><a href="/en-US/Learn">Learning the Web</a> cung cấp cho người mới bắt đầu thông tin và giới thiệu về các khái niệm cơ bản của lập trình và Internet.</li> + <li><a href="/en-US/docs/Web/JavaScript/Guide" title="en/Core_JavaScript_1.5_Guide">JavaScript Guide</a> (là phần hướng dẫn này) cung cấp một cái nhìn tổng quát về ngôn ngữ JavaScript và các Object của nó.</li> + <li><a href="/en-US/docs/Web/JavaScript/Reference" title="en/JavaScript/Reference">JavaScript Reference</a> cung cấp tài liệu chi tiết về JavaScript.</li> +</ul> + +<p>Nếu bạn mới tìm hiểu JavaScript, hãy bắt đầu bằng cách đọc các bài viết tại <a href="/en-US/Learn">learning area</a> và <a href="/en-US/docs/Web/JavaScript/Guide" title="en/Core_JavaScript_1.5_Guide">JavaScript Guide</a>. Một khi bạn đã nắm vững các nền tảng cơ bản, bạn có thể sử dụng <a href="/en-US/docs/Web/JavaScript/Reference" title="en/JavaScript/Reference">JavaScript Reference</a> để lấy những thông tin chi tiết của từng object và các câu lệnh (statements).</p> + +<h2 id="JavaScript_là_gì">JavaScript là gì?</h2> + +<p>JavaScript là một ngôn ngữ lập trình đa nền tảng (<strong>cross-platform)</strong>, ngôn ngữ lập trình kịch bản, hướng đối tượng. JavaScript là một ngôn ngữ nhỏ và nhẹ (small and lightweight). Khi nằm bên trong một môi trường (host environment), JavaScript có thể kết nối tới các object của môi trường đó và cung cấp các cách quản lý chúng (object).</p> + +<p>JavaScript chứa các thư viện tiêu chuẩn cho các object, ví dụ như: <code>Array</code>, <code>Date</code>, và <code>Math</code>, và các yếu tố cốt lõi của ngôn ngữ lập trình như: toán tử (operators), cấu trúc điều khiển (control structures), và câu lệnh. JavaScript có thể được mở rộng cho nhiều mục đích bằng việc bổ sung thêm các object; ví dụ:</p> + +<ul> + <li><em>Client-side JavaScript</em> - JavaScript phía máy khách, JavaScript được mở rộng bằng cách cung cấp các object để quản lý trình duyệt và Document Object Model (DOM) của nó. Ví dụ, phần mở rộng phía máy khách cho phép một ứng dụng tác động tới các yếu tố trên một trang HTML và phản hồi giống các tác động của người dùng như click chuột, nhập form, và chuyển trang.</li> + <li><em>Server-side JavaScript </em>- JavaScript phía Server, JavaScript được mở rộng bằng cách cung cấp thêm các đối tượng cần thiết để để chạy JavaScript trên máy chủ. Ví dụ, phần mở rộng phía server này cho phép ứng dụng kết nối với cơ sở dữ liệu (database), cung cấp thông tin một cách liên tục từ một yêu cầu tới phần khác của ứng dụng, hoặc thực hiện thao tác với các tập tin trên máy chủ.</li> +</ul> + +<h2 id="JavaScript_and_Java" name="JavaScript_and_Java">JavaScript và Java</h2> + +<p>JavaScript và Java thì giống nhau ở những cái này nhưng lại khác nhau ở cái khác. Ngôn ngữ JavaScript có lẽ giống giống với ngôn ngữ Java nhưng JavaScript không có khai báo static cũng như không có "tính mạnh về kiểu" (strong type checking) như Java. Cú pháp (syntax) lập trình, đặt tên công thức và xây dựng điều khiển lưu lượng (control-flow) cơ bản của JavaScript phần lớn dựa theo ngôn ngữ lập trình Java, đó cũng là lý do tại sao JavaScript được đổi tên từ LiveScript thành JavaScript.</p> + +<p>Ngược lại với hệ thống thời gian biên dịch (compile-time) Java của các lớp được xây dựng bởi các khai báo, JavaScript hỗ trợ nền tảng hệ thống thời gian chạy<span id="result_box" lang="vi"><span class="hps"> dựa</span> <span class="hps">trên</span> <span class="hps">một</span> <span class="hps">số lượng nhỏ các</span> <span class="hps">loại</span> <span class="hps">dữ liệu</span> <span class="hps">đại diện cho</span> <span class="hps">số, boolean và dữ liệu các chuỗi. JavaScript có một mô hình ít phổ biến hơn là mô hình đối tượng</span> <span class="hps">dựa trên nguyên mẫu</span> <span class="hps">(</span></span>prototype-based) <span lang="vi"><span class="hps">thay vì</span> <span class="hps">các</span> <span class="hps">mô hình đối tượng</span> <span class="hps">dựa trên lớp (</span></span>class-based)<span lang="vi">. </span><span id="result_box" lang="vi"><span class="hps">Các</span> <span class="hps">mô hình</span> <span class="hps">dựa trên nguyên mẫu</span> <span class="hps">cung cấp</span> khả năng <span class="hps">thừa kế</span> <span class="hps">năng động</span><span>;</span> <span class="hps">nghĩa là,</span> <span class="hps">những gì được</span><span class="hps"> kế thừa có thể</span> <span class="hps">khác nhau</span> <span class="hps">cho các đối tượng</span> <span class="hps">khác nhau.</span> <span class="hps">JavaScript</span> <span class="hps">cũng hỗ trợ</span> <span class="hps">các phương thức (function)</span> không khai báo bất cứ gì ở trỏng<span class="hps">.</span> <span class="hps">Phương thức có thể</span> <span class="hps">là một trong các thuộc tính (property) của</span> <span class="hps">các đối tượng,</span> <span class="hps">t</span><span>hực thi như là một phương thức đã được định kiểu (</span></span>loosely typed methods).</p> + +<p>JavaScript là một ngôn ngữ rất tự do so với Java. Bạn có thể không cần khai báo tất cả biến (variable), lớp (class) và cả phương thức (method). Bạn không cần quan tâm cho dù phương thức đó là public, private hoặc protected, và bạn không cần phải implement interfaces. Biến, tham số (parameters), và kiểu trả về của phương thức (function return) cũng không cần phải rõ ràng.</p> + +<p>Java is a class-based programming language designed for fast execution and type safety. Type safety means, for instance, that you can't cast a Java integer into an object reference or access private memory by corrupting Java bytecodes. Java's class-based model means that programs consist exclusively of classes and their methods. Java's class inheritance and strong typing generally require tightly coupled object hierarchies. These requirements make Java programming more complex than JavaScript programming.</p> + +<p>In contrast, JavaScript descends in spirit from a line of smaller, dynamically typed languages such as HyperTalk and dBASE. These scripting languages offer programming tools to a much wider audience because of their easier syntax, specialized built-in functionality, and minimal requirements for object creation.</p> + +<table class="standard-table"> + <caption>JavaScript so sánh với Java</caption> + <thead> + <tr> + <th scope="col">JavaScript</th> + <th scope="col">Java</th> + </tr> + </thead> + <tbody> + <tr> + <td>Hướng đối tượng (Object-oriented). Không phân biệt giữa kiểu (type) của các đối tượng (object). Tính kế thừa thông qua cơ chế nguyên mẫu (prototype), và các thuộc tính (property) cũng như phương thức có thể thêm vào bất cứ đối tượng nào một cách năng động.</td> + <td>Class-based (nền tảng lớp.).Đối tượng được thành các lớp với tất cả kế thừa thông qua hệ thống phân cấp lớp. Các lớp không thể thêm vào các thuộc tính và phương thức mới một cách năng động.</td> + </tr> + <tr> + <td>Không khai báo kiểu dữ liệu cho biến (dynamic typing).</td> + <td>Phải khai báo kiểu dữ liệu cho biến (static typing).</td> + </tr> + <tr> + <td>Không thể tự động ghi vào ổ đĩa cứng.</td> + <td>Có thể tự động ghi dữ liệu vào đĩa cứng.</td> + </tr> + </tbody> +</table> + +<p>Thêm thông tin về sự khác nhau giữa JavaScript và Java, xem chương: <a href="/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model" title="JavaScript/Guide/Details of the Object Model">Details of the object model</a>.</p> + +<h2 id="JavaScript_and_the_ECMAScript_Specification" name="JavaScript_and_the_ECMAScript_Specification">JavaScript và tiêu chuẩn ECMAScript</h2> + +<p>JavaScript được tiêu chuẩn hóa tại <a class="external" href="http://www.ecma-international.org/">Ecma International</a> — the European association for standardizing information and communication systems, Liên kết Châu Âu cho các tiêu chuẩn hóa hệ thống thông tin và truyền thông (ECMA trước đây là viết tắt cho the European Computer Manufacturers Association) cung cấp một tiêu chuẩn hóa, nền tảng ngôn ngữ lập trình mở quốc tế lên JavaScript. Phiên bản đã tiêu chuẩn hóa của JavaScript được gọi là ECMAScript, làm việc giống với cái cách mà tất cả ứng dụng đã được hỗ trợ theo tiêu chuẩn. Các công ty có thể sử dụng tiêu chuẩn ngôn ngữ mở (open standard language) để phát triển các implementation của JavaScript riêng cho họ. Tiêu chuẩn ECMAScript là tài liệu nằm trong tiêu chuẩn ECMA-262 (ECMA-262 specification) . Xem <a href="/en-US/docs/Web/JavaScript/New_in_JavaScript">New in JavaScript </a>để biết thêm về sự khác nhau giữa các phiên bản JavaScript cũng như sự khác nhau của phiên bản tiêu chuẩn ECMAScript (ECMAScript specification editions).</p> + +<p>Tiêu chuẩn ECMA-262 cũng đã được phê duyệt bởi <a class="external" href="http://www.iso.ch/">ISO</a> (International Organization for Standardization) tại ISO-16262. Bạn cũng có thể tìm tiêu chuẩn trên <a class="external" href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">the Ecma International website</a>. Tiêu chuẩn ECMAScript không bao gồm các mô tả cho Document Object Model (DOM), nó được tiêu chuẩn hóa bởi <a class="external" href="http://www.w3.org/">World Wide Web Consortium (W3C)</a>. DOM định nghĩa cách mà các đối tượng trong HTML tiếp xúc với các đoạn script của bạn. <span id="result_box" lang="vi"><span class="hps">Để có được một</span> <span class="hps">cảm nhận tốt hơn</span> <span class="hps">về các công nghệ</span> <span class="hps">khác nhau được</span> <span class="hps">sử dụng khi</span> <span class="hps">lập trình với</span> <span class="hps">JavaScript</span><span>, hãy tham khảo</span> <span class="hps">bài viết</span> </span><a href="/en-US/docs/Web/JavaScript/JavaScript_technologies_overview">tổng quan về công nghệ JavaScript</a>.</p> + +<h3 id="JavaScript_Documentation_versus_the_ECMAScript_Specification" name="JavaScript_Documentation_versus_the_ECMAScript_Specification">Tài liệu JavaScript và tiêu chuẩn ECMAScript</h3> + +<p>Tiêu chuẩn ECMAScript là một tập hợp yêu cầu các việc cần thực hiện khi triển khai ECMAScript; nó rất là hữu ích nếu bạn muốn tạo ra một trình biên dịch tiêu chuẩn các tính năng của ngôn ngữ trong ECMAScript implementation hoặc bộ máy biên dịch của bạn (giống như SpiderMonkey của Firefox, hoặc v8 của Chrome).</p> + +<p>Tài liệu ECMAScript được tạo ra không dự định hỗ trợ các lập trình viên script; sử dụng tài liệu JavaScript để lấy thông tin cho việc viết scripts của bạn.</p> + +<p>Tiêu chuẩn ECMAScript sử dụng các thuật ngữ và cú pháp có thể các lập trình viên JavaScript chưa được làm quen. Mặc dù sự mô tả của ngôn ngữ có lẽ khác nhau trong ECMAScript, nhưng bản thân ngôn ngữ vẫn giữ nguyên, không thay đổi. JavaScript hỗ trợ tất cả chức năng được nêu trong tiêu chuẩn ECMAScript.</p> + +<p>Tài liệu JavaScript mô tả các khía cạnh của ngôn ngữ lập trình JavaScript, thích hợp cho các lập trình viên JavaScript sử dụng.</p> + +<h2 id="Bắt_đầu_với_JavaScript">Bắt đầu với JavaScript</h2> + +<p>Bắt đầu với JavaScript rất đơn giản: tất cả những gì bạn cần là một trình duyệt Web hiện đại. Trong các bài hướng dẫn có kèm theo một số tính năng JavaScript, mà nó chỉ chạy được ở các phiên bản trình duyệt mới nhất của Firefox, hoặc... cách tốt nhất là sử dụng một số phiên bản trình duyệt gần đây nhất của Firefox..</p> + +<p>Có 2 công cụ được xây dựng trong Firefox, nó rất hữu ích để chạy các 'thí nghiệm' với JavaScript, đó là: <strong>Web Console</strong> và <strong>Scratchpad</strong>.</p> + +<h3 id="Web_Console">Web Console</h3> + +<p><a href="/en-US/docs/Tools/Web_Console">Web Console</a> cho phép bạn thấy thông tin về trang Web đang chạy, và kèm theo một <a href="/en-US/docs/Tools/Web_Console#The_command_line_interpreter">command line</a>, với nó bạn có thể sử dụng để chạy một đoạn lệnh JavaScript trên trang Web hiện tại.</p> + +<p>Mở Web Console bằng cách chọn "Web Console" từ menu "Web Developer" (Ctrl + Shift + I), "Web Developer" nằm trong Menu chính của Firefox, nó có hình cờ lê, tên: Developer (nếu vẫn không thấy nó, bạn có thể mở menu và nhấn Customize để kéo nó ra ngoài). Sau khi mở lên, nó sẽ là 1 bảng hiển thị nằm phía dưới của cửa sổ trình duyệt. Có 1 ô nhập chạy dài dưới cùng của cửa sổ Web Console (khoanh vùng màu đỏ trong mình), nó chính là command line, với nó bạn có thể nhập vào đoạn JavaScript mà bạu muốn thực thi, và sau khi Enter thì trình duyệt sẽ chạy và trả về kết quả lên bảng Web Console nằm trên nó:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/7363/web-console-commandline.png" style="display: block; margin-left: auto; margin-right: auto;"></p> + +<h3 id="Scratchpad">Scratchpad</h3> + +<p>Web Console có thể rất hiệu quả cho việc chạy đơn lẻ từng dòng lệnh của JavaScript, bạn cũng có thể chạy những đoạn lệnh nhiều dòng với nó (Ctrl + Enter)... Nhưng có vẻ nó không được tiện lợi cho lắm! Bạn không thể lưu lại code khi sử dụng Web Console. Với các 'thí nghiệm' dài và phức tạp thì <a href="/en-US/docs/Tools/Scratchpad">Scratchpad</a> là một công cụ hiệu quả.</p> + +<p>Để mở Scratchpad, chọn "Scratchpad" từ menu "Web Developer" (Ctrl + Shift + I), "Web Developer" nằm trong Menu chính của Firefox, nó có hình cờ lê, tên: Developer (nếu vẫn không thấy nó, bạn có thể mở menu và nhấn Customize để kéo nó ra ngoài). Nó sẽ mở lên trong một cửa sổ window riêng với trình duyệt và là một trình soạn thảo mà bạn có thể sử dụng để viết và chạy JavaScript trong trình duyệt. Bạn cũng có thế lưu lại hoặc mở lên các đoạn script đó lên từ ổ đĩa.</p> + +<p>Nếu bạn chọn "Inspect", đoạn code trong cửa sổ nãy sẽ chạy trong trình duyệt và xuất kết quả trở về bảng dưới dạng comment:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/7365/scratchpad.png" style="display: block; margin-left: auto; margin-right: auto;"></p> + +<h3 id="Hello_world">Hello world</h3> + +<p>Bắt đầu với JavaScript, mở Web Console hoặc Scarthpad và viết code JavaScript hiển thị "Hello world" đầu tiên của bạn:</p> + +<pre class="brush: js">function greetMe(user) { + return "Hi " + user; +} + +greetMe("Alice"); // "Hi Alice" +</pre> + +<p>Trong trang tiếp theo, chúng tôi sẽ giới thiệu cho bạn về cú pháp và các đặc tính của ngôn ngữ JavaScript, với nó, bạn sẽ có thể viết các ứng dụng phức tạp.</p> + +<p>{{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}</p> diff --git a/files/vi/web/javascript/guide/index.html b/files/vi/web/javascript/guide/index.html new file mode 100644 index 0000000000..d81ff019a4 --- /dev/null +++ b/files/vi/web/javascript/guide/index.html @@ -0,0 +1,124 @@ +--- +title: JavaScript Guide +slug: Web/JavaScript/Guide +tags: + - Hướng dẫn + - JavaScript +translation_of: Web/JavaScript/Guide +--- +<p>{{jsSidebar("JavaScript Guide")}}</p> + +<div class="summary"> +<p><span class="seoSummary">Tài liệu về JavaScript cung cấp cho bạn cách sử dụng <a href="/vi/docs/Web/JavaScript">JavaScript</a> và đưa ra cái nhìn tổng quan về ngôn ngữ này. Nếu muốn bắt đầu ngay với Javascript hay lập trình nói chung, hãy tham khảo các bài viết tại <a href="/vi/Learn">learning area</a>. Nếu cần thông tin đầy đủ về tính năng của ngôn ngữ này, hãy tham khảo <a href="/vi/docs/Web/JavaScript/Reference">JavaScript reference</a>.</span></p> +</div> + +<ul class="card-grid"> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Introduction">Giới thiệu</a></span> + + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Introduction#Where_to_find_JavaScript_information">Về hướng dẫn này</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Introduction#What_is_JavaScript">Về Javascript</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Introduction#JavaScript_and_Java">JavaScript và Java</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Introduction#JavaScript_and_the_ECMAScript_Specification">ECMAScript</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Introduction#Getting_started_with_JavaScript">Các công cụ</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Introduction#Hello_world">Hello World</a></p> + </li> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Grammar_and_types">Ngữ pháp và các kiểu dữ liệu</a></span> + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Basics">Cú pháp cơ bản & bình luận</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Declarations">Khai báo</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Variable_scope">Phạm vi biến</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Variable_hoisting">Variable hoisting</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Data_structures_and_types">Cấu trúc dữ liệu và các kiểu</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals">Literals</a></p> + </li> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Control_flow_and_error_handling">Luồng điều khiển và xử lý lỗi</a></span> + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#if...else_statement">Xử lý trường hợp <code>if...else</code></a><br> + <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#switch_statement">switch</a></code><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Exception_handling_statements"><code>try</code>/<code>catch</code>/<code>throw</code></a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Utilizing_Error_objects">Error objects</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Promises">Promises</a></p> + </li> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Loops_and_iteration">Các vòng lặp</a></span> + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#for_statement">for</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#while_statement">while</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#do...while_statement">do...while</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#break_statement">break</a>/<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#continue_statement">continue</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#for...in_statement">for..in</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration#for...of_statement">for..of</a></p> + </li> +</ul> + +<ul class="card-grid"> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Functions">Hàm</a></span> + + <p><a href="/vi/docs/Web/JavaScript/Guide/Functions#Defining_functions">Định nghĩa hàm</a><br> + <a href="/vi/docs/Web/JavaScript/Guide/Functions#Calling_functions">Gọi hàm</a><br> + <a href="/vi/docs/Web/JavaScript/Guide/Functions#Function_scope">Phạm vi hàm</a><br> + <a href="/vi/docs/Web/JavaScript/Guide/Functions#Closures">Closures</a><br> + <a href="/vi/docs/Web/JavaScript/Guide/Functions#Using_the_arguments_object">Đối số & tham số</a><br> + <a href="/vi/docs/Web/JavaScript/Guide/Functions#Arrow_functions">Arrow functions</a></p> + </li> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Expressions_and_Operators">Biểu thức và các toán tử</a></span> + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment_operators">Phép gán và So sánh</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Arithmetic_operators">Các toán tử toán học</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise_operators">Các toán tử Bitwise</a> & <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Logical_operators">logic</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Conditional_(ternary)_operator">Toán tử 3 ngôi</a></p> + </li> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Numbers_and_dates">Numbers and dates</a></span><a href="/vi/docs/Web/JavaScript/Guide/Numbers_and_dates#Numbers"> </a><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_dates#Numbers">Number literals</a> + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_dates#Number_object"><code>Number</code> object</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_dates#Math_object"><code>Math</code> object</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_dates#Date_object"><code>Date</code> object</a></p> + + <p> </p> + </li> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Text_formatting">Text formatting</a></span> + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Text_formatting#String_literals">String literals</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Text_formatting#String_objects">Đối tượng <code>String</code></a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Text_formatting#Multi-line_template_literals">Template literals</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Text_formatting#Internationalization">Internationalization</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">Biểu thức chính quy</a></p> + </li> +</ul> + +<ul class="card-grid"> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Indexed_collections">Indexed collections</a></span> + + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#Array_object">Mảng</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#Typed_Arrays">Mảng được định sẵn kiểu</a></p> + + <p> </p> + </li> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Keyed_collections_and_structured_data">Keyed collections and structured data</a></span> + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_collections#Map_object">Maps</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_collections#WeakMap_object">WeakMaps</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_collections#Set_object">Set</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_collections#WeakSet_object">WeakSets</a><br> + JSON</p> + </li> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Working_with_Objects">Working with objects</a></span> + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Objects_and_properties">Objects và các thuộc tính</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Creating_new_objects">Tạo objects</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_methods">Định nghĩa các phương thức</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters">Getter và setter</a><br> + </p> + </li> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Details_of_the_Object_Model">Details of the object model</a></span> + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#Class-based_vs._prototype-based_languages">Prototype-based OOP</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#Creating_the_hierarchy">Creating object hierarchies</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#Property_inheritance_revisited">Inheritance</a></p> + </li> +</ul> + +<ul class="card-grid"> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Iterators_and_Generators">Iterators and generators</a></span> + + <p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterators">Iterators</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterables">Iterables</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Generators">Generators</a></p> + </li> + <li><span><a href="/vi/docs/Web/JavaScript/Guide/Meta_programming">Meta programming</a></span> + <p><code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Meta_programming#Proxies">Proxy</a></code><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Meta_programming#Handlers_and_traps">Handlers and traps</a><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Meta_programming#Revocable_Proxy">Revocable Proxy</a><br> + <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Meta_programming#Reflection">Reflect</a></code></p> + </li> +</ul> + +<p>{{Next("Web/JavaScript/Guide/Introduction")}}</p> diff --git a/files/vi/web/javascript/guide/iterators_and_generators/index.html b/files/vi/web/javascript/guide/iterators_and_generators/index.html new file mode 100644 index 0000000000..e283bbb21d --- /dev/null +++ b/files/vi/web/javascript/guide/iterators_and_generators/index.html @@ -0,0 +1,187 @@ +--- +title: Iterators and generators +slug: Web/JavaScript/Guide/Iterators_and_Generators +translation_of: Web/JavaScript/Guide/Iterators_and_Generators +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Using_promises", "Web/JavaScript/Guide/Meta_programming")}}</div> + +<p class="summary">Việc xử lý mỗi phần tử trong một tập hợp là thao tác rất phổ biến. JavaScript cung cấp một số cách để duyệt qua một tập hợp, từ đơn giản với lệnh lặp {{jsxref("Statements/for","for")}} đến {{jsxref("Global_Objects/Array/map","map()")}} và {{jsxref("Global_Objects/Array/filter","filter()")}}. Iterators và Generators đem đến khái niệm của iteration vào nhân của ngôn ngữ và cung cấp cách để tùy biến cơ chế của vòng lặp {{jsxref("Statements/for...of","for...of")}}.</p> + +<p>Tham khảo thêm:</p> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Iteration_protocols">Iteration protocols</a></li> + <li>{{jsxref("Statements/for...of","for...of")}}</li> + <li>{{jsxref("Statements/function*","function*")}} and {{jsxref("Generator")}}</li> + <li>{{jsxref("Operators/yield","yield")}} and {{jsxref("Operators/yield*","yield*")}}</li> +</ul> + +<h2 id="Iterators">Iterators</h2> + +<p>Trong JavaScript một <strong>iterator</strong> là một object mà nó định nghĩa một trình tự và giá trị có thể trả về tiếp theo trước khi kết thúc. Một cách cụ thể hơn một iterator là một object bất kỳ mà nó cài đặt giao thức <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol">Iterator</a> với việc cài đặt phương thức next() mà trả về một object với thuộc tính: <code>value</code>, giá trị kế tiếp in chuỗi giá trị; và <code>done</code>, mà là <code>true</code> nếu giá trị cuối cùng trong chuỗi giá trị đã được sử dụng. Nếu <code>value</code> trả về cùng với thuộc tính <code>done</code>, nó là giá trị trả về bởi lệnh return trong iterator đó.</p> + +<p>Mỗi lần được tạo, một iterator có thể được duyệt tường minh bởi việc gọi lại nhiều lần phương thức <code>next()</code>. Việc duyệt qua iterator được gọi là sử dụng iterator, bởi vì nó chỉ có thể làm một lần. Sau khi giá trị kết thúc được trả về thì lần gọi <code>next()</code> luôn trả về <code>{done: true}</code>.<br> + <br> + Iterator thông dụng nhất trong JavaScript là iterator mãng, mà đơn giản là trả về mỗi giá trị trong associated array theo thứ tự. Trong khi nó thì dễ dàng tưởng tượng rằng tất cả iterators được biểu diễn như mãng, điều này không đúng. Mảng phải được cấp phát toàn bộ, nhưng iterators được sử dụng chỉ khi cần thiết và vì vậy có thể biểu diễn một chuỗi không có giới hạn kích thước, như là một dãy các số nguyên từ 0 cho đến vô cực.<br> + <br> + Sau đây là một ví dụ minh họa cho điều đó. Bạn có thể tạo ra một iterator khoảng giá trị đơn giản mà nó định nghĩa một dãy các số nguyên từ <code>start</code> (đã bao gồm) đến <code>end</code> (không bao gồm) với bước nhảy <code>step</code>. Giá trị trả về cuối cùng là kích thước của dãy giá trị mà nó đã tạo, ghi nhận trong biến iterationCount.</p> + +<pre class="brush: js">function makeRangeIterator(start = 0, end = Infinity, step = 1) { + let nextIndex = start; + let iterationCount = 0; + + const rangeIterator = { + next: function() { + let result; + if (nextIndex <= end) { + result = { value: nextIndex, done: false } + nextIndex += step; + iterationCount++; + return result; + } + return { value: iterationCount, done: true } + } + }; + return rangeIterator; +}</pre> + +<p>Việc sử dụng iterator được minh họa như trong đoạn mã sau:</p> + +<pre class="brush: js">let it = makeRangeIterator(1, 10, 2); + +let result = it.next(); +while (!result.done) { + console.log(result.value); // 1 3 5 7 9 + result = it.next(); +} + +console.log("Iterated over sequence of size: ", result.value); // 5 + +</pre> + +<div class="note"> +<p>Bạn không biết chắc một đối tượng cụ thể là một iterator hay không. Nếu bạn cần làm điều này, thì hãy dùng <a href="#Iterables">Iterables</a>.</p> +</div> + +<h2 id="Generator_functions">Generator functions</h2> + +<p>Iterator tùy biến là công cụ hữu ích, tuy nhiên việc tạo chúng đòi hỏi sự cẩn thận vì chúng ta cần phải tự quản lý trạng thái của chúng. Hàm Generator cung cấp một cách thức tốt hơn để thay thế việc đó: chúng cho phép bạn định nghĩa giải thuật duyệt bằng cách viết một hàm đơn mà sự thực thi của nó không diễn ra liên tục. Hàm Generator được viết bằng cách sử dụng cú pháp {{jsxref("Statements/function*","function*")}}. Khi gọi lần đầu, hàm generator không thực thi bất kỳ đoạn mã nào bên trong, thay vào đó nó trả về kiểu của iterator được gọi là generator. Khi một giá trị được dùng để trả về bởi lời gọi phương thức <strong>next</strong>() của generator, hàm generator thực thi cho đến khi nó bắt gặp từ khóa <strong>yield</strong>.</p> + +<p>Hàm có thể được gọi bao nhiêu lần cũng được và nó trả về một generator cho mỗi lần gọi, tuy nhiên generator có thể chỉ được duyệt một lần.<br> + <br> + Chúng ta có thể điều chỉnh ví dụ trên. Chúng ta thấy đoạn mã sau cũng thực thi cùng chức năng, nhưng nó dễ viết và dễ đọc hơn.</p> + +<pre class="brush: js">function* makeRangeIterator(start = 0, end = Infinity, step = 1) { + let iterationCount = 0; + for (let i = start; i < end; i += step) { + iterationCount++; + yield i; + } + return iterationCount; +}</pre> + +<h2 id="Iterables">Iterables</h2> + +<p>Một đối tượng là khả duyệt nếu nó định nghĩa cơ chế duyệt của nó, chẳng hạn như giá trị gì được duyệt qua trong hàm dựng {{jsxref("Statements/for...of", "for...of")}}. Một vài kiểu dựng sẳn, như {{jsxref("Array")}} hoặc {{jsxref("Map")}}, có cơ chế duyệt mặc định, trong khi những kiểu khác (như là {{jsxref("Object")}}) thì không có.</p> + +<p>Để có thể khả duyệt, một object phải cái đặt phương thức của <strong>@@iterator</strong>, nghĩa là object (hoặc đối tượng cha trong chuỗi <a href="/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain">prototype</a>) phải có một thuộc tính {{jsxref("Symbol.iterator")}}.<br> + It may be possible to iterate over an iterable more than once, or only once. It is up to the programmer to know which is the case. Iterables which can iterate only once (e.g. Generators) customarily return <strong>this</strong> from their <strong>@@iterator</strong> method, where those which can be iterated many times must return a new iterator on each invocation of <strong>@@iterator</strong>.<br> + Bạn có thể cho phép duyệt qua nhiều lần, hoặc chỉ một lần. Điều này phụ thuộc vào theo yêu cầu của mỗi ứng dụng. Đối tượng khả duyệt mà chỉ duyệt qua một lần (ví dụ Generators) đơn giản là nó chỉ trả về <strong>this</strong> từ phương thức <strong>@@iterator</strong>, trong khi để khả duyệt nhiều lần bạn phải trả về một iterator mới cho mỗi lần gọi <strong>@@iterator</strong>.</p> + +<h3 id="Tự_định_nghĩa_đối_tượng_khả_duyệt">Tự định nghĩa đối tượng khả duyệt</h3> + +<p>Chúng ta có thể tự tạo đối tượng khả duyệt như sau:</p> + +<pre class="brush: js">var myIterable = { + *[Symbol.iterator]() { + yield 1; + yield 2; + yield 3; + } +} + +for (let value of myIterable) { + console.log(value); +} +// 1 +// 2 +// 3 + +or + +[...myIterable]; // [1, 2, 3] +</pre> + +<h3 id="Những_iterable_tạo_sẵn">Những iterable tạo sẵn</h3> + +<p>{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}} and {{jsxref("Set")}} là những iterable đã được tạo sẵn, bởi vì đối tượng prototype của chúng đã có phương thức {{jsxref("Symbol.iterator")}}.</p> + +<h3 id="Cú_pháp_đòi_hỏi_đối_tượng_khả_duyệt">Cú pháp đòi hỏi đối tượng khả duyệt</h3> + +<p>Một vài câu lệnh và biểu thức đòi hỏi toán hạng hoặc đối số phải là đối tượng khả duyệt, ví dụ lệnh lặp {{jsxref("Statements/for...of","for-of")}}, {{jsxref("Operators/yield*","yield*")}}</p> + +<pre class="brush: js">for (let value of ['a', 'b', 'c']) { + console.log(value); +} +// "a" +// "b" +// "c" + +[...'abc']; // ["a", "b", "c"] + +function* gen() { + yield* ['a', 'b', 'c']; +} + +gen().next(); // { value: "a", done: false } + +[a, b, c] = new Set(['a', 'b', 'c']); +a; // "a" + +</pre> + +<h2 id="Generator_Cao_Cấp">Generator Cao Cấp</h2> + +<p>Generator tính toán giá trị trả ra tùy biến theo nhu cầu, nó cho phép biển diễn chuỗi giá trị một cách hiệu quả mà tốn kém để tính toán, hoặc thậm chí cho phép chuỗi giá trị vô tận như đã minh họa ở trên.<br> + </p> + +<p>The {{jsxref("Global_Objects/Generator/next","next()")}} method also accepts a value which can be used to modify the internal state of the generator. A value passed to <code>next()</code> will be treated as the result of the last <code>yield</code> expression that paused the generator.<br> + Phương thức {{jsxref("Global_Objects/Generator/next","next()")}} cũng chấp nhận một đối số mà được sử dụng để thay đổi trạng thái bên trong của generator. Một giá trị được truyền vào <code>next()</code> sẽ được dùng như kết quả của biểu thức <code>yield</code> cuối cùng khi tạm dừng generator.</p> + +<p>Here is the fibonacci generator using <code>next(x)</code> to restart the sequence:</p> + +<pre class="brush: js">function* fibonacci() { + var fn1 = 0; + var fn2 = 1; + while (true) { + var current = fn1; + fn1 = fn2; + fn2 = current + fn1; + var reset = yield current; + if (reset) { + fn1 = 0; + fn2 = 1; + } + } +} + +var sequence = fibonacci(); +console.log(sequence.next().value); // 0 +console.log(sequence.next().value); // 1 +console.log(sequence.next().value); // 1 +console.log(sequence.next().value); // 2 +console.log(sequence.next().value); // 3 +console.log(sequence.next().value); // 5 +console.log(sequence.next().value); // 8 +console.log(sequence.next(true).value); // 0 +console.log(sequence.next().value); // 1 +console.log(sequence.next().value); // 1 +console.log(sequence.next().value); // 2</pre> + +<p>Bạn có thể ép một generator phát sinh lỗi bằng cách gọi phương thức {{jsxref("Global_Objects/Generator/throw","throw()")}} của generator và chỉ định giá trị lỗi mà nó cần phát sinh. Lỗi này sẽ được phát sinh từ ngữ cảnh hiện tại của generator, tạo điểm mà <code>yield</code> đang tam dừng, thay vì lệnh <code>throw <em>value</em></code> như cách thông thường.</p> + +<p>Nếu lỗi không được bắt từ bên trong generator, nó sẽ được đẩy lên cấp cao hơn thông qua lời gọi hàm <code>throw()</code>, khi đó lời gọi tiếp theo tới <code>next()</code> sẽ trả về <code>done</code> với giá trị <code>true</code>.</p> + +<p>Generator có một phương thức {{jsxref("Global_Objects/Generator/return","return(value)")}} mà giá trị được truyền vào và kết thúc chính nó.</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Using_promises", "Web/JavaScript/Guide/Meta_programming")}}</p> diff --git a/files/vi/web/javascript/guide/keyed_collections/index.html b/files/vi/web/javascript/guide/keyed_collections/index.html new file mode 100644 index 0000000000..491efcf1da --- /dev/null +++ b/files/vi/web/javascript/guide/keyed_collections/index.html @@ -0,0 +1,153 @@ +--- +title: Keyed collections +slug: Web/JavaScript/Guide/Keyed_collections +translation_of: Web/JavaScript/Guide/Keyed_collections +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}</div> + +<p class="summary">Chương này sẽ giới thiệu về bộ sưu tập dữ liệu được sắp xếp theo key; <code>Map</code> và <code>Set</code> objects chứa các phần tử có thể được lặp lại theo thứ tự được thêm vào.</p> + +<h2 id="Maps">Maps</h2> + +<h3 id="Map_object">Map object</h3> + +<p>ECMAScript 2015 giới thiệu một cấu trúc dữ liệu mới để ánh xạ giá trị thành giá trị. Một đối tượng {{jsxref("Map")}} là một ánh xạ đơn giản key/value và có thể lặp lại các phần tử theo thứ tự thêm vào.</p> + +<p>Đoạn code bên dưới sẽ thể hiện các thao tác cơ bản với <code>Map</code>. Xem thêm {{jsxref("Map")}} để có thêm nhiều ví dụ và toàn bộ API. Bạn có thể sử dụng một vòng lặp {{jsxref("Statements/for...of","for...of")}} để trả về một mảng của <code>[<var>key<var>, <var>value</var>]</var></var></code> trong mỗi lần lặp.</p> + +<pre class="brush: js">let sayings = new Map(); +sayings.set('dog', 'woof'); +sayings.set('cat', 'meow'); +sayings.set('elephant', 'toot'); +sayings.size; // 3 +sayings.get('fox'); // undefined +sayings.has('bird'); // false +sayings.delete('dog'); +sayings.has('dog'); // false + +for (let [key, value] of sayings) { + console.log(key + ' goes ' + value); +} +// "cat goes meow" +// "elephant goes toot" + +sayings.clear(); +sayings.size; // 0 +</pre> + +<h3 id="Object_and_Map_compared">Object and Map compared</h3> + +<p>Thông thường, {{jsxref("Object", "objects", "", 1)}} được sử dụng để ánh xạ string thành value. Objects cũng cho phép bạn đặt key thành values, truy xuất các value, xóa các key, và kiểm tra xe có dữ liệu nào được lưu trữ trong một key. Tuy nhiên <code>Map</code> objects có một vài lợi thế hơn giúp chúng tốt hơn trong việc ánh xạ.</p> + +<ul> + <li>Các key trong một <code>Object</code> là {{jsxref("Global_Objects/String","Strings")}} hoặc {{jsxref("Global_Objects/Symbol","Symbols")}}, trong khi chúng có thể là bất kỳ giá trị nào trong một <code>Map</code>.</li> + <li>Bạn có thể lấy được <code>size</code> của một <code>Map</code> dễ dàng, trong khi bạn sẽ phải xử lý thủ công để lấy được kích thước của một <code>Object</code>.</li> + <li>Vòng lặp của các ánh xạ sẽ theo thứ tự được thêm vào của các phần tử.</li> + <li>Một <code>Object</code> có một prototype, vì thế có các giá trị mặc định của key trong ánh xạ. (Điều này có thể bỏ qua bằng cách sử dụng <code>map = Object.create(null)</code>.)</li> +</ul> + +<p>Ba mẹo dưới đây có thể giúp bạn quyết định khi nào thì sử dụng <code>Map</code> hoặc <code>Object</code>:</p> + +<ul> + <li>Sử dụng các object khi các key không được xác định cho đến khi chạy, và khi tất cả các key có cùng kiểu và tất cả các value cũng cùng kiểu.</li> + <li>Sử dụng các map nếu cần lưu trữ các giá trị có kiểu nguyên thủy làm key vì các object coi mỗi key là một string cho dù nó là một giá trị số, boolean hoặc bất kỳ giá trị có kiểu nguyên thủy nào.</li> + <li>Sử dụng các object khi có logic hoạt động trên các yếu tố riêng lẻ.</li> +</ul> + +<h3 id="WeakMap_object">WeakMap object</h3> + +<p>Đối tượng <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap">{{jsxref("WeakMap")}}</a> là một bộ sưu tập của cặp key/value trong đó các key chỉ là các đối tượng và các value có thể là bất kỳ giá trị nào. Tham chiếu đối tượng trong các key được giữ<em> yếu ớt (weakly)</em>, có nghĩa là chúng là mục tiêu của garbage collection (GC) nếu không có tham chiếu nào khác đến đối tượng nữa. Các <code>WeakMap</code> API giống với các <code>Map</code> API.</p> + +<p>Một điểm khác biệt so với các <code>Map</code> objects là các key của <code>WeakMap</code> không đếm được (tức là không có phương thức nào cung cấp cho bạn danh sách các key). Nếu có, danh sách key sẽ phụ thuộc vào trạng thái của garbage collection, đưa ra tính không xác định.</p> + +<p>Một số thông tin và ví dụ khác, xem tại "Why <em>Weak</em>Map?" trong tài liệu tham khảo {{jsxref("WeakMap")}}.</p> + +<p>Một trường hợp sử dụng các <code>WeakMap</code> objec là lưu trữ dữ liệu riêng tư cho một đối tượng hoặc ấn chi tiết thực hiện. Ví dụ sau đây từ bài đăng trên blog của Nick Fitzgerald's <a href="http://fitzgeraldnick.com/weblog/53/">"Hiding Implementation Details with ECMAScript 6 WeakMaps"</a>. Các dữ liệu và phương thức riêng bên trong object sẽ được lưu trữ trong đối tượng <code><var>privates</var></code>. Tất cả các instance và prototype lộ ra được công khai; mọi thứ khác không thể truy cập từ bên ngoài bởi vì <code><var>privates</var></code> không được xuất từ mô-đun.</p> + +<pre class="brush: js">const privates = new WeakMap(); + +function Public() { + const me = { + // Private data goes here + }; + privates.set(this, me); +} + +Public.prototype.method = function () { + const me = privates.get(this); + // Do stuff with private data in `me`... +}; + +module.exports = Public;</pre> + +<h2 id="Sets">Sets</h2> + +<h3 id="Set_object">Set object</h3> + +<p>Các {{jsxref("Set")}} object là bộ sưu tập các giá trị. Bạn có thể lặp các phần tử theo thứ tự được thêm vào. Một giá trị trong một <code>Set</code> chỉ có thể xuất hiện một lần; nó là duy nhất trong <code>Set</code>.</p> + +<p>Đoạn code dưới đây là các thao tác cơ bản với <code>Set</code>. Xem thêm tại tài liệu tham khảo {{jsxref("Set")}} để có thêm nhiều ví dụ và toàn bộ các API.</p> + +<pre class="brush: js">let mySet = new Set(); +mySet.add(1); +mySet.add('some text'); +mySet.add('foo'); + +mySet.has(1); // true +mySet.delete('foo'); +mySet.size; // 2 + +for (let item of mySet) console.log(item); +// 1 +// "some text" +</pre> + +<h3 id="Converting_between_Array_and_Set">Converting between Array and Set</h3> + +<p>Bạn có thể tạo một {{jsxref("Array")}} từ một Set bằng cách sử dụng {{jsxref("Array.from")}} hoặc <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator">spread operator</a>. Ngoài ra, hàm khởi tạo <code>Set</code> cho phép chuyển đổi một <code>Array</code> theo một hướng khác.</p> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> Hãy nhớ rằng các <code>Set</code> object lưu trữ các <em>giá trị duy nhất</em>—vì thế bất kỳ phần tử nào trùng lặp trong Array sẽ bị loại bỏ khi chuyển đổi!</p> +</div> + +<pre class="brush: js">Array.from(mySet); +[...mySet2]; + +mySet2 = new Set([1, 2, 3, 4]); +</pre> + +<h3 id="Array_and_Set_compared">Array and Set compared</h3> + +<p>Thông thường, một tập hợp các phần tử được lưu trữ trong mảng trong JavaScript trong nhiều tính huống. Tuy nhiên, <code>Set</code> object có một vài điểm lợi thế sau:</p> + +<ul> + <li>Xóa bỏ các phẩn tử trong mảng theo giá trị (<code>arr.splice(arr.indexOf(val), 1)</code>) rất chậm.</li> + <li><code>Set</code> object cho phép bạn xóa bỏ các phần tử theo giá trị của chúng. Trong khi đó một mảng, bạn sẽ phải dùng phương thức <code>splice</code> dựa theo index của phần tử.</li> + <li>Giá trị {{jsxref("NaN")}} không thể được tìm thất với <code>indexOf</code> trong một mảng.</li> + <li>Các <code>Set</code> object lưu trữ các giá trị duy nhất. Bạn không cần phải thao tác thủ công để theo dõi các giá trị bị trùng lặp.</li> +</ul> + +<h3 id="WeakSet_object">WeakSet object</h3> + +<p>Các <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap">{{jsxref("WeakSet")}}</a> object là bộ sưu tập các đối tượng. Một đối tượng trong <code>WeakSet</code> chỉ xuất hiện một lần. Nó là duy nhất trong bộ sưu tập <code>WeakSet</code>, và các đối tượng đó không thể đếm được.</p> + +<p>Những điểm khác biệt chính so với {{jsxref("Set")}} object:</p> + +<ul> + <li>Khác với <code>Sets</code>, <code>WeakSets</code> là <strong>bộ sưu tập các đối tượng</strong> và không phải bất kỳ giá trị của bất kỳ kiểu nào.<strong> </strong></li> + <li><code>WeakSet</code> là <em>yếu ớt (weak)</em>: Tham chiếu tới đối tượng trong bộ sưu tập được tổ chức <em>yếu ớt </em>(weakly). Nếu không có tham chiếu nào khác tới đối tượng được lưu trữ trong <code>WeakSet</code>, chúng có thể bị thu thập bởi garbage collected. Điều này có nghĩa là không có danh sách các đối tượng đang được lưu trữ trong bộ sưu tập. <code>WeakSets</code> không thể đếm được.</li> +</ul> + +<p>Các trường hợp sử dụng các <code>WeakSet</code> object bị hạn chế. Chúng sẽ không rò rỉ bộ nhớ, vì thế nó có thể an toàn khi sử dụng các phần tử DOM làm khóa và đánh dấu chúng cho mục đích theo dõi.</p> + +<h2 id="Key_and_value_equality_of_Map_and_Set">Key and value equality of Map and Set</h2> + +<p>So sánh bằng nhau của các key của các <code>Map</code> object và value của các <code>Set</code> object dựa trên "<a href="https://tc39.github.io/ecma262/#sec-samevaluezero">same-value-zero algorithm</a>":</p> + +<ul> + <li>So sánh bằng nhau làm việc giống như so sánh bằng toán tử <code>===</code>.</li> + <li><code>-0</code> và<code>+0</code> được coi là bằng nhau.</li> + <li>{{jsxref("NaN")}} được coi là bằng chính nó (trái với <code>===</code>).</li> +</ul> + +<p>{{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}</p> diff --git a/files/vi/web/javascript/guide/loops_and_iteration/index.html b/files/vi/web/javascript/guide/loops_and_iteration/index.html new file mode 100644 index 0000000000..5ad3581fba --- /dev/null +++ b/files/vi/web/javascript/guide/loops_and_iteration/index.html @@ -0,0 +1,348 @@ +--- +title: Loops and iteration +slug: Web/JavaScript/Guide/Loops_and_iteration +translation_of: Web/JavaScript/Guide/Loops_and_iteration +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}</div> + +<p class="summary">Vòng lặp giúp thực hiện một hành động nhiều lần một cách nhanh chóng và đơn giản. Chương <a href="/en-US/docs/Web/JavaScript/Guide">Hướng dẫn JavaScript</a> này giới thiệu về các câu lệnh lặp trong JavaScript.</p> + +<p>Hãy tưởng tượng vòng lặp giống như phiên bản vi tính của trò chơi mà bạn bảo một người đi X bước sang một hướng rồi đi Y bước sang một hướng khác; chẳng hạn, ý tưởng trò "Tiến 5 bước về phía Đông" có thể được biểu diễn dưới dạng vòng lặp như sau:</p> + +<pre class="brush: js">var step; +for (let step = 0; step < 5; step++) { + // Chạy 5 lần, với giá trị chạy từ 0 đến 4. + console.log('Walking east one step'); +} +</pre> + +<p>Có nhiều kiểu vòng lặp khác nhau, nhưng tất cả đều thực hiện cùng một việc: làm lại một hành động trong số lần nhất định (số lần đó có thể là 0). Mỗi vòng lặp có các cơ chế khác nhau, tương ứng với đó là sự khác nhau giữa cách xác định điểm bắt đầu và kết thúc của vòng lặp. Tuỳ theo trường hợp xác định mà lựa kiểu vòng lặp cho phù hợp..</p> + +<p>Các lệnh lặp trong JavaScript là:</p> + +<ul> + <li>{{anch("for statement")}}</li> + <li>{{anch("do...while statement")}}</li> + <li>{{anch("while statement")}}</li> + <li>{{anch("labeled statement")}}</li> + <li>{{anch("break statement")}}</li> + <li>{{anch("continue statement")}}</li> + <li>{{anch("for...in statement")}}</li> + <li>{{anch("for...of statement")}}</li> +</ul> + +<h2 id="Lệnh_for">Lệnh <code>for</code></h2> + +<p>Vòng lặp {{jsxref("statements/for","for")}} thực hiện liên tục cho tới khi điều kiện ban đầu trả về false. Vòng <code>for</code> trong JavaScript tương tự như vòng <code>for</code> trong Java hoặc C. Lệnh <code>for</code> có dạng như sau:</p> + +<pre class="syntaxbox">for ([biểu_thức_khởi_tạo]; [điều_kiện]; [biểu_thức_tăng_tiến]) + lệnh +</pre> + +<p>Vòng lặp <code>for</code> thực thi như sau:</p> + +<ol> + <li>Biểu thức khởi tạo (<code>biểu_thức_khởi_tạo</code>), nếu có, được thực thi. Biểu thức này thường khởi tạo một hoặc nhiều biến đếm cho vòng lặp, nhưng cú pháp của nó vẫn có thể tạo ra biểu thức có độ phức tạp. Biểu thức này còn có thể khai báo biến.</li> + <li>Biểu thức điều kiện (<code>điều_kiện</code>) được tính toán. Nếu giá trị của <code>điều_kiện</code> trả về true, các lệnh trong vòng lặp được thực thi. Nếu giá trị của <code>điều_kiện</code> trả về false, vòng lặp <code>for</code> bị dừng lại. Nếu biểu thức <code>điều_kiện</code> bị khuyết (bỏ qua không đặt), điều kiện sẽ được gán giả định là true.</li> + <li><code>lệnh</code> sẽ được thực thi. Để thực thi nhiều lệnh, dùng khối lệnh (<code>{ ... }</code>) để gom nhóm các lệnh này.</li> + <li>Nếu không có lỗi nào xảy ra sau khi thực thi lệnh, biểu thức cập nhật (<code>biểu_thức_tăng_tiến</code>) được thực thi.</li> + <li>Quay lại bước 2.</li> +</ol> + +<h3 id="Ví_dụ"><strong>Ví dụ</strong></h3> + +<p>Hàm dưới đây chứa lệnh <code>for</code> đếm số option được chọn trong danh sách cuộn (phần tử {{HTMLElement("select")}} cho phép chọn nhiều). Lệnh <code>for</code> khai báo biến <code>i</code> và khởi tạo cho nó là 0. Điều kiện kiểm tra <code>i</code> có nhỏ hơn số option mà phần tử <code><select></code> sở hữu hay không, nếu thoả mãn điều kiện, chương trình sẽ chạy vào lệnh <code>if</code>, và tăng <code>i</code> thêm một.</p> + +<pre class="brush: html"><form name="selectForm"> + <p> + <label for="musicTypes">Choose some music types, then click the button below:</label> + <select id="musicTypes" name="musicTypes" multiple="multiple"> + <option selected="selected">R&B</option> + <option>Jazz</option> + <option>Blues</option> + <option>New Age</option> + <option>Classical</option> + <option>Opera</option> + </select> + </p> + <p><input id="btn" type="button" value="How many are selected?" /></p> +</form> + +<script> +function howMany(selectObject) { + var numberSelected = 0; + for (var i = 0; i < selectObject.options.length; i++) { + if (selectObject.options[i].selected) { + numberSelected++; + } + } + return numberSelected; +} + +var btn = document.getElementById('btn'); +btn.addEventListener('click', function() { + alert('Number of options selected: ' + howMany(document.selectForm.musicTypes)); +}); +</script> + +</pre> + +<h2 id="Lệnh_do...while">Lệnh <code>do...while</code></h2> + +<p>Lệnh {{jsxref("statements/do...while", "do...while")}} thực hiện liên tục cho tới khi điều kiện xác định trả về false. Lệnh <code>do...while</code> có dạng như sau:</p> + +<pre class="syntaxbox">do + lệnh +while (điều_kiện); +</pre> + +<p><code>lệnh</code> luôn được thực thi một lần trước khi kiểm tra điều kiện (và rồi cứ thế cho tới khi điều kiện trả về false). Để thực thi nhiều lệnh, dùng khối lệnh (<code>{ ... }</code>) để gom nhóm các câu lệnh. Nếu <code>điều_kiện</code> trả về true, lệnh lại được thực thi một lần nữa. Sau mỗi lần thực thi, chương trình kiểm tra lại điều kiện. Khi điều kiện trả về false, chương trình dừng thực thi vòng lặp và truyền điều khiển xuống lệnh liền sau vòng <code>do...while</code>.</p> + +<h3 id="Ví_dụ_2"><strong>Ví dụ</strong></h3> + +<p>Trong ví dụ sau, lặp <code>do</code> lặp ít nhất một lần và tái duyệt cho tới khi <code>i</code> không nhỏ hơn 5.</p> + +<pre class="brush: js">var i = 0; +do { + i += 1; + console.log(i); +} while (i < 5);</pre> + +<h2 id="Lệnh_while">Lệnh <code>while</code></h2> + +<p>Lệnh {{jsxref("statements/while","while")}} thực thi các lệnh bên trong nó ngay khi điều kiện xác định trả về true. Lệnh <code>while</code> có dạng như sau:</p> + +<pre class="syntaxbox">while (điều_kiện) + lệnh +</pre> + +<p>Nếu điều kiện trả về false, chương trình sẽ ngừng thực thi <code>lệnh</code> bên trong vòng lặp và truyền điều khiển xuống lệnh liền sau vòng lặp.</p> + +<p>Chương trình kiểm tra điều kiện trước khi thực thi <code>lệnh</code> bên trong. Nếu điều kiện trả về true, <code>lệnh</code> sẽ được thực thi và kiểm tra lại điều kiện. Nếu điều kiện trả về false, ngừng thực thi và truyền điều khiển xuống lệnh liền sau vòng lặp <code>while</code>.</p> + +<p>Để thực thi nhiều lệnh, dùng khối lệnh ({ ... }) để gom nhóm các câu lệnh.</p> + +<h3 id="Ví_dụ_1"><strong>Ví dụ 1</strong></h3> + +<p>Vòng <code>while</code> lặp lại cho tới khi <code>n</code> nhỏ hơn 3:</p> + +<pre class="brush: js">var n = 0; +var x = 0; +while (n < 3) { + n++; + x += n; +} +</pre> + +<p>Ứng với mỗi lần lặp, tăng <code>n</code> thêm một và cộng giá trị đó vào <code>x</code>. Bởi vậy, <code>x</code> và <code>n</code> có giá trị như sau:</p> + +<ul> + <li>Sau lần lặp thứ nhất: <code>n</code> = 1 và <code>x</code> = 1</li> + <li>Sau lần lặp thứ hai: <code>n</code> = 2 và <code>x</code> = 3</li> + <li>Sau lần lặp thứ ba: <code>n</code> = 3 và <code>x</code> = 6</li> +</ul> + +<p>Sau khi hoàn thành lần lặp thứ ba, điều kiện <code>n < 3</code> không còn trả về true nữa nên vòng lặp bị kết thúc.</p> + +<h3 id="Ví_dụ_2_2"><strong>Ví dụ 2</strong></h3> + +<p>Hãy tránh lặp vô hạn. Hãy đảm bảo rằng điều kiện của vòng lặp sẽ dần trả về false; bằng không, vòng lặp sẽ không bao giờ kết thúc. Lệnh trong vòng lặp <code>while</code> dưới đây được thực thi mãi mãi vì điều kiện không bao giờ trả về false:</p> + +<pre class="brush: js">while (true) { + console.log('Hello, world!'); +}</pre> + +<h2 id="Lệnh_gán_nhãn">Lệnh gán nhãn</h2> + +<p>{{jsxref("statements/label","label")}} tạo ra một lệnh đi kèm với một định danh, thông qua định danh giúp bạn tham chiếu tới nó từ những nơi khác trong chương trình của bạn. Chẳng hạn, bạn có thể dùng nhãn để định danh một vòng lặp, rồi dùng lệnh <code>break</code> hoặc <code>continue</code> để chương trình xác định có nên dừng hay tiếp tục thực thi vòng lặp hay không.</p> + +<p>Cú pháp của lệnh gán nhãn có dạng như sau:</p> + +<pre class="syntaxbox">nhãn : + lệnh +</pre> + +<p>Giá trị của <code><em>nhãn</em></code> có thể là định danh JavaScript bất kỳ nhưng không phải từ dành riêng (tên biến, tên hàm hoặc nhãn khác). <code><em>lệnh</em></code> được gán với nhãn có thể là bất kỳ lệnh nào.</p> + +<h3 id="Ví_dụ_3"><strong>Ví dụ</strong></h3> + +<p>Trong ví dụ này, nhãn <code>markLoop</code> giúp định danh cho một vòng lặp <code>while</code>.</p> + +<pre class="brush: js">markLoop: +while (theMark == true) { + doSomething(); +}</pre> + +<h2 id="Lệnh_break">Lệnh <code>break</code></h2> + +<p>Dùng lệnh {{jsxref("statements/break","break")}} để kết thúc vòng lặp, kết thúc <code>switch</code>, hoặc liên hợp với một lệnh được gán nhãn.</p> + +<ul> + <li>Khi dùng <code>break</code> không kèm với nhãn, chương trình kết thúc ngay tức thì vòng <code>while</code>, <code>do-while</code>, <code>for</code>, hoặc <code>switch</code> trong cùng bọc lệnh <code>break</code> và truyền điều khiển xuống lệnh liền sau.</li> + <li>Khi dùng <code>break</code> kèm với nhãn, nó sẽ chấm dứt việc thực thi lệnh được gắn nhãn đó.</li> +</ul> + +<p>Cú pháp lệnh <code>break</code> có dạng như sau:</p> + +<pre class="syntaxbox">break; +break [<em>nhãn</em>]; +</pre> + +<p>Kiểu cú pháp đầu tiên kết thúc vòng lặp trong cục bao bọc hoặc <code>switch</code>; kiểu thứ hai kết thúc lệnh gắn với nhãn.</p> + +<h3 id="Ví_dụ_1_2"><strong>Ví dụ</strong> <strong>1</strong></h3> + +<p>Trong ví dụ sau, lệnh lặp sẽ lặp qua từng phần tử của mảng (thông qua chỉ mục của từng phần tử) cho tới khi gặp phần tử có giá trị bằng <code>theValue</code>:</p> + +<pre class="brush: js">for (var i = 0; i < a.length; i++) { + if (a[i] == theValue) { + break; + } +}</pre> + +<h3 id="Ví_dụ_2_Áp_dụng_break_cho_nhãn"><strong>Ví dụ 2: </strong>Áp dụng break cho nhãn</h3> + +<pre class="brush: js">var x = 0; +var z = 0; +labelCancelLoops: while (true) { + console.log('Outer loops: ' + x); + x += 1; + z = 1; + while (true) { + console.log('Inner loops: ' + z); + z += 1; + if (z === 10 && x === 10) { + break labelCancelLoops; + } else if (z === 10) { + break; + } + } +} +</pre> + +<h2 id="Lệnh_continue">Lệnh <code>continue</code></h2> + +<p>Lệnh {{jsxref("statements/continue","continue")}} có thể dùng để tái duyệt các vòng <code>while</code>, <code>do-while</code>, <code>for</code>, hoặc <code>label</code>.</p> + +<ul> + <li>Khi dùng <code>continue</code> không kèm theo label, chương trình ngừng thực thi lần lặp hiện tại của vòng <code>while</code>, <code>do-while</code>, hoặc <code>for</code> gần nhất bọc lệnh <code>continue</code> và tiếp tục thực thi lần lặp tiếp theo. Trái với lệnh <code>break</code>, <code>continue</code> không dừng vòng lặp hoàn toàn. Trong vòng lặp <code>while</code>, chương trình nhảy về đoạn xét điều kiện. Trong vọng lặp <code>for</code>, chương trình nhảy tới <code>biểu_thức_tăng_tiến</code>.</li> + <li>Khi dùng <code>continue</code> có kèm theo label, lệnh <code>continue</code> sẽ áp dụng cho vòng lặp được gán nhãn đó.</li> +</ul> + +<p>Cú pháp của lệnh <code>continue</code> có dạng như sau:</p> + +<pre class="syntaxbox">continue [<em>label</em>]; +</pre> + +<h3 id="Ví_dụ_1_3"><strong>Ví dụ 1</strong></h3> + +<p>Trong ví dụ sau, vòng <code>while</code> với lệnh <code>continue</code> thực thi khi giá trị của <code>i</code> bằng 3. Thế nên, <code>n</code> sẽ có giá trị là 1, 3, 7 và 12.</p> + +<pre class="brush: js">var i = 0; +var n = 0; +while (i < 5) { + i++; + if (i == 3) { + continue; + } + n += i; + console.log(n); +} +//1,3,7,12 + + +var i = 0; +var n = 0; +while (i < 5) { + i++; + if (i == 3) { + // continue; + } + n += i; + console.log(n); +} +// 1,3,6,10,15 +</pre> + +<h3 id="Ví_dụ_2_3"><strong>Ví dụ 2</strong></h3> + +<p>Lệnh nhãn <em><code>checkiandj</code> </em>chứa nhãn <em><code>checkj</code></em>. Nếu chương trình chạy tới <code>continue</code>, chương trình sẽ ngừng thực hiện lần lặp hiện tại của <em><code>checkj</code></em><em> </em>và bắt đầu thực hiện lần lặp kế tiếp. Mỗi khi chạy tới <code>continue</code>, <em><code>checkj</code> </em>tái duyệt cho tới khi biểu thức điều kiện của nó trả về <code>false</code>. Khi <code>false</code> được trả về, phần còn lại của lệnh <em><code>checkiandj</code></em><em> </em>được hoàn thành, và <em><code>checkiandj</code></em><em> </em>tái duyệt cho tới khi điều kiện của nó trả về <code>false</code>. Khi <code>false</code> được trả về, chương trình tiếp tục thực thi lệnh liền sau <em><code>checkiandj</code></em>.</p> + +<p>Nếu <code>continue</code> gắn với nhãn <em><code>checkiandj</code></em>, chương trình sẽ tiếp tục ở đầu lệnh <em><code>checkiandj</code></em><em> </em>.</p> + +<pre class="brush: js">var i = 0; +var j = 10; +checkiandj: + while (i < 4) { + console.log(i); + i += 1; + checkj: + while (j > 4) { + console.log(j); + j -= 1; + if ((j % 2) == 0) { + continue checkj; + } + console.log(j + ' is odd.'); + } + console.log('i = ' + i); + console.log('j = ' + j); + }</pre> + +<h2 id="Lệnh_for...in">Lệnh <code>for...in</code></h2> + +<p>Lệnh {{jsxref("statements/for...in","for...in")}} lặp một biến (variable) đã được xác định trước, qua mọi thuộc tính có thể đếm được (enumerable properties) của đối tượng (object). Với từng phần tử riêng biệt, JavaScript thực thi các câu lệnh mà bạn định sẵn. Lệnh <code>for...in</code> có dạng như sau:</p> + +<pre class="syntaxbox">for (variable in object) + statement +</pre> + +<h3 id="Ví_dụ_4"><strong>Ví dụ</strong></h3> + +<p>Hàm sau nhận vào tham số là một object và tên của object đó. Sau đó nó lặp qua mọi thuộc tính của object, với mỗi lần lặp nó trả về một chuỗi ký tự liệt kê các tên thuộc tính và giá trị của chúng.</p> + +<pre class="brush: js">function dump_props(obj, obj_name) { + var result = ''; + for (var i in obj) { + result += obj_name + '.' + i + ' = ' + obj[i] + '<br>'; + } + result += '<hr>'; + return result; +} +</pre> + +<p>Chẳng hạn với object <code>car</code> có thuộc tính là <code>make</code> và <code>model</code>, <code>result</code> sẽ là:</p> + +<pre class="brush: js">car.make = Ford +car.model = Mustang +</pre> + +<h3 id="Mảng"><strong>Mảng</strong></h3> + +<p>Mặc dù có thể dùng cách này để lặp qua từng phần tử của mảng {{jsxref("Array")}}, lệnh <code>for...in</code> sẽ trả về tên của thuộc tính mà người dùng tự định nghĩa kèm theo chỉ mục của mảng.</p> + +<p>Bởi vậy, tốt hơn hết hãy sử dụng cách truyền thống là dùng vòng lặp {{jsxref("statements/for","for")}} với chỉ mục dạng số để lặp qua từng phần tử của mảng, bởi lệnh <code>for...in</code> còn lặp qua cả thuộc tính mà người dùng tự định nghĩa (chẳng hạn như khi thêm một thuộc tính vào mảng, sẽ có ví dụ ở phía dưới).</p> + +<h2 id="for...of_statement"><code>for...of</code> statement</h2> + +<p>Lệnh {{jsxref("statements/for...of","for...of")}} tạo ra một vòng lặp, áp dụng với các <a href="/en-US/docs/Web/JavaScript/Guide/iterable">đối tượng khả duyệt</a> (iterable object) (bao gồm {{jsxref("Array")}}, {{jsxref("Map")}}, {{jsxref("Set")}}, {{jsxref("functions/arguments","arguments")}} object, v.v...), và gọi lên một hook lặp tùy chỉnh (custom iteration hook) với các câu lệnh sẽ được thực thi cho <strong>giá trị</strong> của từng thuộc tính.</p> + +<pre class="syntaxbox">for (<em>variable</em> of <em>object</em>) + <em>statement</em> +</pre> + +<p>Ví dụ sau chỉ ra sự khác biệt giữa hai vòng lặp: <code>for...of</code> và {{jsxref("statements/for...in","for...in")}}. Trong khi <code>for...in</code> lặp qua tên thuộc tính, <code>for...of</code> lặp qua giá trị thuộc tính:</p> + +<pre class="brush:js">var arr = [3, 5, 7]; +arr.foo = 'hello'; + +for (var i in arr) { + console.log(i); // logs "0", "1", "2", "foo" +} + +for (var i of arr) { + console.log(i); // logs 3, 5, 7 +} +</pre> + +<p>{{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}</p> diff --git a/files/vi/web/javascript/guide/numbers_and_dates/index.html b/files/vi/web/javascript/guide/numbers_and_dates/index.html new file mode 100644 index 0000000000..a48afbbb89 --- /dev/null +++ b/files/vi/web/javascript/guide/numbers_and_dates/index.html @@ -0,0 +1,385 @@ +--- +title: Numbers and dates +slug: Web/JavaScript/Guide/Numbers_and_dates +translation_of: Web/JavaScript/Guide/Numbers_and_dates +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}</div> + +<p>Chương này giới thiệu những khái niệm, đối tượng và hàm được sử dụng để làm việc và tính toán với giá trị số và ngày tháng trong JavaScript. Nó bao gồm việc sử dụng những con số được viết dưới dạng những hệ cơ số khác nhau như là hệ thập phân, hệ nhị phân và hệ thập lục phân, cũng như việc sử dụng đối tượng toàn cục {{jsxref("Math")}} để thực hiện các phép toán số học.</p> + +<h2 id="Con_Số_Numbers">Con Số (Numbers)</h2> + +<p>Trong JavaScript, tất cả các con số được cài đặt theo <a class="external external-icon" href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">double-precision 64-bit binary format IEEE 754</a> (ví dụ: một số bắt đầu từ ±2<sup>−1022</sup> and ±2<sup>+1023</sup>, hoặc là khoảng ±10<sup>−308</sup> to ±10<sup>+308</sup>, với độ chính xác 53 bits sau dấu phẩy). Số nguyên lớn nhất có thể là ±2<sup>53 </sup>− 1. Để có thể biểu diễn số thực dấu chấm động, ta có thể dùng ba ký hiệu <code>+</code>{{jsxref("Infinity")}}, <code>-</code>{{jsxref("Infinity")}}, and {{jsxref("NaN")}} (not-a-number). Xem thêm trong <a href="/en-US/docs/Web/JavaScript/Data_structures">JavaScript data types and structures</a> về những kiểu sơ cấp trong JavaScript.</p> + +<div class="blockIndicator note"> +<p><strong>Lưu Ý:</strong> Không có kiểu cụ thể cho số nguyên trong JavaScript, mặc dù kiểu {{jsxref("BigInt")}} cho phép biểu diễn số nguyên mà có giá trị rất lớn. Nhưng cần cẩn thận khi dùng <code>BigInt</code>, ví dụ, bạn có không thể kết hợp giá trị <code>BigInt</code> và {{jsxref("Number")}} trong cùng một biểu thức, và bạn cũng không thể sử dụng {{jsxref("Math")}} với giá trị <code>BigInt</code>.</p> +</div> + +<p>Bạn có thể sử dụng bốn loại literal để tạo số: thập phân, nhị phân, bát phân và thập lục phân.</p> + +<h3 id="Số_thập_phân">Số thập phân</h3> + +<pre class="brush: js">1234567890 +42 + +// Cẩn thận với số bắt đầu bằng số không: + +0888 // 888 trong hệ thập phân +0777 // được xem như là số bát phân trong chế độ non-strict (và có giá trị là 511 trong hệ thập phân) +</pre> + +<p>Lưu ý literal thập phân có thể bắt đầu bằng số zero (0) được theo sau là những số thập phân, nhưng nếu mọi chữ số sau số 0 nhỏ hơn 8, thì nó hiểu nhầm như là hệ bát phân.</p> + +<h3 id="Số_nhị_phân">Số nhị phân</h3> + +<p>Cú pháp của hệ nhị phân bắt đầu bằng chữ số 0 theo sau là "B" hoặc "b" (<code>0b</code> or <code>0B</code>). Nếu các chữ số theo sau <code>0b</code> không phải là 0 hoặc 1, thì lỗi <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError">SyntaxError</a></code> sẽ phát sinh như sau "Missing binary digits after 0b".</p> + +<pre class="brush: js">var FLT_SIGNBIT = 0b10000000000000000000000000000000; // 2147483648 +var FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040 +var FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607</pre> + +<h3 id="Số_bát_phân">Số bát phân</h3> + +<p>Số bát phân bắt đầu bằng số 0. Nếu chữ số theo sau số <code>0</code> không nắm trong khoảng từ 0 đến 7, thì số đó sẽ được hiểu là số thập phân.</p> + +<pre class="brush: js">var n = 0755; // 493 +var m = 0644; // 420 +</pre> + +<p>Trong chế độ strict trong ECMAScript 5 ngăn cấm cú pháp hệ bát phân. Cú pháp hệ bát phân không nằm trong đặc tả của ECMAScript 5, nhưng nó được hỗ trợ bởi tất cả các trình duyệt bằng cách đặt tiền tố 0: <code>0644 === 420</code> and<code>"\045" === "%"</code>. Trong ECMAScript 2015 (ES6), số bát phân được hỗ trợ nếu chúng bắt đầu bằng <code>0o</code>, ví dụ:</p> + +<pre class="brush: js">var a = 0o10; // ES2015: 8 +</pre> + +<h3 id="Số_thập_lục_phân">Số thập lục phân</h3> + +<p>Cú pháp của số thập lục phân được bắt đầu bằng 0 và theo sau là "x" hoặc "X" (<code>0x</code> or <code>0X)</code>. Nếu các chữ số theo sau 0x nằm ngoài khoảng giá trị (0123456789ABCDEF), Lỗi <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError">SyntaxError</a></code> sẽ phát sinh: "Identifier starts immediately after numeric literal".</p> + +<pre class="brush: js">0xFFFFFFFFFFFFFFFFF // 295147905179352830000 +0x123456789ABCDEF // 81985529216486900 +0XA // 10 +</pre> + +<h3 id="Số_mũ">Số mũ</h3> + +<pre class="brush: js">1E3 // 1000 +2e6 // 2000000 +0.1e2 // 10</pre> + +<h2 id="Number_object"><code>Number</code> object</h2> + +<p>{{jsxref("Number")}} object có những thuộc tính có giá trị là những hằng kiểu số, như giá trị lớn nhất, not-a-number, và vô cực. Bạn không thể thay đổi những giá trị của những thuộc tính này và bạn sử dụng nó như sau:</p> + +<pre class="brush: js">var biggestNum = Number.MAX_VALUE; +var smallestNum = Number.MIN_VALUE; +var infiniteNum = Number.POSITIVE_INFINITY; +var negInfiniteNum = Number.NEGATIVE_INFINITY; +var notANum = Number.NaN; +</pre> + +<p>Bạn luôn phải tham chiếu đến những thuộc tính được định nghĩa sẳn của <code>Number</code> object như trên, và không thể truy xuất qua giá trị số mà bạn tạo ra.</p> + +<p>Bảng sau tổng hợp những thuộc tính của <code>Number</code> object.</p> + +<table class="standard-table"> + <caption>Thuộc tính của <code>Number</code></caption> + <thead> + <tr> + <th scope="col">Thuộc tính</th> + <th scope="col">Mô tả</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("Number.MAX_VALUE")}}</td> + <td>Số lớn nhất có thể gán (<code>±1.7976931348623157e+308</code>)</td> + </tr> + <tr> + <td>{{jsxref("Number.MIN_VALUE")}}</td> + <td>Số nhỏ nhất có thể gán (<code>±5e-324</code>)</td> + </tr> + <tr> + <td>{{jsxref("Number.NaN")}}</td> + <td>Special "not a number" value<br> + Giá trị đặc biệt để mô tả "không phải là số"</td> + </tr> + <tr> + <td>{{jsxref("Number.NEGATIVE_INFINITY")}}</td> + <td>Giá trị số âm vô định; được về khi vượt quá giá trị có thể tính toán</td> + </tr> + <tr> + <td>{{jsxref("Number.POSITIVE_INFINITY")}}</td> + <td>Giá trị số dương vô định; được về khi vượt quá giá trị có thể tính toán</td> + </tr> + <tr> + <td>{{jsxref("Number.EPSILON")}}</td> + <td>Sự khác nhau giữa <code>1</code> và giá trị nhỏ nhất lớn hơn <code>1</code> mà có thể được biểu diễn là một số<br> + {{jsxref("Number")}} (<code>2.220446049250313e-16</code>)</td> + </tr> + <tr> + <td>{{jsxref("Number.MIN_SAFE_INTEGER")}}</td> + <td>Số nguyên được an toàn nhỏ nhất trong JavaScript (−2<sup>53</sup> + 1, or <code>−9007199254740991</code>)</td> + </tr> + <tr> + <td>{{jsxref("Number.MAX_SAFE_INTEGER")}}</td> + <td>Số nguyên dương an toàn lớn nhất trong JavaScript (+2<sup>53</sup> − 1, or <code>+9007199254740991</code>)</td> + </tr> + </tbody> +</table> + +<table class="standard-table"> + <caption>Phương thức của <code>Number</code></caption> + <thead> + <tr> + <th>Phương thức</th> + <th>Mô tả</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("Number.parseFloat()")}}</td> + <td>Phân tích giá trị chuỗi và trả vể một giá trị số thực.<br> + Giống như hàm toàn cục {{jsxref("parseFloat", "parseFloat()")}}.</td> + </tr> + <tr> + <td>{{jsxref("Number.parseInt()")}}</td> + <td>Phân tích giá trị kiểu chuỗi và trả về giá trị số nguyên dựa trên cơ số chỉ định.<br> + Cũng giống như hàm toàn cục {{jsxref("parseInt", "parseInt()")}} function.</td> + </tr> + <tr> + <td>{{jsxref("Number.isFinite()")}}</td> + <td>Xác định giá trị được truyền vào có phải là một số xác đinh.</td> + </tr> + <tr> + <td>{{jsxref("Number.isInteger()")}}</td> + <td>Xác định giá trị truyền vào có phải là một số nguyên.</td> + </tr> + <tr> + <td>{{jsxref("Number.isNaN()")}}</td> + <td>Xác định giá trị truyền vào là {{jsxref("Global_Objects/NaN", "NaN")}}. Đây là phiên bản cải tiến của {{jsxref("Global_Objects/isNaN", "isNaN()")}}.</td> + </tr> + <tr> + <td>{{jsxref("Number.isSafeInteger()")}}</td> + <td>Xác định giá trị truyền vào là một số nguyên an toàn.</td> + </tr> + </tbody> +</table> + +<p><code>Number</code> prototype cung cấp những phương thức để lấy thông tin từ những đối tượng <code>Number</code> dưới nhiều định dạng. Bảng sau đây tổng hợp những phương thức của <code>Number.prototype</code>.</p> + +<table class="standard-table"> + <caption>Những phương thức của <code>Number.prototype</code></caption> + <thead> + <tr> + <th scope="col">Phương thức</th> + <th scope="col">Mô tả</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("Number.toExponential", "toExponential()")}}</td> + <td>Trả về một chuỗi biểu diễn một số theo dạng lũy thừa.</td> + </tr> + <tr> + <td>{{jsxref("Number.toFixed", "toFixed()")}}</td> + <td>Trả về một chuỗi biểu diễn một số theo dạng số thập phân, với phần thập phân cố định.</td> + </tr> + <tr> + <td>{{jsxref("Number.toPrecision", "toPrecision()")}}</td> + <td>Trả về một chuỗi biểu diễn một số thập phân với độ chính xác được chỉ định.</td> + </tr> + </tbody> +</table> + +<h2 id="Math_object"><code>Math</code> object</h2> + +<p>{{jsxref("Math")}} object cung cấp thuộc tính và những phương thức để lấy giá trị của các hằng số và những hàm toán học. Ví dụ, thuộc tính PI của <code>Math</code> có giá trị pi (3.141...), mà bạn có thể sử dụng trong ứng dụng như</p> + +<pre class="brush: js">Math.PI +</pre> + +<p>Tương tự, những hàm chuẩn của toán học là phương thức của <code>Math</code>. Bao gồm lượng giác, logarit, hàm mũ, và những hàm khác nữa. Ví dụ, nếu bạn muốn sử dụng hàm lượng giác sine, bạn có thể viết như sau</p> + +<pre class="brush: js">Math.sin(1.56) +</pre> + +<p>Lưu ý rằng phương thức lượng giác của <code>Math</code> nhận đổi số kiểu radians.</p> + +<p>Bảng sau tóm tắt những phương thức của đối tượng <code>Math</code>.</p> + +<table class="standard-table"> + <caption>Phương thức của <code>Math</code></caption> + <thead> + <tr> + <th scope="col">Phương thức</th> + <th scope="col">Mô tả</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("Math.abs", "abs()")}}</td> + <td>Giá trị tuyệt đối</td> + </tr> + <tr> + <td>{{jsxref("Math.sin", "sin()")}}, {{jsxref("Math.cos", "cos()")}}, {{jsxref("Math.tan", "tan()")}}</td> + <td>Những hàm lượng giác chuẩn, với đối số đơn vị radians.</td> + </tr> + <tr> + <td>{{jsxref("Math.asin", "asin()")}}, {{jsxref("Math.acos", "acos()")}}, {{jsxref("Math.atan", "atan()")}}, {{jsxref("Math.atan2", "atan2()")}}</td> + <td>Những hàm lượng giác ngược; trả về giá trị theo đơn vị radians.</td> + </tr> + <tr> + <td>{{jsxref("Math.sinh", "sinh()")}}, {{jsxref("Math.cosh", "cosh()")}}, {{jsxref("Math.tanh", "tanh()")}}</td> + <td>Hàm Hyperbolic; đối số là giá trị theo đơn vị hyperbolic.<br> + </td> + </tr> + <tr> + <td>{{jsxref("Math.asinh", "asinh()")}}, {{jsxref("Math.acosh", "acosh()")}}, {{jsxref("Math.atanh", "atanh()")}}</td> + <td>Nghịch đảo của hàm hyperbolic; đối số là giá trị theo đơn vị hyperbolic.</td> + </tr> + <tr> + <td> + <p>{{jsxref("Math.pow", "pow()")}}, {{jsxref("Math.exp", "exp()")}}, {{jsxref("Math.expm1", "expm1()")}}, {{jsxref("Math.log10", "log10()")}}, {{jsxref("Math.log1p", "log1p()")}}, {{jsxref("Math.log2", "log2()")}}</p> + </td> + <td>Hàm mũ và hàm logarit</td> + </tr> + <tr> + <td>{{jsxref("Math.floor", "floor()")}}, {{jsxref("Math.ceil", "ceil()")}}</td> + <td>Trả về số nguyên lớn nhất và nhỏ nhất mà nhỏ hơn hoặc lớn hơn hoặc bằng đối số truyền vào.</td> + </tr> + <tr> + <td>{{jsxref("Math.min", "min()")}}, {{jsxref("Math.max", "max()")}}</td> + <td>Trả về giá trị lớn nhất hoặc nhỏ nhất trong dãy các giá trị truyền vào.</td> + </tr> + <tr> + <td>{{jsxref("Math.random", "random()")}}</td> + <td>Trả về số ngẫu nhiên trong khoảng 0 và 1.</td> + </tr> + <tr> + <td>{{jsxref("Math.round", "round()")}}, {{jsxref("Math.fround", "fround()")}}, {{jsxref("Math.trunc", "trunc()")}},</td> + <td>Những hàm làm tròn hoặc cắt bớt.</td> + </tr> + <tr> + <td>{{jsxref("Math.sqrt", "sqrt()")}}, {{jsxref("Math.cbrt", "cbrt()")}}, {{jsxref("Math.hypot", "hypot()")}}</td> + <td> + <p>Căn bậc hai, cube root, căn bậc hai của tổng đối số bình phương.</p> + </td> + </tr> + <tr> + <td>{{jsxref("Math.sign", "sign()")}}</td> + <td>Xác dịnh số âm hay số dương hay số không</td> + </tr> + <tr> + <td>{{jsxref("Math.clz32", "clz32()")}},<br> + {{jsxref("Math.imul", "imul()")}}</td> + <td>Số bit 0 ở đầu trong số nhị phân 32 bit. Kết quả của phép nhân 32 bit.</td> + </tr> + </tbody> +</table> + +<p>Không giống như những object khác, bạn không bao giờ tạo <code>Math</code> riêng. Bạn luôn dùng đối tượng <code>Math</code> có sẳn</p> + +<h2 id="Date_object"><code>Date</code> object</h2> + +<p>JavaScript không có kiểu dữ liệu ngày tháng. Tuy nhiên, bạn có thể sử dụng {{jsxref("Date")}} object và phương thức của nó để làm việc với ngày giờ trong ứng dụng của mình. <code>Date</code> object cung cấp nhiều phương thức trực tiếp để thao tác trên trên giá trị ngày giờ. Nó không có bất kỳ thuộc tính nào.</p> + +<p>JavaScript xử lý ngày giờ tương tự Java. Hai ngôn ngữ có nhiều tên phương thức giống nhau, và cả hai ngôn ngữ đều lưu trữ ngày giờ như là một số theo mili giây tính từ ngày 1 tháng 1 năm 1970, 00:00:00, với một Unix Timestamp là một số theo giây tính từ ngày 1 tháng 1, 1970, 00:00:00.</p> + +<p>Dãy giá trị của <code>Date</code> object là -100,000,000 ngày đến 100,000,000 ngày so với 01 tháng 1, 1970 UTC.</p> + +<p>Để tạo một <code>Date</code> object:</p> + +<pre class="brush: js">var dateObjectName = new Date([parameters]); + +</pre> + +<p><code>dateObjectName</code> là biến lưu trữ <code>Date</code> object được tạo;</p> + +<p>Nếu chúng ta bỏ qua từ khóa <code>new</code>, giá trị nhận được là một chuỗi biểu diễn giá trị kiểu ngày giờ.</p> + +<p><code>parameters</code> trong cú pháp trên có thể là một trong những giá trị sau:</p> + +<ul> + <li>Không truyền gì vào: tạo ngày giờ hiện hành. Ví dụ: <code>today = new Date();</code>.</li> + <li>Một chuỗi biểu diễn ngày giờ theo định dạng: "Tháng ngày, năm giờ:phút:giây". Ví dụ: <code>var Xmas95 = new Date("December 25, 1995 13:30:00")</code>. Nếu bạn bỏ sót giờ, phút, giây, giá trị mặc định sẽ là 0.</li> + <li>Một tập các số nguyên cho năm, tháng, và ngày. Ví dụ, <code>var Xmas95 = new Date(1995, 11, 25)</code>.</li> + <li>Một tập các số nguyên cho năm, tháng, ngày, giờ, phút, và giây. Ví dụ <code>var Xmas95 = new Date(1995, 11, 25, 9, 30, 0);</code>.</li> +</ul> + +<h3 id="Những_phương_thức_của_Date_object">Những phương thức của <code>Date</code> object</h3> + +<p>Những phương thức của <code>Date</code> object để xử lý thuộc một trong những loại sau:</p> + +<ul> + <li>phương thức "set", để gán giá trị ngày giờ cho <code>Date</code> objects.</li> + <li>phương thức "get", để nhận giá trị ngày giờ từ <code>Date</code> objects.</li> + <li>phương thức "to", để nhận về giá trị kiểu chuỗi cho <code>Date</code> objects.</li> + <li>phương thức phân giải (parse) và UTC, để phân giải chuỗi <code>Date</code> .</li> +</ul> + +<p>Với phương thức "get" và "set" bạn có thể nhận và gán giây, phút, giờ và ngày của tháng, ngày của tuần, tháng, và năm. Phương thức <code>getDay</code> trả về ngày của tuần, tháng, nhưng không có phương thức <code>setDay</code> tương ứng, bởi vì ngày của tuần được xác định tự động. Những phương thức này sử dụng số nguyên để biểu diễn những giá trị sau:</p> + +<ul> + <li>Giây và phúc: 0 đến 59</li> + <li>Giờ: 0 đến 23</li> + <li>Thứ: 0 (Chủ nhật) đến 6 (Thứ bảy)</li> + <li>Ngày: 1 đến 31 (ngày của tháng)</li> + <li>Tháng: 0 (Tháng 1) to 11 (Tháng 12)</li> + <li>Năm: năm tính từ 1900</li> +</ul> + +<p>Ví dụ, giả sử bạn định nghĩa giá trị ngày như sau:</p> + +<pre class="brush: js">var Xmas95 = new Date('December 25, 1995'); +</pre> + +<p>Phương thức <code>Xmas95.getMonth()</code> trả về 11, và <code>Xmas95.getFullYear()</code> trả về 1995.</p> + +<p>Phương thức <code>getTime</code> và <code>setTime</code> dùng để so sánh hai giá trị ngày. Phương thức <code>getTime</code> trả về số milli giây tính từ 0 giờ 0 phút 0 giây ngày 1 tháng 1 năm 1970.</p> + +<p>Ví dụ đoạn mã sau hiển thị số ngày còn lại trong năm hiện tại:</p> + +<pre class="brush: js">var today = new Date(); +var endYear = new Date(1995, 11, 31, 23, 59, 59, 999); // Set day and month +endYear.setFullYear(today.getFullYear()); // Set year to this year +var msPerDay = 24 * 60 * 60 * 1000; // Number of milliseconds per day +var daysLeft = (endYear.getTime() - today.getTime()) / msPerDay; +var daysLeft = Math.round(daysLeft); //returns days left in the year +</pre> + +<p>Đầu tiên một <code>Date</code> object được tạo ra với tên là <code>today</code> chứ giá trị là ngày hiện tại. Sau đó, một <code>Date</code> object nữa được tạo ra với tên là <code>endYear</code> và được gán giá trị của ngày cuối cùng của năm 1995. Nhưng sau đó <code>endYear</code> được gán lại với năm hiện tại cho đồng nhất về năm. Rồi ta tính toán độ chênh lệch theo ngày giữa <code>endYear</code> và <code>today</code> giá trị phải được làm tròn.</p> + +<p>Phương thức <code>parse</code> dùng để chuyển đổi chuỗi kiểu <code>Date</code> thành <code>Date</code> object. Ví dụ, Đoạn mã sau sử dụng <code>parse</code> và <code>setTime</code> để gán giá trị ngày cho biến <code>IPOdate</code>:</p> + +<pre class="brush: js">var IPOdate = new Date(); +IPOdate.setTime(Date.parse('Aug 9, 1995')); +</pre> + +<h3 id="Ví_dụ">Ví dụ</h3> + +<p>Trong ví dụ sau, hàm <code>JSClock()</code> trả về thời gian trong định dạng của đồng hồ số.</p> + +<pre class="brush: js">function JSClock() { + var time = new Date(); + var hour = time.getHours(); + var minute = time.getMinutes(); + var second = time.getSeconds(); + var temp = '' + ((hour > 12) ? hour - 12 : hour); + if (hour == 0) + temp = '12'; + temp += ((minute < 10) ? ':0' : ':') + minute; + temp += ((second < 10) ? ':0' : ':') + second; + temp += (hour >= 12) ? ' P.M.' : ' A.M.'; + return temp; +} +</pre> + +<p>Hàm <code>JSClock</code> đầu tiên tạo ra <code>Date</code> object với tên <code>time</code>; vì không có đối số được cung cấp, <code>time</code> được tạo ra có giá trị là ngày giờ hiện tại. Sau đó các hàm <code>getHours</code>, <code>getMinutes</code>, và <code>getSeconds</code> để gán giá trị giờ, phút, giây hiện tai cho các biến <code>hour</code>, <code>minute</code>, và <code>second</code>.</p> + +<p>Bốn câu lệnh kế tiếp tạo giá trị chuỗi từ thời gian. Câu lệnh đầu tiên tạo một biến <code>temp</code>, dùng biểu thức điều kiện để gán 1 giá trị cho temp; nếu <code>hour</code> lớn hơn 12, thì gán (<code>hour - 12</code>), ngược lại thì gán giá trị của <code>hour</code>. Nếu giá trị của <code>hour</code> là 0, thì giá trị 12 cho temp.</p> + +<p>Câu lệnh tiếp theo chèn gía trị <code>minute</code> cho <code>temp</code>. Nếu giá trị của <code>minute</code> kém hơn 10, ta thêm ':0' vào trước giá trị chuỗi; ngược lại ta chỉ thêm ':'. Sau đó chèn giá trị giây vào <code>temp</code> với cùng cách trên.</p> + +<p>Cuối cùng, chèn "P.M" vào <code>temp</code> nếu <code>hour</code> lớn hơn 12, ngược lại ta chèn "A.M.".</p> + +<p>{{PreviousNext("Web/JavaScript/Guide/Expressions_and_Operators", "Web/JavaScript/Guide/Text_formatting")}}</p> diff --git a/files/vi/web/javascript/guide/regular_expressions/index.html b/files/vi/web/javascript/guide/regular_expressions/index.html new file mode 100644 index 0000000000..acddfd5184 --- /dev/null +++ b/files/vi/web/javascript/guide/regular_expressions/index.html @@ -0,0 +1,666 @@ +--- +title: Biểu thức chính quy +slug: Web/JavaScript/Guide/Regular_Expressions +tags: + - Guide + - Intermediate + - JavaScript + - Regular Expression +translation_of: Web/JavaScript/Guide/Regular_Expressions +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}</div> + +<p>Biểu thức chính quy (regular expressions ) là các mẫu dùng để tìm kiếm các bộ kí tự được kết hợp với nhau trong các chuỗi kí tự. Trong JavaScript thì biểu thức chính quy cũng đồng thời là các đối tượng, tức là khi bạn tạo ra một biểu thức chính quy là bạn có một đối tượng tương ứng. Các mẫu này được sử dụng khá nhiều trong JavaScript như phương thức <a href="/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec" title="exec"><code>exec</code></a> và <a href="/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/test" title="test"><code>test</code></a> của<a href="/vi/docs/JavaScript/Reference/Global_Objects/RegExp" title="RegExp"> <code>RegExp</code></a>, hay phương thức <a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/match" title="match"><code>match</code></a>, <a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/replace" title="en-US/docs/JavaScript/Reference/Global_Objects/String/replace"><code>replace</code></a>,<a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/search" title="search"> <code>search</code></a>, và <a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/split" title="split"><code>split</code></a> của <a href="/en-US/docs/JavaScript/Reference/Global_Objects/String" title="String"><code>String</code></a>. Trong chương này, ta cùng tìm hiểu chi tiết hơn về biểu thức chính quy trong JavaScript.</p> + +<h2 id="Tạo_một_biểu_thức_chính_quy">Tạo một biểu thức chính quy</h2> + +<p>Bạn có thể tạo ra một biểu thức chính quy bằng 1 trong 2 cách sau:</p> + +<ul> + <li>Sử dụng cách mô tả chính quy thuần (regular expression literal) như sau: + <pre class="brush: js">var re = /ab+c/; +</pre> + + <p>Các đoạn mã chứa các mô tả chính quy thuần sau khi được nạp vào bộ nhớ sẽ dịch các đoạn mô tả đó thành các biểu thức chính quy. Các biểu thức chính quy được dịch ra này sẽ được coi như các hằng số, tức là không phải tạo lại nhiều lần, điều này giúp cho hiệu năng thực hiện tốt hơn.</p> + </li> + <li>Tạo một đối tượng <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/RegExp" title="en-US/docs/JavaScript/Reference/Global Objects/RegExp">RegExp</a></code> như sau: + <pre class="brush: js">var re = new RegExp("ab+c"); +</pre> + + <p>Với cách này, các biểu thức chính quy sẽ được dịch ra lúc thực thi chương trình nên hiệu năng không đạt được như với việc sử dụng cách mô tả chính quy thuần. Nhưng ưu điểm là nó có thể thay đổi được, nên ta thường sử dụng chúng khi ta muốn nó có thể thay đổi được, hoặc khi ta chưa chắc chắn về các mẫu chính quy (pattern) như nhập từ bàn phím chẳng hạn.</p> + </li> +</ul> + +<h2 id="Cách_viết_một_mẫu_biểu_thức_chính_quy">Cách viết một mẫu biểu thức chính quy</h2> + +<p>Một mẫu biểu thức chính quy là một tập các kí tự thường, như <code>/abc/</code>, hay một tập kết hợp cả kí tự thường và kí tự đặc biệt như <code>/ab*c/</code> hoặc <code>/Chapter (\d+)\.\d*/</code>. Trong ví dụ cuối, ta thấy rằng nó chứa cả các dấu ngoặc đơn( () )được sử dụng như các thiết bị nhớ, tức là các mẫu trong phần () này sau khi được tìm kiếm có thể được nhớ lại để sử dụng cho các lần sau. Bạn có thể xem chi tiết hơn tại: <a href="#Sử dụng nhiều dấu ngoặc tròn">Sử dụng dấu ngoặc đơn tìm xâu con</a>.</p> + +<h3 id="Sử_dụng_mẫu_đơn_giản">Sử dụng mẫu đơn giản</h3> + +<p>Các mẫu đơn giản là các mẫu có thể được xây dựng từ các kí tự có thể thể tìm kiếm một cách trực tiếp. Ví dụ, mẫu <code>/abc/</code> sẽ tìm các các đoạn 'abc' theo đúng thứ tự đó trong các chuỗi. Mẫu này sẽ khớp được với "Hi, do you know your abc's?" và "The latest airplane designs evolved from slabcraft.", vì cả 2 chuỗi này đều chứa đoạn 'abc'. Còn với chuỗi 'Grab crab', nó sẽ không khớp vì chuỗi này không chứa 'abc' theo đúng thứ tự, mà chỉ chứa 'ab c'.</p> + +<h3 id="Sử_dụng_các_kí_tự_đặc_biệt">Sử dụng các kí tự đặc biệt</h3> + +<p>Các mẫu có thể chứa các kí tự đặc biệt cho các mục đích tìm kiếm nâng cao mà tìm kiếm trực tiếp sẽ khó khăn như tìm một đoạn chứa một hoặc nhiều hơn một kí tự b, hay tìm một hoặc nhiều kí tự dấu cách (while space). Ví dụ, mẫu <code>/ab*c/</code> có thể tìm các đoạn có chứa: một kí tự 'a', theo sau là không có hoặc có một hoặc có nhiều kí tự 'b', cuối cùng là một kí tự 'c' như chuỗi "cbbabbbbcdebc," sẽ được khớp với xâu con 'abbbbc'.</p> + +<p>Bảng dưới đây mô tả đầy đủ các kí tự đặc biệt có thể dùng với biểu thức chính quy.</p> + +<table class="fullwidth-table"> + <caption>Bảng 4.1 Các kí tự đặc biệt trong biểu thức chính quy.</caption> + <thead> + <tr> + <th scope="col">Kí tự (kí hiệu, cờ)</th> + <th scope="col">Ý nghĩa</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="#special-backslash" id="special-backslash" name="special-backslash"><code>\</code></a></td> + <td> + <p>Tìm với luật dưới đây:<br> + <br> + Một dấu gạch chéo ngược sẽ biến một kí tự thường liền kế phía sau thành một kí tự đặc biệt, tức là nó không được sử dụng để tìm kiếm thông thường nữa. Ví dụ, trường hợp kí tự '<code>b</code>' không có dấu gạch chéo ngược này sẽ được khớp với các kí tự 'b' in thường, nhưng khi nó có thêm dấu gạch chéo ngược, '<code>\b</code>' thì nó sẽ không khớp với bất kì kí tự nào nữa, lúc này nó trở thành kí tự đặc biệt. Xem thêm phần <a href="#special-word-boundary" title="#special-word-boundary">word boundary character</a> để biết thêm chi tiết.<br> + <br> + Tuy nhiên nếu đứng trước một kí tự đặc biệt thì nó sẽ biến kí tự này thành một kí tự thường, tức là bạn có thể tìm kiếm kí tự đặc biệt này trong xâu chuỗi của bạn như các kí tự thường khác. Ví dụ, mẫu <code>/a*/</code> có '*' là kí tự đặc biệt và mẫu này sẽ bị phụ thuộc vào kí tự này, nên được hiểu là sẽ tìm khớp với 0 hoặc nhiều kí tự a. Nhưng, với mẫu <code>/a\*/</code> thì kí tự '<code>*</code>' lúc này được hiểu là kí tự thường nên mẫu này sẽ tìm kiếm xâu con là 'a*'.</p> + + <p>Đừng quên \ cũng là một kí tự đặc biệt, khi cần so khớp chính nó ta cũng phải đánh dấu nó là kí tự đặc biệt bằng cách đặt \ ở trước (\\).</p> + </td> + </tr> + <tr> + <td><a href="#special-caret" id="special-caret" name="special-caret"><code>^</code></a></td> + <td> + <p>Khớp các kí tự đứng đầu một chuỗi. Nếu có nhiều cờ này thì nó còn khớp được cả các kí tự đứng đầu của mỗi dòng (sau kí tự xuống dòng).<br> + <br> + Ví dụ, <code>/^A/</code> sẽ không khớp được với 'A' trong "an A" vì 'A' lúc này không đứng đầu chuỗi, nhưng nó sẽ khớp "An E" vì lúc này 'A' đã đứng đầu chuỗi.</p> + + <p>Ý nghĩa của '^' sẽ thay đổi khi nó xuất hiện như một kí tự đầu tiên trong một lớp kí tự, xem phần <a href="#special-negated-character-set" title="#special-negated-character-set">complemented character sets</a> để biết thêm chi tiết.</p> + </td> + </tr> + <tr> + <td><a href="#special-dollar" id="special-dollar" name="special-dollar"><code>$</code></a></td> + <td> + <p>So khớp ở cuối chuỗi. Nếu gắn cờ multiline (đa dòng), nó sẽ khớp ngay trước kí tự xuống dòng.</p> + + <p>Ví dụ, /t$/ không khớp với 't' trong chuỗi "eater" nhưng lại khớp trong chuỗi "eat".</p> + </td> + </tr> + <tr> + <td><a href="#special-asterisk" id="special-asterisk" name="special-asterisk"><code>*</code></a></td> + <td> + <p>Cho phép kí tự trước nó lặp lại 0 lần hoặc nhiều lần. Tương đương với cách viết {0,}.</p> + + <p>Ví dụ, /bo*/ khớp với 'boooo' trong chuỗi "A ghost booooed" nhưng không khớp trong chuỗi "A birth warbled".</p> + </td> + </tr> + <tr> + <td><a href="#special-plus" id="special-plus" name="special-plus"><code>+</code></a></td> + <td> + <p>Cho phép kí tự trước nó lặp lại 1 lần hoặc nhiều lần. Tương đương với cách viết {1,}.</p> + + <p>Ví dụ, /a+/ khớp với 'a' trong chuỗi "candy" và khớp với tất cả kí tự a liền nhau trong chuỗi "caaaaaaandy".</p> + </td> + </tr> + <tr> + <td><a href="#special-questionmark" id="special-questionmark" name="special-questionmark"><code>?</code></a></td> + <td> + <p>Cho phép kí tự trước nó lặp lại 0 lần hoặc 1 lần duy nhất. Tương đương với cách viết {0,1}.</p> + + <p>Ví dụ, /e?le?/ khớp với 'el' trong chuỗi "angel" và 'le' trong chuỗi "angle" hay 'l' trong "oslo".</p> + + <p>Nếu sử dụng kí tự này ngay sau bất kì kí tự định lượng nào trong số *,+,? hay {}, đều làm bộ định lượng "chán ăn" (dừng so khớp sau ngay khi tìm được kí tự phù hợp), trái ngược với đức tính "tham lam" vốn sẵn của chúng (khớp tất cả kí tự chúng tìm thấy). Ví dụ, áp dụng biểu mẫu /\d+/ cho "123abc" ta được "123". Nhưng áp /\d+?/ cho chính chuỗi trên ta chỉ nhận được kết quả là "1".</p> + + <p>Bạn có thể đọc thêm trong mục x(?=y) và x(?!y) của bảng này.</p> + </td> + </tr> + <tr> + <td><a href="#special-dot" id="special-dot" name="special-dot"><code>.</code></a></td> + <td> + <p>Dấu . khớp với bất kì kí tự đơn nào ngoại trừ kí tự xuống dòng.</p> + + <p>Ví dụ, /.n/ khớp với 'an' và 'on' trong chuỗi "no, an apple is on the tree", nhưng không khớp với 'no'.</p> + </td> + </tr> + <tr> + <td><a href="#special-capturing-parentheses" id="special-capturing-parentheses" name="special-capturing-parentheses"><code>(x)</code></a></td> + <td> + <p>Khớp 'x' và nhớ kết quả so khớp này, như ví dụ ở dưới. Các dấu ngoặc tròn được gọi là các dấu ngoặc có nhớ.</p> + + <p>Biểu mẫu <code>/(foo) (bar) \1 \2/ khớp với 'foo' và 'bar'</code> trong chuỗi "foo bar foo bar". <code>\1</code> và <code>\2</code> trong mẫu khớp với 2 từ cuối.</p> + + <p>Chú ý rằng <code>\1</code>, <code>\2</code>, <code>\n</code> được sử dụng để so khớp các phần trong regex, nó đại diện cho nhóm so khớp đằng trước. Ví dụ: <code>/(foo) (bar) \1 \2/ tương đương với biểu thức /(foo) (bar) foo bar/.</code> </p> + + <p>Cú pháp <code>$1, $2, $n còn</code> được sử dụng trong việc thay thế các phần của một regex. Ví dụ: <code>'bar foo'.replace(/(...) (...)/, '$2 $1') </code>sẽ đảo vị trí 2 từ 'bar' và 'foo' cho nhau.</p> + </td> + </tr> + <tr> + <td><a href="#special-non-capturing-parentheses" id="special-non-capturing-parentheses" name="special-non-capturing-parentheses"><code>(?:x)</code></a></td> + <td> + <p>Khớp 'x' nhưng không nhớ kết quả so khớp. Những dấu ngoặc tròn được gọi là những dấu ngoặc không nhớ, nó cho phép bạn định nghĩa những biểu thức con cho những toán tử so khớp. Xem xét biểu thức đơn giản <code>/(?:foo){1,2}/. </code>Nếu biểu thức này được viết là <code>/foo{1,2}/</code>, <code>{1,2}</code> sẽ chỉ áp dụng cho kí tự 'o' ở cuối chuỗi 'foo'. Với những dấu ngoặc không nhớ, <code>{1,2} </code>sẽ áp dụng cho cả cụm 'foo'.</p> + </td> + </tr> + <tr> + <td><a href="#special-lookahead" id="special-lookahead" name="special-lookahead"><code>x(?=y)</code></a></td> + <td> + <p>Chỉ khớp 'x' nếu 'x' theo sau bởi 'y'.</p> + + <p>Ví dụ, <code>/Jack(?=Sprat)/ </code>chỉ<code> </code>khớp với 'Jack' nếu đằng sau nó là 'Sprat'. <code>/Jack(?=Sprat|Frost)/ </code>chỉ khớp 'Jack' nếu theo sau nó là 'Sprat' hoặc 'Frost'. Tuy nhiên, cả 'Sprat' và 'Frost' đều không phải là một phần của kết quả so khớp trả về.</p> + </td> + </tr> + <tr> + <td><a href="#special-negated-look-ahead" id="special-negated-look-ahead" name="special-negated-look-ahead"><code>x(?!y)</code></a></td> + <td> + <p>Chỉ khớp 'x' nếu 'x' <strong>không</strong> được theo sau bởi 'y'.</p> + + <p>Ví dụ: <code>/\d+(?!\.)/</code> chỉ khớp với số không có dấu <code>.</code> đằng sau. Biểu thức <code>/\d+(?!\.)/.exec("3.141") </code>cho kết quả là '141' mà không phải '3.141'.</p> + </td> + </tr> + <tr> + <td><a href="#special-or" id="special-or" name="special-or"><code>x|y</code></a></td> + <td> + <p>Khớp 'x' hoặc 'y'</p> + + <p>Ví dụ, <code>/green|red/ </code>khớp với 'green' trong chuỗi "green apple" và 'red' trong chuỗi "red apple".</p> + </td> + </tr> + <tr> + <td><a href="#special-quantifier" id="special-quantifier" name="special-quantifier"><code>{n}</code></a></td> + <td> + <p>Kí tự đứng trước phải xuất hiện n lần. n phải là một số nguyên dương.</p> + + <p>Ví dụ, <code>/a{2}/ </code>không khớp với 'a' trong "candy", nhưng nó khớp với tất cả kí tự 'a' trong "caandy", và khớp với 2 kí tự 'a' đầu tiên trong "caaandy".</p> + </td> + </tr> + <tr> + <td><a href="#special-quantifier-range" id="special-quantifier-range" name="special-quantifier-range"><code>{n,m}</code></a></td> + <td> + <p>Kí tự đứng trước phải xuất hiện từ n đến m lần. n và m là số nguyên dương và n <= m. Nếu m bị bỏ qua, nó tương đương như ∞.</p> + + <p>Ví dụ, <code>/a{1,3}/ không </code>khớp bất kì kí tự nào trong "cndy", kí tự 'a' trong "candy", 2 kí tự 'a' đầu tiên trong "caandy", và 3 kí tự 'a' đầu tiên trong "caaaaaaandy". Lưu ý là "caaaaaaandy" chỉ khớp với 3 kí tự 'a' đầu tiên mặc dù chuỗi đó chứa 7 kí tự 'a'.</p> + </td> + </tr> + <tr> + <td><a href="#special-character-set" id="special-character-set" name="special-character-set"><code>[xyz]</code></a></td> + <td> + <p>Lớp kí tự. Loại mẫu này dùng để so khớp với một kí tự bất kì trong dấu ngoặc vuông, bao gồm cả <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals#Unicode_escape_sequences" title="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals#Unicode_escape_sequences">escape sequences</a>. Trong lớp kí tự, dấu chấm (.) và dấu hoa thị (*) không còn là kí tự đặc biệt nên ta không cần kí tự thoát đứng trước nó. Bạn có thể chỉ định một khoảng kí tự bằng cách sử dụng một kí tự gạch nối (-) như trong ví dụ dưới đây:</p> + + <p>Mẫu <code>[a-d] </code>so khớp tương tự như mẫu <code>[abcd]</code>, khớp với 'b' trong "brisket" và 'c' trong "city". Mẫu <code>/[a-z.]+/ và /[\w.]+/ </code>khớp với toàn chuỗi "test.i.ng".</p> + </td> + </tr> + <tr> + <td><a href="#special-negated-character-set" id="special-negated-character-set" name="special-negated-character-set"><code>[^xyz]</code></a></td> + <td> + <p>Lớp kí tự phủ định. Khi kí tự ^ đứng đầu tiên trong dấu ngoặc vuông, nó phủ định mẫu này.</p> + + <p>Ví dụ, <code>[^abc] </code>tương tự như <code>[^a-c], khớp với 'r' trong "brisket" và 'h' trong "chop" là kí tự đầu tiên không thuộc khoảng a đến c.</code></p> + </td> + </tr> + <tr> + <td><a href="#special-backspace" id="special-backspace" name="special-backspace"><code>[\b]</code></a></td> + <td> + <p>Khớp với kí tự dịch lùi - backspace (U+0008). Bạn phải đặt trong dấu ngoặc vuông nếu muốn so khớp một kí tự dịch lùi. (Đừng nhầm lẫn với mẫu \b).</p> + </td> + </tr> + <tr> + <td><a href="#special-word-boundary" id="special-word-boundary" name="special-word-boundary"><code>\b</code></a></td> + <td> + <p>Khớp với kí tự biên. Kí tự biên là một kí tự giả, nó khớp với vị trí mà một kí tự không được theo sau hoặc đứng trước bởi một kí tự khác. Tương đương với mẫu <code>(^\w|\w$|\W\w|\w\W).</code> Lưu ý rằng một kí tự biên được khớp sẽ không bao gồm trong kết quả so khớp. Nói cách khác, độ dài của một kí tự biên là 0. (Đừng nhầm lẫn với mẫu [\b])</p> + + <p>Ví dụ:<br> + <code>/\bm/ </code>khớp với 'm' trong chuỗi "moon";<br> + <code>/oo\b/ </code>không khớp 'oo' trong chuỗi "moon", bởi vì 'oo' được theo sau bởi kí tự 'n';<br> + <code>/oon\b/ </code>khớp với 'oon' trong chuỗi "moon", bởi vì 'oon' ở cuối chuỗi nên nó không được theo sau bởi một kí tự; <br> + <code>/\w\b\w/ </code>sẽ không khớp với bất kì thứ gì, bởi vì một kí tự không thể theo sau một kí tự biên và một kí tự thường.</p> + + <div class="note"> + <p><strong>Chú ý:</strong> Engine biên dịch biểu thức chính quy trong Javascript định nghĩa một <a href="http://www.ecma-international.org/ecma-262/5.1/#sec-15.10.2.6">lớp kí tự</a> là những kí tự thường. Bất kỳ kí tự nào không thuộc lớp kí tự bị xem như một kí tự ngắt. Lớp kí tự này khá hạn chế: nó bao gồm bộ kí tự La-tinh cả hoa và thường, số thập phân và kí tự gạch dưới. Kí tự có dấu, như "é" hay "ü", không may, bị đối xử như một kí tự ngắt.</p> + </div> + </td> + </tr> + <tr> + <td><a href="#special-non-word-boundary" id="special-non-word-boundary" name="special-non-word-boundary"><code>\B</code></a></td> + <td> + <p>Khớp với kí tự không phải kí tự biên. Mẫu này khớp tại vị trí mà kí tự trước và kí tự sau nó cùng kiểu: hoặc cả hai là kí tự hoặc cả hai không phải là kí tự. Bắt đầu và kết thúc chuỗi không được xem là những kí tự.</p> + + <p>Ví dụ, <code>/\B../ </code>khớp với 'oo' trong "noonday", và<code> /y\B./ </code>khớp với 'ye' trong "possibly yesterday."</p> + </td> + </tr> + <tr> + <td><a href="#special-control" id="special-control" name="special-control"><code>\c<em>X</em></code></a></td> + <td> + <p>X là một kí tự trong khoảng A tới Z. Mẫu này khớp với một kí tự điều khiển trong một chuỗi.</p> + + <p>Ví dụ: <code>/\cM/</code> khớp với control-M (U+000D) trong chuỗi.</p> + </td> + </tr> + <tr> + <td><a href="#special-digit" id="special-digit" name="special-digit"><code>\d</code></a></td> + <td> + <p>Khớp với một kí tự số. Tương đương với mẫu [0-9].</p> + + <p>Ví dụ: <code>/\d/</code> hoặc <code>/[0-9]/ </code>khớp với '2' trong chuỗi "B2 is the suite number."</p> + </td> + </tr> + <tr> + <td><a href="#special-non-digit" id="special-non-digit" name="special-non-digit"><code>\D</code></a></td> + <td> + <p>Khớp với một kí tự không phải là kí tự số. Tương đương với mẫu [^0-9].</p> + + <p>Ví dụ; <code>/\D/</code> hoặc <code>/[^0-9]/</code> khớp với 'B' trong "B2 is the suite number."</p> + </td> + </tr> + <tr> + <td><a href="#special-form-feed" id="special-form-feed" name="special-form-feed"><code>\f</code></a></td> + <td>Khớp với kí tự phân trang - form feed (U+000C).</td> + </tr> + <tr> + <td><a href="#special-line-feed" id="special-line-feed" name="special-line-feed"><code>\n</code></a></td> + <td>Khớp với kí tự xuống dòng - line feed (U+000A).</td> + </tr> + <tr> + <td><a href="#special-carriage-return" id="special-carriage-return" name="special-carriage-return"><code>\r</code></a></td> + <td>Khớp với kí tự quay đầu dòng - carriage return (U+000D).</td> + </tr> + <tr> + <td><a href="#special-white-space" id="special-white-space" name="special-white-space"><code>\s</code></a></td> + <td> + <p>Khớp với một kí tự khoảng trắng, bao gồm trống - space, tab, phân trang - form feed, phân dòng - line feed. Tương đương với <code>[ \f\n\r\t\v\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]</code>.</p> + + <p>Ví dụ: <code>/\s\w*/</code> khớp với ' bar' trong "foo bar."</p> + </td> + </tr> + <tr> + <td><a href="#special-non-white-space" id="special-non-white-space" name="special-non-white-space"><code>\S</code></a></td> + <td> + <p>Khớp với một kí tự không phải khoảng trắng. Tương đương với <code>[^ \f\n\r\t\v\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]</code>.</p> + + <p>Ví dụ: <code>/\S\w*/</code> khớp với 'foo' trong chuỗi "foo bar."</p> + </td> + </tr> + <tr> + <td><a href="#special-tab" id="special-tab" name="special-tab"><code>\t</code></a></td> + <td>Khớp với kí tự tab (U+0009).</td> + </tr> + <tr> + <td><a href="#special-vertical-tab" id="special-vertical-tab" name="special-vertical-tab"><code>\v</code></a></td> + <td>Khớp với kí tự vertical tab (U+000B).</td> + </tr> + <tr> + <td><a href="#special-word" id="special-word" name="special-word"><code>\w</code></a></td> + <td> + <p>Khớp với tất cả kí tự là chữ, số và gạch dưới. Tương đương với mẫu <code>[A-Za-z0-9_]</code>.</p> + + <p>ví dụ, <code>/\w/</code> khớp với 'a' trong "apple," '5' trong "$5.28," và '3' trong "3D."</p> + </td> + </tr> + <tr> + <td><a href="#special-non-word" id="special-non-word" name="special-non-word"><code>\W</code></a></td> + <td> + <p>Khớp với tất cả kí tự không phải là chữ. Tương đương với mẫu <code>[^A-Za-z0-9_]</code>.</p> + + <p>ví dụ, <code>/\W/</code> hoặc <code>/[^A-Za-z0-9_]/</code> khớp với '%' trong "50%."</p> + </td> + </tr> + <tr> + <td><a href="#special-backreference" id="special-backreference" name="special-backreference"><code>\<em>n</em></code></a></td> + <td> + <p>Trong đó, n là một số nguyên dương, một tham chiếu ngược tới chuỗi khớp thứ n trong biểu thức (đếm từ trái sang, bắt đầu bằng 1).</p> + + <p>ví dụ, <code>/apple(,)\sorange\1/ </code>hay <code>/apple(,)\sorange,/</code> khớp với 'apple, orange,' trong chuỗi "apple, orange, cherry, peach."</p> + </td> + </tr> + <tr> + <td><a href="#special-null" id="special-null" name="special-null"><code>\0</code></a></td> + <td>Khớp với kí tự NULL (U+0000). Lưu ý: không được thêm bất kì một kí tự số nào sau 0, vì <code>\0<các-kí-tự-số></code> là một biểu diễn hệ bát phân <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals#Unicode_escape_sequences" title="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals#Unicode_escape_sequences">escape sequence</a>.</td> + </tr> + <tr> + <td><a href="#special-hex-escape" id="special-hex-escape" name="special-hex-escape"><code>\xhh</code></a></td> + <td>Khớp với kí tự với mã code là hh (2 số trong hệ thập lục phân)</td> + </tr> + <tr> + <td><a href="#special-unicode-escape" id="special-unicode-escape" name="special-unicode-escape"><code>\uhhhh</code></a></td> + <td>Khớp với kí tự có mã hhhh (4 số trong hệ thập lục phân).</td> + </tr> + </tbody> +</table> + +<p>Mã hóa escapse chuỗi người dùng nhập vào bằng một hàm thay thế đơn giản sử dụng biểu thức chính quy:</p> + +<pre class="brush: js">function escapeRegExp(string){ + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +}</pre> + +<h3 id="Sử_dụng_ngoặc_tròn">Sử dụng ngoặc tròn</h3> + +<p>Ngoặc tròn bao quanh bất kỳ phần nào của biểu thức chính quy sẽ khiến phần kết quả so khớp được nhớ. Mỗi lần nhớ, chuỗi con có thể được gọi lại để sử dụng, mô tả trong <span style="line-height: 1.5;"><a href="#Using_Parenthesized_Substring_Matches">Using Parenthesized Substring Matches</a>.</span></p> + +<p><span style="line-height: 1.5;">Ví dụ, mẫu </span><code>/Chapter (\d+)\.\d*/ </code>khớp đúng với 'Chapter ' theo sau bởi một hoặc nhiều kí tự số, sau nữa là một dấu chấm thập phân, cuối cùng có thể là 0 hoặc nhiều kí tự số. Bên cạnh đó, dấu ngoặc tròn được sử dụng để nhớ một hoặc nhiều kí tự số đầu tiên được khớp.</p> + +<p>Mẫu này được tìm thấy trong chuỗi "Open Chapter 4.3, paragraph 6", nhớ '4' nhưng không được tìm thấy trong chuỗi "Chapter 3 and 4", bởi vì chuỗi đó không có dấu chấm sau kí tự số '3'.</p> + +<p>Để so khớp một chuỗi con không nhớ, đặt ?: ở vị trí đầu tiên trong ngoặc. Ví dụ, <code>(?:\d+)</code> khớp với một hoặc nhiều kí tự số nhưng không nhớ kết quả so khớp.</p> + +<h2 id="Làm_việc_với_biểu_thức_chính_quy">Làm việc với biểu thức chính quy</h2> + +<p>Biểu thức chính quy được sử dụng với phương thức test và exec của lớp RegExp hoặc phương thức match, replace, search và split của chuỗi. Những phương thức này được giải thích chi tiết trong <a href="/en-US/docs/JavaScript/Reference" title="en-US/docs/JavaScript/Reference">JavaScript Reference</a>.</p> + +<table class="standard-table"> + <caption>Bảng 4.2 Những phương thức được sử dụng trong biểu thức chính quy</caption> + <thead> + <tr> + <th scope="col">Phương thức</th> + <th scope="col">Mô tả</th> + </tr> + </thead> + <tbody> + <tr> + <td><code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec" title="en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec">exec</a></code></td> + <td>Một phương thức của RegExp dùng để tìm kiếm chuỗi phù hợp với mẫu so khớp. Nó trả về một mảng chứa kết quả tìm kiếm.</td> + </tr> + <tr> + <td><code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/test" title="en-US/docs/JavaScript/Reference/Global_Objects/RegExp/test">test</a></code></td> + <td>Một phương thức của RegExp dùng để kiểm tra mẫu có khớp với chuỗi hay không. Nó trả về giá trị true hoặc false.</td> + </tr> + <tr> + <td><code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/match" title="en-US/docs/JavaScript/Reference/Global_Objects/String/match">match</a></code></td> + <td>Một phương thức của chuỗi dùng để tìm kiếm chuỗi phù hợp với mẫu so khớp. Nó trả về một mảng chứa kết quả tìm kiếm hoặc null nếu không tìm thấy.</td> + </tr> + <tr> + <td><code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/search" title="en-US/docs/JavaScript/Reference/Global_Objects/String/search">search</a></code></td> + <td>Một phương thức của chuỗi dùng để tìm kiếm chuỗi phù hợp với mẫu so khớp và trả về vị trí của chuỗi đó hoặc -1 nếu không tìm thấy.</td> + </tr> + <tr> + <td><code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/replace" title="en-US/docs/JavaScript/Reference/Global_Objects/String/replace">replace</a></code></td> + <td>Một phương thức của chuỗi dùng để tìm kiếm một chuỗi theo mẫu so khớp và thay thế chuỗi con được khớp với một chuỗi thay thế.</td> + </tr> + <tr> + <td><code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/split" title="en-US/docs/JavaScript/Reference/Global_Objects/String/split">split</a></code></td> + <td>Một phương thức của chuỗi dùng một biểu mẫu chính quy hoặc một chuỗi bất biến để ngắt chuỗi đó thành một mảng các chuỗi con.</td> + </tr> + </tbody> +</table> + +<p>Khi bạn muốn biết một mẫu có được tìm thấy trong chuỗi hay không, sử dụng phương thức test hoặc search; để lấy nhiều thông tin hơn (nhưng chậm hơn) sử dụng phương thức exec hoặc match.</p> + +<p>Như ví dụ dưới đây, phương thức exec được dùng để tìm chuỗi phù hợp theo mẫu so khớp.</p> + +<pre class="brush: js">var myRe = /d(b+)d/g; +var myArray = myRe.exec("cdbbdbsbz"); +</pre> + +<p>Nếu bạn không cần truy cập những thuộc tính khác của biểu thức chính quy, sử dụng cách sau:</p> + +<pre class="brush: js">var myArray = /d(b+)d/g.exec("cdbbdbsbz"); +</pre> + +<p>Nếu bạn muốn khởi tạo một biểu thức chính quy từ một chuỗi:</p> + +<pre class="brush: js">var myRe = new RegExp("d(b+)d", "g"); +var myArray = myRe.exec("cdbbdbsbz"); +</pre> + +<p>Với những mã này, so khớp thành công và trả về một mảng kết quả với những thuộc tính được liệt kê trong bảng dưới đây.</p> + +<table class="fullwidth-table"> + <caption>Bảng 4.3 Kết quả so khớp</caption> + <thead> + <tr> + <th scope="col">Đối tượng</th> + <th scope="col">Thuộc tính hoặc chỉ số</th> + <th scope="col">Mô tả</th> + <th scope="col">Trong vd này</th> + </tr> + </thead> + <tbody> + <tr> + <td rowspan="4"><code>myArray</code></td> + <td> </td> + <td>Chuỗi kết quả so khớp và toàn bộ chuỗi con được nhớ.</td> + <td><code>["dbbd", "bb"]</code></td> + </tr> + <tr> + <td><code>index</code></td> + <td>Vị trí của chuỗi tìm thấy, đếm từ 0</td> + <td><code>1</code></td> + </tr> + <tr> + <td><code>input</code></td> + <td>Chuỗi gốc được nhập vào</td> + <td><code>"cdbbdbsbz"</code></td> + </tr> + <tr> + <td><code>[0]</code></td> + <td>Những kí tự cuối cùng được khớp.</td> + <td><code>"dbbd"</code></td> + </tr> + <tr> + <td rowspan="2"><code>myRe</code></td> + <td><code>lastIndex</code></td> + <td>Vị trí nơi mà bắt đầu so khớp lần sau. (Thuộc tính này chỉ được gán nếu biểu thức chính quy sử dụng lựa chọn g, được mô tả trong <a href="#Advanced_Searching_With_Flags">Advanced Searching With Flags</a> ).</td> + <td><code>5</code></td> + </tr> + <tr> + <td><code>source</code></td> + <td>Chuỗi biểu thức chính quy, được cập nhật tại thời điểm biểu thức được tạo, không phải tại lúc thực thi.</td> + <td><code>"d(b+)d"</code></td> + </tr> + </tbody> +</table> + +<p>Như dạng thứ 2 của ví dụ trên, bạn có thể dùng một biểu thức chính quy được khởi tạo mà không gán nó tới một biến. Tuy nhiên, nếu bạn làm thế, mỗi lần xuất hiện là một biểu thức chính quy mới. Vì lí do này, nếu bạn không gán nó vào một biến, bạn sẽ không thể truy cập các thuộc tính của biểu thức chính quy đó nữa. Ví dụ bạn có đoạn script sau:</p> + +<pre class="brush: js">var myRe = /d(b+)d/g; +var myArray = myRe.exec("cdbbdbsbz"); +console.log("The value of lastIndex is " + myRe.lastIndex); +</pre> + +<p>Kết quả hiển thị là:</p> + +<pre>The value of lastIndex is 5 +</pre> + +<p>Tuy nhiên nếu bạn chạy:</p> + +<pre class="brush: js">var myArray = /d(b+)d/g.exec("cdbbdbsbz"); +console.log("The value of lastIndex is " + /d(b+)d/g.lastIndex); +</pre> + +<p>Thì kết quả hiển thị sẽ là:</p> + +<pre>The value of lastIndex is 0 +</pre> + +<p>Sự xuất hiện của <code>/d(b+)d/g </code>trong 2 lệnh trên là những đối tượng biểu thức chính quy khác nhau và vì thế có những giá trị khác nhau cho thuộc tính lastIndex. Nếu bạn cần truy cập những thuộc tính của một biểu thức chính quy, bạn nên gán nó tới một biến.</p> + +<h3 id="Sử_dụng_nhiều_dấu_ngoặc_tròn"><a id="Sử dụng nhiều dấu ngoặc tròn" name="Sử dụng nhiều dấu ngoặc tròn">Sử dụng nhiều dấu ngoặc tròn</a></h3> + +<p>Sử dụng nhiều ngoặc tròn trong một biểu thức chính quy cho ta nhiều kết quả so khớp tương ứng được nhớ. Cho ví dụ, <code>/a(b)c/</code> khớp với 'abc' và nhớ 'b'. Để gọi lại những kết quả so khớp, sử dụng những phần tử của mảng [1]..., [n].</p> + +<p>Số lượng các chuỗi con trong những ngoặc tròn là không giới hạn. Mảng trả về giữ lại tất cả mọi thứ được tìm thấy.</p> + +<h4 id="Ví_dụ">Ví dụ</h4> + +<p>Đoạn mã JavaScript dưới đây sử dụng phương thức <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/replace" title="en-US/docs/JavaScript/Reference/Global Objects/String/replace">replace()</a> </code>để giao hoán các từ trong chuỗi. Trong chuỗi thay thế, ta dùng $1 và $2 để chỉ các chuỗi khớp với mẫu trong ngoặc ở vị trí thứ 1 và 2.</p> + +<pre class="brush: js">var re = /(\w+)\s(\w+)/; +var str = "John Smith"; +var newstr = str.replace(re, "$2, $1"); +console.log(newstr); +</pre> + +<p>Kết quả hiển thị là: "Smith, John".</p> + +<h3 id="Tìm_kiếm_nâng_cao_với_cờ">Tìm kiếm nâng cao với cờ</h3> + +<p>Biểu thức chính quy có 4 cờ cho phép tìm kiếm toàn cục và hoa thường. Những cờ này có thể được đứng riêng hoặc đứng gần nhau, và được coi như một phần của biểu thức chính quy.</p> + +<table class="standard-table"> + <caption>Bảng 4.4 Cờ của biểu thức chính quy</caption> + <thead> + <tr> + <th scope="col">Cờ</th> + <th scope="col">Mô tả</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>g</code></td> + <td>Tìm kiếm toàn cục.</td> + </tr> + <tr> + <td>i</td> + <td>Tìm kiếm không phân biệt hoa thường.</td> + </tr> + <tr> + <td>m</td> + <td>Tìm đa dòng.</td> + </tr> + <tr> + <td>y</td> + <td>Thực thi một tìm kiếm "dính" - so khớp được bắt đầu ở vị trí hiện tại trong chuỗi mục tiêu.</td> + </tr> + </tbody> +</table> + +<p>{{ Fx_minversion_note(3, "Từ Firefox 3 đã hỗ trợ cờ y. Cờ y thất bại nếu so khớp không thành công ở vị trí hiện tại trong chuỗi mục tiêu.") }}</p> + +<p>Để sử dụng cờ trong biểu thức chính quy, dùng cú pháp này:</p> + +<pre class="brush: js">var re = /pattern/flags; +</pre> + +<p>hoặc</p> + +<pre class="brush: js">var re = new RegExp("pattern", "flags"); +</pre> + +<p>Lưu ý rằng cờ là một phần hợp thành một biểu thức chính quy. Chúng không thể được thêm hoặc gỡ bỏ sau đó.</p> + +<p>Ví dụ, <code>re = /\w+\s/g </code>tạo một biểu thức chính quy dùng để tìm kiếm một hoặc nhiều kí tự theo sau bởi một khoảng trắng, và nó tìm kiếm tổ hợp này xuyên suốt chuỗi mục tiêu.</p> + +<pre class="brush: js">var re = /\w+\s/g; +var str = "fee fi fo fum"; +var myArray = str.match(re); +console.log(myArray); +</pre> + +<p>Kết quả hiển thị là ["fee ", "fi ", "fo "].</p> + +<p>Trong ví dụ này, bạn cũng có thể thay thế dòng này:</p> + +<pre class="brush: js">var re = /\w+\s/g; +</pre> + +<p>bằng:</p> + +<pre class="brush: js">var re = new RegExp("\\w+\\s", "g"); +</pre> + +<p>và nhận được cùng một kết quả giống nhau.</p> + +<p>Cờ m được sử dụng để xác định rằng một chuỗi đầu vào nên được đối xử như nhiều dòng. Nếu dùng cờ này, so khớp ^ và $ ở đầu và cuối ở mọi dòng trong chuỗi đầu vào thay vì ở đầu và cuỗi của toàn bộ chuỗi.</p> + +<h2 id="Ví_dụ_minh_họa">Ví dụ minh họa</h2> + +<p>Các ví dụ sau đây cho thấy một số cách sử dụng các biểu thức chính quy.</p> + +<h3 id="Thay_đổi_thứ_tự_trong_một_chuỗi">Thay đổi thứ tự trong một chuỗi</h3> + +<p>Ví dụ sau đây minh họa sự cấu thành các biểu thức chính quy và việc sử dụng các phương thức<code> string.split()</code> và <code>string.Replace().</code> Nó làm sạch một chuỗi đầu vào được định dạng có chứa tên (first name ở vị trí đầu tiên) cách nhau bởi khoảng trống, các tab và chỉ một dấu chấm phẩy duy nhất. Cuối cùng, nó đảo ngược thứ tự tên (last name ở vị trí đầu tiên) và sắp xếp lại danh sách.</p> + +<pre class="brush: js">// The name string contains multiple spaces and tabs, +// and may have multiple spaces between first and last names. +var names = "Harry Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand "; + +var output = ["---------- Original String\n", names + "\n"]; + +// Prepare two regular expression patterns and array storage. +// Split the string into array elements. + +// pattern: possible white space then semicolon then possible white space +var pattern = /\s*;\s*/; + +// Break the string into pieces separated by the pattern above and +// store the pieces in an array called nameList +var nameList = names.split(pattern); + +// new pattern: one or more characters then spaces then characters. +// Use parentheses to "memorize" portions of the pattern. +// The memorized portions are referred to later. +pattern = /(\w+)\s+(\w+)/; + +// New array for holding names being processed. +var bySurnameList = []; + +// Display the name array and populate the new array +// with comma-separated names, last first. +// +// The replace method removes anything matching the pattern +// and replaces it with the memorized string—second memorized portion +// followed by comma space followed by first memorized portion. +// +// The variables $1 and $2 refer to the portions +// memorized while matching the pattern. + +output.push("---------- After Split by Regular Expression"); + +var i, len; +for (i = 0, len = nameList.length; i < len; i++){ + output.push(nameList[i]); + bySurnameList[i] = nameList[i].replace(pattern, "$2, $1"); +} + +// Display the new array. +output.push("---------- Names Reversed"); +for (i = 0, len = bySurnameList.length; i < len; i++){ + output.push(bySurnameList[i]); +} + +// Sort by last name, then display the sorted array. +bySurnameList.sort(); +output.push("---------- Sorted"); +for (i = 0, len = bySurnameList.length; i < len; i++){ + output.push(bySurnameList[i]); +} + +output.push("---------- End"); + +console.log(output.join("\n")); +</pre> + +<h3 id="Sử_dụng_những_kí_tự_đặc_biệt_để_xác_thực_đầu_vào">Sử dụng những kí tự đặc biệt để xác thực đầu vào</h3> + +<p>Trong ví dụ dưới đây, ta mong chờ người dùng nhập một số điện thoại. Khi người dùng ấn nút "Check", đoạn script sẽ kiểm tra tính xác thực của số vừa nhập. Nếu số đó hợp lệ (khớp với chuỗi kí tự được xác định bởi biểu thức chính quy), website sẽ hiển thị một tin nhắn cảm ơn người dùng và xác nhận số đó. Nếu số đó không hợp lệ, website sẽ thông báo người dùng rằng số điện thoại vừa nhập không hợp lệ.</p> + +<p><code>var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/;</code></p> + +<p>Trong mẫu ngoặc tròn không nhớ (<code>?:</code>, biểu thức chính quy tìm 3 kí tự số <code>\d{3}</code> hoặc <code>|</code> 3 kí tự số trong cặp ngoặc tròn, (kết thúc mẫu ngoặc tròn không nhớ), sau đó là một kí tự gạch ngang, dấu chéo ngược, hoặc dấu chấm thập phân, và khi tìm thấy, nhớ kí tự vừa tìm được, tìm tiếp 3 kí tự số, theo sau là một so khớp được nhớ ở lần đầu tiên <code>([-\/\.]), </code>cuối cùng là 4 kí tự số.</p> + +<p>Sự kiện change được kích hoạt khi người dùng nhấp Enter.</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> + <meta http-equiv="Content-Script-Type" content="text/javascript"> + <script type="text/javascript"> + var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/; + function testInfo(phoneInput){ + var OK = re.exec(phoneInput.value); + if (!OK) + window.alert(OK.input + " isn't a phone number with area code!"); + else + window.alert("Thanks, your phone number is " + OK[0]); + } + </script> + </head> + <body> + <p>Enter your phone number (with area code) and then click "Check". + <br>The expected format is like ###-###-####.</p> + <form action="#"> + <input id="phone"><button onclick="testInfo(document.getElementById('phone'));">Check</button> + </form> + </body> +</html> +</pre> + +<div>{{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}</div> diff --git a/files/vi/web/javascript/guide/text_formatting/index.html b/files/vi/web/javascript/guide/text_formatting/index.html new file mode 100644 index 0000000000..c3a09c6617 --- /dev/null +++ b/files/vi/web/javascript/guide/text_formatting/index.html @@ -0,0 +1,250 @@ +--- +title: Text formatting +slug: Web/JavaScript/Guide/Text_formatting +translation_of: Web/JavaScript/Guide/Text_formatting +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Numbers_and_dates", "Web/JavaScript/Guide/Regular_Expressions")}}</div> +<p class="summary">Chương này giới thiệu cách làm việc với các chuỗi và văn bản trong JavaScript.</p> + +<h2 id="Dây">Dây</h2> + +<p>Kiểu <a href="/en-US/docs/Glossary/String">chuỗi</a> của JavaScript được sử dụng để thể hiện dữ liệu văn bản. Nó là một tập hợp các "phần tử" của các giá trị nguyên không dấu 16 bit (đơn vị mã UTF-16). Mỗi phần tử trong Chuỗi chiếm một vị trí trong Chuỗi. Phần tử đầu tiên là ở chỉ số 0, phần tử tiếp theo ở chỉ số 1, v.v. Độ dài của Chuỗi là số phần tử trong đó. Bạn có thể tạo chuỗi bằng cách sử dụng chuỗi ký tự hoặc chuỗi đối tượng.</p> + +<div class="hidden">THẬN TRỌNG: nếu bạn chỉnh sửa trang này, không bao gồm bất kỳ ký tự nào trên U + FFFF, cho đến khi lỗi MDN 857438 được khắc phục ( <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=857438">https://ormszilla.mozilla.org/show_orms.cgi?id=857438</a> ).</div> + +<h3 id="Chuỗi_ký_tự">Chuỗi ký tự</h3> + +<p>Bạn có thể tạo các chuỗi đơn giản bằng cách sử dụng dấu ngoặc đơn hoặc dấu ngoặc kép:</p> + +<pre class="brush: js notranslate">'foo' +"quán ba"</pre> + +<p>Các chuỗi nâng cao hơn có thể được tạo bằng các chuỗi thoát:</p> + +<h4 id="Trình_tự_thoát_thập_lục_phân">Trình tự thoát thập lục phân</h4> + +<p>The number after \x is interpreted as a <a href="https://en.wikipedia.org/wiki/Hexadecimal">hexadecimal</a> number.</p> + +<pre class="brush: js notranslate">'\xA9' // "©" +</pre> + +<h4 id="Unicode_escape_sequences">Unicode escape sequences</h4> + +<p>The Unicode escape sequences require at least four hexadecimal digits following <code>\u</code>.</p> + +<pre class="brush: js notranslate">'\u00A9' // "©"</pre> + +<h4 id="Unicode_code_point_escapes">Unicode code point escapes</h4> + +<p>New in ECMAScript 2015. With Unicode code point escapes, any character can be escaped using hexadecimal numbers so that it is possible to use Unicode code points up to <code>0x10FFFF</code>. With simple Unicode escapes it is often necessary to write the surrogate halves separately to achieve the same result.</p> + +<p>See also {{jsxref("String.fromCodePoint()")}} or {{jsxref("String.prototype.codePointAt()")}}.</p> + +<pre class="brush: js notranslate">'\u{2F804}' + +// the same with simple Unicode escapes +'\uD87E\uDC04'</pre> + +<h3 id="String_objects">String objects</h3> + +<p>The {{jsxref("String")}} object is a wrapper around the string primitive data type.</p> + +<pre class="brush: js notranslate">const foo = new String('foo'); // Creates a String object +console.log(foo); // Displays: <span><span>[String: 'foo']</span></span> +typeof foo; // Returns 'object' +</pre> + +<p>You can call any of the methods of the <code>String</code> object on a string literal value—JavaScript automatically converts the string literal to a temporary <code>String</code> object, calls the method, then discards the temporary <code>String</code> object. You can also use the <code>String.length</code> property with a string literal.</p> + +<p>You should use string literals unless you specifically need to use a <code>String</code> object, because <code>String</code> objects can have counterintuitive behavior. For example:</p> + +<pre class="brush: js notranslate">const firstString = '2 + 2'; // Creates a string literal value +const secondString = new String('2 + 2'); // Creates a String object +eval(firstString); // Returns the number 4 +eval(secondString); // Returns the string "2 + 2"</pre> + +<p>A <code>String</code> object has one property, <code>length</code>, that indicates the number of UTF-16 code units in the string. For example, the following code assigns <code>helloLength</code> the value 13, because "Hello, World!" has 13 characters, each represented by one UTF-16 code unit. You can access each code unit using an array bracket style. You can't change individual characters because strings are immutable array-like objects:</p> + +<pre class="brush: js notranslate">const hello = 'Hello, World!'; +const helloLength = hello.length; +hello[0] = 'L'; // This has no effect, because strings are immutable +hello[0]; // This returns "H" +</pre> + +<p>Characters whose Unicode scalar values are greater than U+FFFF (such as some rare Chinese/Japanese/Korean/Vietnamese characters and some emoji) are stored in UTF-16 with two surrogate code units each. For example, a string containing the single character U+1F600 "Emoji grinning face" will have length 2. Accessing the individual code units in such a string using brackets may have undesirable consequences such as the formation of strings with unmatched surrogate code units, in violation of the Unicode standard. (Examples should be added to this page after MDN bug 857438 is fixed.) See also {{jsxref("String.fromCodePoint()")}} or {{jsxref("String.prototype.codePointAt()")}}.</p> + +<p>A <code>String</code> object has a variety of methods: for example those that return a variation on the string itself, such as <code>substring</code> and <code>toUpperCase</code>.</p> + +<p>The following table summarizes the methods of {{jsxref("String")}} objects.</p> + +<table class="standard-table"> + <caption> + <h4 id="Methods_of_String">Methods of <code>String</code></h4> + </caption> + <thead> + <tr> + <th scope="col">Method</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{jsxref("String.charAt", "charAt")}}, {{jsxref("String.charCodeAt", "charCodeAt")}}, {{jsxref("String.codePointAt", "codePointAt")}}</td> + <td>Return the character or character code at the specified position in string.</td> + </tr> + <tr> + <td>{{jsxref("String.indexOf", "indexOf")}}, {{jsxref("String.lastIndexOf", "lastIndexOf")}}</td> + <td>Return the position of specified substring in the string or last position of specified substring, respectively.</td> + </tr> + <tr> + <td>{{jsxref("String.startsWith", "startsWith")}}, {{jsxref("String.endsWith", "endsWith")}}, {{jsxref("String.includes", "includes")}}</td> + <td>Returns whether or not the string starts, ends or contains a specified string.</td> + </tr> + <tr> + <td>{{jsxref("String.concat", "concat")}}</td> + <td>Combines the text of two strings and returns a new string.</td> + </tr> + <tr> + <td>{{jsxref("String.fromCharCode", "fromCharCode")}}, {{jsxref("String.fromCodePoint", "fromCodePoint")}}</td> + <td>Constructs a string from the specified sequence of Unicode values. This is a method of the String class, not a String instance.</td> + </tr> + <tr> + <td>{{jsxref("String.split", "split")}}</td> + <td>Splits a <code>String</code> object into an array of strings by separating the string into substrings.</td> + </tr> + <tr> + <td>{{jsxref("String.slice", "slice")}}</td> + <td>Extracts a section of a string and returns a new string.</td> + </tr> + <tr> + <td>{{jsxref("String.substring", "substring")}}, {{jsxref("String.substr", "substr")}}</td> + <td>Return the specified subset of the string, either by specifying the start and end indexes or the start index and a length.</td> + </tr> + <tr> + <td>{{jsxref("String.match", "match")}}, {{jsxref("String.matchAll", "matchAll")}}, {{jsxref("String.replace", "replace")}}, {{jsxref("String.search", "search")}}</td> + <td>Work with regular expressions.</td> + </tr> + <tr> + <td>{{jsxref("String.toLowerCase", "toLowerCase")}}, {{jsxref("String.toUpperCase", "toUpperCase")}}</td> + <td> + <p>Return the string in all lowercase or all uppercase, respectively.</p> + </td> + </tr> + <tr> + <td>{{jsxref("String.normalize", "normalize")}}</td> + <td>Returns the Unicode Normalization Form of the calling string value.</td> + </tr> + <tr> + <td>{{jsxref("String.repeat", "repeat")}}</td> + <td>Returns a string consisting of the elements of the object repeated the given times.</td> + </tr> + <tr> + <td>{{jsxref("String.trim", "trim")}}</td> + <td>Trims whitespace from the beginning and end of the string.</td> + </tr> + </tbody> +</table> + +<h3 id="Multi-line_template_literals">Multi-line template literals</h3> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Template_literals">Template literals</a> are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them.</p> + +<p>Template literals are enclosed by the back-tick (` `) (<a class="external external-icon" href="https://en.wikipedia.org/wiki/Grave_accent">grave accent</a>) character instead of double or single quotes. Template literals can contain place holders. These are indicated by the Dollar sign and curly braces (<code>${expression}</code>).</p> + +<h4 id="Multi-lines">Multi-lines</h4> + +<p>Any new line characters inserted in the source are part of the template literal. Using normal strings, you would have to use the following syntax in order to get multi-line strings:</p> + +<pre class="brush: js notranslate">console.log('string text line 1\n\ +string text line 2'); +// "string text line 1 +// string text line 2"</pre> + +<p>To get the same effect with multi-line strings, you can now write:</p> + +<pre class="brush: js notranslate">console.log(`string text line 1 +string text line 2`); +// "string text line 1 +// string text line 2"</pre> + +<h4 id="Embedded_expressions">Embedded expressions</h4> + +<p>In order to embed expressions within normal strings, you would use the following syntax:</p> + +<pre class="brush: js notranslate">const five = 5; +const ten = 10; +console.log('Fifteen is ' + (five + ten) + ' and not ' + (2 * five + ten) + '.'); +// "Fifteen is 15 and not 20."</pre> + +<p>Now, with template literals, you are able to make use of the syntactic sugar making substitutions like this more readable:</p> + +<pre class="brush: js notranslate">const five = 5; +const ten = 10; +console.log(`Fifteen is ${five + ten} and not ${2 * five + ten}.`); +// "Fifteen is 15 and not 20."</pre> + +<p>For more information, read about <a href="/en-US/docs/Web/JavaScript/Reference/Template_literals">Template literals</a> in the <a href="/en-US/docs/Web/JavaScript/Reference">JavaScript reference</a>.</p> + +<h2 id="Internationalization">Internationalization</h2> + +<p>The {{jsxref("Intl")}} object is the namespace for the ECMAScript Internationalization API, which provides language sensitive string comparison, number formatting, and date and time formatting. The constructors for {{jsxref("Collator")}}, {{jsxref("NumberFormat")}}, and {{jsxref("DateTimeFormat")}} objects are properties of the <code>Intl</code> object.</p> + +<h3 id="Date_and_time_formatting">Date and time formatting</h3> + +<p>The {{jsxref("DateTimeFormat")}} object is useful for formatting date and time. The following formats a date for English as used in the United States. (The result is different in another time zone.)</p> + +<pre class="brush: js notranslate">const msPerDay = 24 * 60 * 60 * 1000; + +// July 17, 2014 00:00:00 UTC. +const july172014 = new Date(msPerDay * (44 * 365 + 11 + 197)); + +const options = { year: '2-digit', month: '2-digit', day: '2-digit', + hour: '2-digit', minute: '2-digit', timeZoneName: 'short' }; +const americanDateTime = new Intl.DateTimeFormat('en-US', options).format; + +console.log(americanDateTime(july172014)); // 07/16/14, 5:00 PM PDT +</pre> + +<h3 id="Number_formatting">Number formatting</h3> + +<p>The {{jsxref("NumberFormat")}} object is useful for formatting numbers, for example currencies.</p> + +<pre class="brush: js notranslate">const gasPrice = new Intl.NumberFormat('en-US', + { style: 'currency', currency: 'USD', + minimumFractionDigits: 3 }); + +console.log(gasPrice.format(5.259)); // $5.259 + +const hanDecimalRMBInChina = new Intl.NumberFormat('zh-CN-u-nu-hanidec', + { style: 'currency', currency: 'CNY' }); + +console.log(hanDecimalRMBInChina.format(1314.25)); // ¥ 一,三一四.二五 +</pre> + +<h3 id="Collation">Collation</h3> + +<p>The {{jsxref("Collator")}} object is useful for comparing and sorting strings.</p> + +<p>For example, there are actually two different sort orders in German, <em>phonebook</em> and <em>dictionary</em>. Phonebook sort emphasizes sound, and it’s as if “ä”, “ö”, and so on were expanded to “ae”, “oe”, and so on prior to sorting.</p> + +<pre class="brush: js notranslate">const names = ['Hochberg', 'Hönigswald', 'Holzman']; + +const germanPhonebook = new Intl.Collator('de-DE-u-co-phonebk'); + +// as if sorting ["Hochberg", "Hoenigswald", "Holzman"]: +console.log(names.sort(germanPhonebook.compare).join(', ')); +// logs "Hochberg, Hönigswald, Holzman" +</pre> + +<p>Some German words conjugate with extra umlauts, so in dictionaries it’s sensible to order ignoring umlauts (except when ordering words differing <em>only</em> by umlauts: <em>schon</em> before <em>schön</em>).</p> + +<pre class="brush: js notranslate">const germanDictionary = new Intl.Collator('de-DE-u-co-dict'); + +// as if sorting ["Hochberg", "Honigswald", "Holzman"]: +console.log(names.sort(germanDictionary.compare).join(', ')); +// logs "Hochberg, Holzman, Hönigswald" +</pre> + +<p>For more information about the {{jsxref("Intl")}} API, see also <a href="https://hacks.mozilla.org/2014/12/introducing-the-javascript-internationalization-api/">Introducing the JavaScript Internationalization API</a>.</p> + +<div>{{PreviousNext("Web/JavaScript/Guide/Numbers_and_dates", "Web/JavaScript/Guide/Regular_Expressions")}}</div> diff --git a/files/vi/web/javascript/guide/using_promises/index.html b/files/vi/web/javascript/guide/using_promises/index.html new file mode 100644 index 0000000000..8ed6befe37 --- /dev/null +++ b/files/vi/web/javascript/guide/using_promises/index.html @@ -0,0 +1,329 @@ +--- +title: Sử dụng Promise +slug: Web/JavaScript/Guide/Using_promises +tags: + - Hướng dẫn + - JavaScript + - Promise + - bất đồng bộ + - trình độ trung cấp +translation_of: Web/JavaScript/Guide/Using_promises +--- +<div>{{jsSidebar("JavaScript Guide")}}{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}</div> + +<p class="summary">{{jsxref("Promise")}} là một đối tượng thể hiện cho sự hoàn thành hoặc thất bại của một tiến trình bất đồng bộ. Vì đa số chúng ta là người sử dụng Promise được tạo sẵn, bài viết này sẽ hướng dẫn cách sử dụng Promise trước khi hướng dẫn cách tạo ra chúng.</p> + +<p>Về cơ bản, một promise là một đối tượng trả về mà bạn gắn callback vào nó thay vì truyền callback vào trong một hàm.</p> + +<p>Giả sử chúng ta có một hàm, <code>createAudioFileAsync()</code>, mà nó sẽ tạo ra một file âm thanh từ config object và hai hàm callback một cách bất đồng bộ, một hàm sẽ được gọi khi file âm thanh được tạo thành công, và một hàm được gọi khi có lỗi xảy ra.</p> + +<p>Sau đây là code ví dụ sử dụng <code>createAudioFileAsync()</code>:</p> + +<pre class="brush: js line-numbers language-js">function successCallback(result) { + console.log("Audio file ready at URL: " + result); +} + +function failureCallback(error) { + console.log("Error generating audio file: " + error); +} + +createAudioFileAsync(audioSettings, successCallback, failureCallback); +</pre> + +<p>Thay vì như trên, các hàm bất đồng bộ hiện đại sẽ trả về đối tượng promise mà bạn sẽ gắn callback vào nó:</p> + +<p>Nếu hàm <code>createAudioFileAsync()</code> được viết lại sử dụng promise, thì việc sử dụng nó sẽ chỉ đơn giản như sau:</p> + +<pre class="brush: js">createAudioFileAsync(audioSettings).then(successCallback, failureCallback);</pre> + +<p>Nếu viết dài dòng hơn thì sẽ là:</p> + +<pre class="brush: js line-numbers language-js">const promise = createAudioFileAsync(audioSettings); +promise.then(successCallback, failureCallback);</pre> + +<p>Chúng ta gọi đây là <em>một lời gọi hàm bất đồng bộ</em> (<em>asynchronous function call)</em>. Cách tiếp cận này có nhiều ưu điểm, mà chúng ta sẽ lần lượt xem xét bên dưới.</p> + +<h2 id="Sự_đảm_bảo">Sự đảm bảo</h2> + +<p>Không như cách truyền callback kiểu cũ, một promise có những đảm bảo như sau:</p> + +<ul> + <li>Callback sẽ không bao giờ được gọi trước khi <a href="/en-US/docs/Web/JavaScript/EventLoop#Run-to-completion">hoàn tất lượt chạy</a> của một <em>JavaScript event loop</em>.</li> + <li>Callback được thêm vào <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> <em>sau khi</em> tiến trình bất đồng bộ đã hoàn thành vẫn được gọi, và theo nguyên tắc ở trên.</li> + <li>Nhiều callback có thể được thêm vào bằng cách gọi <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> nhiều lần. Mỗi callback sẽ được gọi lần lượt, theo thứ tự mà chúng được thêm vào.</li> +</ul> + +<p>Một trong những đặc tính tuyệt vời của promise là <strong>chaining</strong> (gọi nối).</p> + +<h2 id="Chaining_(gọi_nối)">Chaining (gọi nối)</h2> + +<p>Có một nhu cầu phổ biến đó là thực thi hai hay nhiều tiến trình bất đồng độ liên tiến nhau, cái sau bắt đầu ngay khi cái trước hoàn tất, với giá trị truyền vào là kết quả từ bước trước đó. Mục tiêu này có thể đạt được với một <em>chuỗi promise</em> (<strong>promise chain</strong>).</p> + +<p>Sau đây là cách nó hoạt động: hàm <code>then()</code> trả về một <strong>promise mới</strong>, khác với hàm ban đầu:</p> + +<pre class="brush: js">const promise = doSomething(); +const promise2 = promise.then(successCallback, failureCallback); +</pre> + +<p>hoặc</p> + +<pre class="brush: js">const promise2 = doSomething().then(successCallback, failureCallback); +</pre> + +<p>Promise thứ hai (<code>promise2</code>) không chỉ đại diện cho việc hoàn thành <code>doSomething()</code> mà còn cho cả <code>successCallback</code> hoặc <code>failureCallback</code> mà bạn đưa vào, mà chúng có thể là những hàm bất đồng bộ khác trả về promise. Trong trường hợp đó, bất kỳ callback nào được thêm vào cho <code>promise2</code> cũng sẽ được xếp phía sau promise trả về bởi một trong hai <code>successCallback</code> hoặc <code>failureCallback</code>.</p> + +<p>Tóm lại, mỗi promise đại diện cho việc hoàn tất của một bước bất đồng bộ trong chuỗi.</p> + +<p>Trước khi có promise, kết quả của việc thực hiện một chuỗi các thao tác bất đồng bộ theo cách cũ là một "thảm họa" kim tự tháp callback:</p> + +<pre class="brush: js">doSomething(function(result) { + doSomethingElse(result, function(newResult) { + doThirdThing(newResult, function(finalResult) { + console.log('Got the final result: ' + finalResult); + }, failureCallback); + }, failureCallback); +}, failureCallback); +</pre> + +<p>Thay vào đó, với cách tiếp cận hiện đại, chúng ta sẽ gắn các callback vào các promise trả về, tạo thành một chuỗi promise:</p> + +<pre class="brush: js">doSomething().then(function(result) { + return doSomethingElse(result); +}) +.then(function(newResult) { + return doThirdThing(newResult); +}) +.then(function(finalResult) { + console.log('Got the final result: ' + finalResult); +}) +.catch(failureCallback); +</pre> + +<p>Tham số cho <code>then</code> là không bắt buộc, và <code>catch(failureCallback)</code> là cách viết gọn của <code>then(null, failureCallback)</code>. Bạn có thể thấy chuỗi promise dùng với <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">arrow function</a> như sau:</p> + +<pre class="brush: js">doSomething() +.then(result => doSomethingElse(result)) +.then(newResult => doThirdThing(newResult)) +.then(finalResult => { + console.log(`Got the final result: ${finalResult}`); +}) +.catch(failureCallback); +</pre> + +<p><strong>Quan trọng:</strong> hãy nhớ luôn trả về kết quả, nếu không, callback sẽ không nhận được kết quả từ promise trước đó (với arrow functions <code>() => x</code> được rút gọn từ <code>() => { return x; }</code>)</p> + +<h3 id="Gọi_nối_sau_hàm_catch">Gọi nối sau hàm catch</h3> + +<p>Bạn có thể tiếp tục gọi chuỗi <code>then</code> sau một hàm bắt lỗi <code>catch</code>. Điều này cho phép code của bạn luôn thực hiện một thao tác nào đó cho dù đã có lỗi xảy ra ở một bước nào đó trong chuỗi. Hãy xem ví dụ sau:</p> + +<pre class="brush: js">new Promise((resolve, reject) => { + console.log('Initial'); + + resolve(); +}) +.then(() => { + throw new Error('Something failed'); + + console.log('Do this'); +}) +.catch(() => { + console.log('Do that'); +}) +.then(() => { + console.log('Do this, no matter what happened before'); +}); +</pre> + +<p>Đoạn code này sẽ log ra những dòng sau:</p> + +<pre>Initial +Do that +Do this, no matter what happened before +</pre> + +<p><strong>Ghi chú:</strong> Dòng text <q>Do this</q> không hiển thị bởi vì Error <q>Something failed</q> đã xảy ra trước và gây lỗi trong chuỗi promise.</p> + +<h2 id="Xử_lý_lỗi_tập_trung">Xử lý lỗi tập trung</h2> + +<p>Bạn hãy nhớ lại đoạn code kim tự tháp thảm họa ở trên, có đến 3 lần hàm <code>failureCallback</code> được sử dụng. Trong khi đó, bạn chỉ cần khai báo một lần vào cuối chuỗi promise:</p> + +<pre class="brush: js">doSomething() +.then(result => doSomethingElse(result)) +.then(newResult => doThirdThing(newResult)) +.then(finalResult => console.log(`Got the final result: ${finalResult}`)) +.catch(failureCallback); +</pre> + +<p>Về căn bản, một chuỗi promise sẽ dừng lại nếu có lỗi xảy ra, và nó sẽ truy xuống dưới cuối chuỗi để tìm và gọi hàm xử lý lỗi <code>catch</code>. Cách hoạt động này khá giống với cách thức hoạt động của <code>try catch</code> của code đồng bộ:</p> + +<pre class="brush: js">try { + const result = syncDoSomething(); + const newResult = syncDoSomethingElse(result); + const finalResult = syncDoThirdThing(newResult); + console.log(`Got the final result: ${finalResult}`); +} catch(error) { + failureCallback(error); +} +</pre> + +<p>Và vì lý do trên, <code>try catch</code> cũng được sử dụng để bắt lỗi cho code bất đồng bộ khi viết với cú pháp <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a> của ECMAScript 2017.</p> + +<pre class="brush: js">async function foo() { + try { + const result = await doSomething(); + const newResult = await doSomethingElse(result); + const finalResult = await doThirdThing(newResult); + console.log(`Got the final result: ${finalResult}`); + } catch(error) { + failureCallback(error); + } +} +</pre> + +<p>Cú pháp trên được xây dựng từ Promise, VD: <code>doSomething()</code> chính là hàm được viết với Promise ở trên. Bạn có thể đọc thêm về cú pháp đó <a href="https://developers.google.com/web/fundamentals/getting-started/primers/async-functions">ở đây</a>.</p> + +<p>Promise giúp giải quyết một hạn chế cơ bản của kim tự tháp callback, đó là cho phép bắt được tất cả các loại lỗi, từ những lỗi <em>throw Error</em> cho đến lỗi về cú pháp lập trình. Điều này rất cần thiết cho việc phối hợp các hàm xử lý bất đồng bộ.</p> + +<h2 id="Tạo_Promise_từ_API_có_kiểu_callback_cũ">Tạo Promise từ API có kiểu callback cũ</h2> + +<p>Một {{jsxref("Promise")}} có thể được tạo mới từ đầu bằng cách sử dụng hàm constructor. Tuy nhiên cách này thường chỉ dùng để bọc lại API kiểu cũ.</p> + +<p>Trong môi trường lý tưởng, tất cả các hàm bất đồng bộ đều trả về promise. Tuy nhiên vẫn còn nhiều API yêu cầu hàm callback được truyền vào theo kiểu cũ. Ví dụ điển hình nhất chính là hàm {{domxref("WindowTimers.setTimeout", "setTimeout()")}}:</p> + +<pre class="brush: js">setTimeout(() => saySomething("10 seconds passed"), 10000); +</pre> + +<p>Trộn lẫn callback và promise có nhiều vấn đề tiềm ẩn. Nếu hàm <code>saySomething()</code> xảy ra lỗi bên trong nó, sẽ không có gì bắt được lỗi này. <code>setTimeout</code> là để đổ lỗi cho điều này.</p> + +<p>May mắn là chúng ta có thể bọc <code>setTimeout</code> lại với promise. Cách làm tốt nhất là bọc hàm có vấn đề ở cấp thấp nhất, để rồi sau đó chúng ta không phải gọi nó trực tiếp nữa:</p> + +<pre class="brush: js">const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); + +wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback); +</pre> + +<p>Về căn bản, constructor của Promise nhận vào một hàm thực thi với hai tham số hàm resolve và reject để chúng ta có thể giải quyết hoặc từ chối promise một cách thủ công. Bởi vì hàm <code>setTimeout()</code> không bao giờ gây ra lỗi, chúng ta bỏ qua reject trong trường hợp này.</p> + +<h2 id="Phối_hợp_các_Promise">Phối hợp các Promise</h2> + +<p>{{jsxref("Promise.resolve()")}} và {{jsxref("Promise.reject()")}} là những phương thức để lấy nhanh một promise đã được giải quyết hoặc từ chối sẵn. Những phương thức này có thể hữu dụng trong một số trường hợp.</p> + +<p>{{jsxref("Promise.all()")}} và {{jsxref("Promise.race()")}} là hai hàm tiện ích dùng để phối hợp các thao tác bất đồng bộ chạy song song.</p> + +<p>Chúng ta có thể cho các tiến trình bất đồng bộ bắt đầu song song và chờ cho đến khi tất cả đều hoàn tất như sau:</p> + +<pre class="brush: js">Promise.all([func1(), func2(), func3()]) +.then(([result1, result2, result3]) => { /* use result1, result2 and result3 */ }); +</pre> + +<p>Việc phối hợp các tiến trình bất đồng bộ diễn ra tuần tự không có sẵn tiện ích nhưng có thể viết mẹo với <code>reduce</code> như sau:</p> + +<pre class="brush: js">[func1, func2, func3].reduce((p, f) => p.then(f), Promise.resolve()) +.then(result3 => { /* use result3 */ }); +</pre> + +<p>Về cơ bản, chúng ta đang rút gọn (<em>reduce</em>, tạm dịch) một mảng các hàm bất đồng bộ thành một chuỗi promise: <code>Promise.resolve().then(func1).then(func2).then(func3);</code></p> + +<p>Thao tác trên có thể được viết thành một hàm dùng lại được, như cách chúng ta hay làm trong <em>functional programming</em>:</p> + +<pre class="brush: js">const applyAsync = (acc,val) => acc.then(val); +const composeAsync = (...funcs) => x => funcs.reduce(applyAsync, Promise.resolve(x));</pre> + +<p>Hàm <code>composeAsync()</code> sẽ nhận vào tham số là các hàm xử lý bất đồng bộ với số lượng bất kỳ, và trả và một hàm mới mà khi gọi, nó nhận vào một giá trị ban đầu mà giá trị này sẽ được truyền vào tuần tự qua các hàm xử lý bất đồng bộ:</p> + +<pre class="brush: js">const transformData = composeAsync(func1, func2, func3); +const result3 = transformData(data); +</pre> + +<p>Trong ECMAScript 2017, việc phối hợp tuần tự các promise có thể thực hiện đơn giản hơn với async/await:</p> + +<pre class="brush: js">let result; +for (const f of [func1, func2, func3]) { + result = await f(result); +} +/* use last result (i.e. result3) */ +</pre> + +<h2 id="Thời_điểm_thực_thi">Thời điểm thực thi</h2> + +<p>Để nhất quán và tránh những bất ngờ, các hàm truyền vào cho <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> sẽ không bao giờ được thực thi đồng bộ, ngay với cả những promíe đã được giải quyết:</p> + +<pre class="brush: js">Promise.resolve().then(() => console.log(2)); +console.log(1); // 1, 2 +</pre> + +<p>Thay vì chạy ngay lập tức, promise callback được đặt vào hàng đợi <strong>microtask</strong>, điều này có nghĩa là nó sẽ chỉ được thực thi khi hàng đợi được làm rỗng ( các promise đều được giải quy) cuối event loop hiện tại của JavaScript:</p> + +<pre class="brush: js">const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); + +wait().then(() => console.log(4)); +Promise.resolve().then(() => console.log(2)).then(() => console.log(3)); +console.log(1); // 1, 2, 3, 4 +</pre> + +<h2 id="Lồng_cấp">Lồng cấp</h2> + +<p>Chuỗi Promise đơn giản chỉ nên có một cấp và không lồng vào nhau, vì lồng cấp sẽ dẫn đến những tổ hợp phức tạp dễ gây ra lỗi. Xem <a href="#Một_số_sai_lầm_phổ_biến">các sai lầm thường gặp</a>.</p> + +<p>Lồng nhau là một cấu trúc kiểm soát để giới hạn phạm vi của các câu lệnh <code>catch</code>. Cụ thể, một câu lệnh <code>catch</code> lồng bên trong chỉ có thể bắt được những lỗi trong phạm vi của nó và bên dưới, không phải là lỗi phía bên trên của chuỗi bên ngoài phạm vi lồng nhau. Khi được sử dụng một cách hợp lý, nó mang lại độ chính xác cao hơn trong việc khôi phục lỗi:</p> + +<pre class="brush: js">doSomethingCritical() +.then(result => doSomethingOptional() + .then(optionalResult => doSomethingExtraNice(optionalResult)) + .catch(e => {})) // Ignore if optional stuff fails; proceed. +.then(() => moreCriticalStuff()) +.catch(e => console.log("Critical failure: " + e.message)); +</pre> + +<p>Lưu ý rằng các bước tuỳ chọn ở đây được lồng vào trong, không phải từ việc thụt đầu dòng, mà từ vị trí đặt dấu <code>(</code> và <code>)</code> xung quanh chúng.</p> + +<p>Câu lệnh <code>catch</code> bên trong chỉ bắt lỗi từ <code>doSomethingOptional()</code> và <code>doSomethingExtraNice()</code>, sau đó nó sẽ tiếp tục với <code>moreCriticalStuff()</code>. Điều quan trọng là nếu <code>doSomethingCritical()</code> thất bại, lỗi của nó chỉ bị bắt bởi <code>catch</code> cuối cùng (bên ngoài).</p> + +<h2 id="Một_số_sai_lầm_phổ_biến">Một số sai lầm phổ biến</h2> + +<p>Dưới đây là một số lỗi phổ biến cần chú ý khi sử dụng chuỗi promise. Một số trong những sai lầm này biểu hiện trong ví dụ sau:</p> + +<pre class="brush: js example-bad">// Một ví dụ có đến 3 sai lầm! +doSomething().then(function(result) { + doSomethingElse(result) // Quên trả về promise từ chuỗi lồng bên trong + lồng nhau không cần thiết + .then(newResult => doThirdThing(newResult)); +}).then(() => doFourthThing()); +// Quên kết thúc chuỗi bằng một hàm catch! +</pre> + +<p>Sai lầm đầu tiên là không kết nối mọi thứ với nhau đúng cách. Điều này xảy ra khi chúng ta tạo ra một promise mới nhưng quên trả lại. Hậu quả là chuỗi bị hỏng, hay đúng hơn, chúng ta có hai chuỗi độc lập cùng chạy. Có nghĩa là <code>doFourthThing()</code> sẽ không đợi <code>doSomethingElse()</code> hoặc <code>doThirdThing()</code> kết thúc và sẽ chạy song song với chúng, có khả năng ngoài ý muốn. Các chuỗi riêng biệt cũng sẽ xử lý lỗi riêng biệt, dẫn đến khả năng lỗi không được xử lý.</p> + +<p>Sai lầm thứ hai là làm lồng nhau không cần thiết, cho phép sai lầm đầu tiên. Lồng nhau cũng giới hạn phạm vi của các trình xử lý lỗi bên trong, điều mà nếu không cố ý thì có thể dẫn đến các lỗi chưa được xử lý. Một biến thể của điều này là <a href="https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it">promise constructor anti-pattern</a>, kết hợp lồng với việc sử dụng dự phòng của promise constructor để bọc mã đã sử dụng promise.</p> + +<p>Sai lầm thứ ba là quên chấm dứt chuỗi với <code>catch</code>. Chuỗi promise không kết thúc bằng <code>catch</code>, khi bị reject sẽ gây ra lỗi "uncaught promise rejection" trong hầu hết các trình duyệt.</p> + +<p>Một nguyên tắc tốt là luôn luôn trả lại hoặc chấm dứt chuỗi promise, và ngay khi bạn nhận được một promise mới, hãy trả lại ngay lập tức:</p> + +<pre class="brush: js example-good">doSomething() +.then(function(result) { + return doSomethingElse(result); +}) +.then(newResult => doThirdThing(newResult)) +.then(() => doFourthThing()) +.catch(error => console.log(error)); +</pre> + +<p>Lưu ý rằng <code>() => x</code> được rút gọn từ <code>() => { return x; }</code>.</p> + +<p>Bây giờ chúng ta có một chuỗi xác định duy nhất với xử lý lỗi thích hợp.</p> + +<p>Sử dụng <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a> sẽ khắc phục hầu hết, nếu không muốn nói là tất cả các vấn đề trên đây — với một hạn chế cũng là một lỗi thường gặp với cú pháp này đó là việc quên từ khoá <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function"><code>await</code></a>.</p> + +<h2 id="Xem_thêm">Xem thêm</h2> + +<ul> + <li>{{jsxref("Promise.then()")}}</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function"><code>async</code>/<code>await</code></a> </li> + <li><a href="http://promisesaplus.com/">Promises/A+ specification</a></li> + <li><a href="https://medium.com/@ramsunvtech/promises-of-promise-part-1-53f769245a53">Venkatraman.R - JS Promise (Part 1, Basics)</a></li> + <li><a href="https://medium.com/@ramsunvtech/js-promise-part-2-q-js-when-js-and-rsvp-js-af596232525c#.dzlqh6ski">Venkatraman.R - JS Promise (Part 2 - Using Q.js, When.js and RSVP.js)</a></li> + <li><a href="https://tech.io/playgrounds/11107/tools-for-promises-unittesting/introduction">Venkatraman.R - Tools for Promises Unit Testing</a></li> + <li><a href="http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">Nolan Lawson: We have a problem with promises — Common mistakes with promises</a></li> +</ul> + +<p>{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}</p> diff --git a/files/vi/web/javascript/guide/working_with_objects/index.html b/files/vi/web/javascript/guide/working_with_objects/index.html new file mode 100644 index 0000000000..6fdc2dba69 --- /dev/null +++ b/files/vi/web/javascript/guide/working_with_objects/index.html @@ -0,0 +1,500 @@ +--- +title: Working with objects +slug: Web/JavaScript/Guide/Working_with_Objects +translation_of: Web/JavaScript/Guide/Working_with_Objects +--- +<div>{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}</div> + +<p class="summary">JavaScript được thiết kế trên mô hình đối tượng đơn giản. Một object là một tập hợp các thuộc tính, và một thuộc tính là sự liên kết giữa một cái tên và giá trị. Giá trị của một thuộc tính có thể là một hàm. Ngoài những đối tượng được định nghĩa trước trong trình duyệt, bạn có thể định nghĩa những đối tượng của riêng bạn. Chương này mô tả cách sử dụng những đối tượng, những thuộc tính, những hàm, và phương thức, cũng như cách thức để tạo đối tượng riêng của mình.</p> + +<h2 id="Tổng_quan_về_Objects">Tổng quan về Objects</h2> + +<p>Objects trong JavaScript, cũng tương tự như những ngôn ngữ khác, có thể so sánh như đối tượng trong đời thường. Khái niệm của objects trong JavaScript có thể được hiểu như những đối tượng thực tế trong đời thực.</p> + +<p>Trong JavaScript, một object là một thực thể độc lập, với thuộc tính và kiểu. Lấy cái tách làm ví dụ. Cái tách là một object có những thuộc tính của riêng nó. Một cái tách có màu sắc, thiết kế, trọng lượng, chất liệu tạo ra nó, vân vân... Tương tự như vậy, JavaScript objects có thể có những thuộc tính định nghĩa nên đặc tính của nó.</p> + +<h2 id="Objects_and_thuộc_tính">Objects and thuộc tính</h2> + +<p>Một JavaScript object có những thuộc tính liên kết với nó. Một thuộc tính của một object có thể được giải thích như là một biến mà được gắn vào object đó. Những thuộc tính của object cơ bản cũng là những biến JavaScript bình thường, chỉ đặc biệt là được gắn lên object. Thuộc tính của object định nghĩa đặc tính của object. Chúng ta truy xuất thuộc tính của object với ký hiệu ".":</p> + +<pre class="brush: js">objectName.propertyName +</pre> + +<p>Giống như những biến JavaScript, cả tên của object (có thể được xem như là 1 biến thông thường) và tên thuộc tính thì cũng phân biệt hoa thường. Bạn có thể định nghĩa một thuộc tính bằng cách gán giá trị cho nó. Ví dụ hãy tạo đối tượng myCar và gắn thuộc tính cho nó như <code>make</code>, <code>model</code>, and <code>year</code> như sau:</p> + +<pre class="brush: js">var myCar = new Object(); +myCar.make = 'Ford'; +myCar.model = 'Mustang'; +myCar.year = 1969; +</pre> + +<p>Những thuộc tính không được gán giá trị sẽ có giá trị {{jsxref("undefined")}} (lưu ý nó là không {{jsxref("null")}}).</p> + +<pre class="brush: js">myCar.color; // undefined</pre> + +<p>Thuộc tính của JavaScript object có thể được truy xuất hoặc thiết lập bằng cách dùng dấu ngoặc vuông (xem <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors">property accessors</a> để tham khảo chi tiết). Objects thỉnh thoảng cũng được gọi là <em>mảng liên kết, </em>vì mỗi thuộc tính được liên kết với một giá trị kiểu chuỗi mà có thể được dùng để truy xuất thuộc tính đó. Ví dụ bạn có thể truy xuất những thuộc tính của <code>myCar</code> object như sau:</p> + +<pre class="brush: js">myCar['make'] = 'Ford'; +myCar['model'] = 'Mustang'; +myCar['year'] = 1969; +</pre> + +<p>Tên thuộc tính của một object có thế là chuỗi ký tự hợp lệ bất kỳ, hoặc bất kỳ thứ gì có thể chuyển đổi được thành chuỗi, bao gồm cả chuỗi rỗng. Tuy nhiên, bất kỳ tên thuộc tính nào mà không phải là 1 định danh hợp lệ trong JavaScript (ví dụ, một thuộc tính mà tên có khoảng trắng hoặc gạch ngang, hoặc bắt đầu bằng số) chỉ có thể truy xuất bằng cách dùng dấu ngoặc vuông []. Ký pháp này cũng rất hữu dụng khi tên thuộc tính được xác định động (khi tên thuộc tính chỉ được xác định lúc thực thi). Như trong ví dụ sau:</p> + +<pre class="brush: js">// Khởi tạo 4 biến và gán giá trị cho chúng trên cùng một dòng lệnh +// phân cách bởi dấu "," +var myObj = new Object(), + str = 'myString', + rand = Math.random(), + obj = new Object(); + +myObj.type = 'Dot syntax'; +myObj['date created'] = 'String with space'; +myObj[str] = 'String value'; +myObj[rand] = 'Random Number'; +myObj[obj] = 'Object'; +myObj[''] = 'Even an empty string'; + +console.log(myObj); +</pre> + +<p>Chú ý tất cả biểu thức được làm khóa trong dấu ngoặc vuông đều được chuyển đổi thành kiểu chuỗi, bởi vì objects trong JavaScript chỉ chấp nhận khóa là kiểu chuỗi. Ví dụ trong đoạn mã trên khi khóa <code>obj</code> được thêm vào <code>myObj</code>, JavaScript sẻ gọi phương thức <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString">obj.toString()</a>, và lấy kết quả đó làm khóa.</p> + +<p>Bạn cũng có thể truy xuất thuộc tính bằng cách dùng giá trị chuỗi mà nó được lưu trong một biến:</p> + +<pre class="brush: js">var propertyName = 'make'; +myCar[propertyName] = 'Ford'; + +propertyName = 'model'; +myCar[propertyName] = 'Mustang'; +</pre> + +<p>Bạn có thể sử dụng dấu ngoặc vuông với <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a></code> để duyệt qua tất cả thuộc tính có thể đếm của object. Để minh họa cách nó hoạt động, hãy xem xét hàm sau đây, nó sẽ hiển thị những thuộc tính của đối tượng dựa vào 2 đối số gồm đối tượng (<code>obj</code>) và tên (<code>objName</code>) của đối tượng truyền vào cho hàm:</p> + +<pre class="brush: js">function showProps(obj, objName) { + var result = ''; + for (var i in obj) { + // obj.hasOwnProperty() is used to filter out properties from the object's prototype chain + if (obj.hasOwnProperty(i)) { + result += objName + '.' + i + ' = ' + obj[i] + '\n'; + } + } + return result; +} +</pre> + +<p>Như vậy, khi ta gọi <code>showProps(myCar, "myCar")</code> thì kết quả được trả về như sau:</p> + +<pre class="brush: js">myCar.make = Ford +myCar.model = Mustang +myCar.year = 1969</pre> + +<h2 id="Liệt_kê_những_thuộc_tính_của_một_object">Liệt kê những thuộc tính của một object</h2> + +<p>Bắt đầu từ <a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_5_support_in_Mozilla" title="en-US/docs/JavaScript/ECMAScript 5 support in Mozilla">ECMAScript 5</a>, có 3 cách để liệt kê/duyệt danh sách thuộc tính của object:</p> + +<ul> + <li>Câu lệnh lặp <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/for...in" title="en-US/docs/JavaScript/Reference/Statements/for...in">for...in</a></code><br> + Cách này duyệt qua tất cả thuộc tính có thể duyệt của một object và chuỗi prototype của nó</li> + <li>{{jsxref("Object.keys", "Object.keys(o)")}}<br> + Phương thức này trả về một mảng tất cả tên những thuộc tính có thể liệt kê mà gắn trực tiếp trên object <code>o</code> (không phải từ chuỗi prototype)</li> + <li>{{jsxref("Object.getOwnPropertyNames", "Object.getOwnPropertyNames(o)")}}<br> + Phương thức này trả về một mảng tất cả tên những thuộc tính (có thể liệt kê hoặc không) mà gắn trực tiếp trên object <code>o</code> (không phải từ chuỗi prototype)</li> +</ul> + +<p>Trước ECMAScript 5, không có cách thức có sẵn để liệt kê tất cả thuộc tính của một object. Tuy nhiên, chúng ta có thực hiện việc đó bằng hàm sau:</p> + +<pre class="brush: js">function listAllProperties(o) { + var objectToInspect; + var result = []; + + for(objectToInspect = o; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect)) { + result = result.concat(Object.getOwnPropertyNames(objectToInspect)); + } + + return result; +} +</pre> + +<p>Cách này rất hữu ích khi chúng ta muốn hiển thị những thuộc tính ẩn (những thuộc tính trong chuỗi prototype mà không thể truy xuất thông qua object, bởi vì một thuộc tính khác có cùng tên ở lớp trước của chuỗi prototype đã đè lên nó). Việc liệt kê những thuộc tính có thể truy xuất chỉ có thể dễ dàng hoàn thành bằng cách xóa bỏ trùng lặp trong mảng.</p> + +<h2 id="Tạo_những_object_mới">Tạo những object mới</h2> + +<p>JavaScript có một số object được định nghĩa sẵn. Ngoài ra, bạn có thể tạo định nghĩa những object mới. Bạn có thể tạo một object sử dụng <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer">bộ khởi tạo object (object initializer).</a> Cách khác, bạn có thể tạo hàm dựng và rồi khởi tạo đối tượng bằng cách gọi hàm đó với toán tử <code>new</code> đặt trước.</p> + +<h3 id="Sử_dụng_bộ_khởi_tạo_object"><a id="Object_initializers" name="Object_initializers">Sử dụng bộ khởi tạo object</a></h3> + +<p>Ngoài việc khởi tạo object bằng cách dùng hàm dựng, bạn có thể tạo object bằng cách sử dụng <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer">bộ khởi tạo (object initializer)</a>. Sử dụng bộ khởi tạo thỉnh thoảng cũng được hiểu là cách khởi tạo bằng cách dùng literal. "Bộ khởi tạo" ("Object initializer") thì đồng nhất với thuật ngữ được sử dụng trong C++.</p> + +<p>Cú pháp cho việc tạo một object bằng bộ khởi tạo la:</p> + +<pre class="brush: js">var obj = { property_1: value_1, // property_# may be an identifier... + 2: value_2, // or a number... + // ..., + 'property n': value_n }; // or a string +</pre> + +<p>Trong đó <code>obj</code> là tên của object mới, mỗi <code>property_<em>i</em></code> là một định danh (hoặc là một tên, một số, hoặc một chuỗi dạng literal), và mỗi <code>value_<em>i</em></code> là một biểu thức mà giá trị được gán cho <code>property_<em>i</em></code> . <code>obj</code> và phép gán là không bắt buộc; nếu bạn không cần tham chiếu đến object đó ở chổ khác, bạn không cần assign nó cho một biến. (lưu ý bạn có thể cần bao object literal lại bằng dấu ngoặc nếu nó xuất hiện ở chổ cần như là một câu lệnh, làm như vậy để tránh gây nhầm lẩn với câu lệnh khối.)</p> + +<p>Bộ khởi tạo object là những biểu thức, và mỗi bộ khởi tạo object sẽ tạo ra object mỗi khi biểu thức đó được tính toán. Bộ khởi tạo object tạo ra những đối tượng riêng biệt và chúng không bằng nhau khi so sánh bằng <code>==</code>. Những đối tượng được tạo ra bằng cách <code>new Object()</code> cũng như những đối tượng được tạo ra bằng object literal đều là thực thể (instance) của <code>Object</code>.</p> + +<p>Câu lệnh sau tạo một đối tượng và gán nó cho biến <code>x</code> khi và chỉ khi biểu thức <code>cond</code> là true:</p> + +<pre class="brush: js">if (cond) var x = {greeting: 'hi there'}; +</pre> + +<p>Đoạn mã sau tạo đối tượng <code>myHonda</code> với ba thuộc tính. Lưu ý thuộc tính <code>engine</code> cũng là một object và nó có những thuộc tính riêng của nó.</p> + +<pre class="brush: js">var myHonda = {color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}}; +</pre> + +<p>Bạn cũng có thể dùng bộ khởi tạo object để tạo mảng. Tham khảo <a href="/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Array_literals">array literals.</a></p> + +<h3 id="Sử_dụng_hàm_dựng">Sử dụng hàm dựng</h3> + +<p>Ngoài ra, bạn có thể tạo một object với hai bước sau đây:</p> + +<ol> + <li>Định nghĩa kiểu cho object bằng cách khai báo một hàm dựng. Bạn nên đặt tên hàm với chữ hoa cho ký tự đầu tiên.</li> + <li>Tạo một thực thể của đối tượng với toán tử <code>new</code>.</li> +</ol> + +<p>Để định nghĩa một kiểu dữ liệu object, tạo một hàm cho kiểu dữ liệu đó rồi chỉ định tên, những thuộc tính và phương thưc. Ví dụ, giả sử bạn muốn tạo một kiểu dữ liệu cho cars. Bạn đặt tên cho kiểu dữ liệu đó là <code>Car</code>, và bạn muốn nó có những thuộc tính như make, model, và year. Để làm được điểu này, bạn sẽ viết hàm sau:</p> + +<pre class="brush: js">function Car(make, model, year) { + this.make = make; + this.model = model; + this.year = year; +} +</pre> + +<p>Lưu ý cách sử dụng <code>this</code> để gán trị giá trị cho những thuộc tính của object dựa vào giá trị được truyền vào cho hàm.</p> + +<p>Bây giờ bạn có thể tạo một object tên <code>mycar</code> như sau:</p> + +<pre class="brush: js">var mycar = new Car('Eagle', 'Talon TSi', 1993); +</pre> + +<p>Câu lệnh này tạo <code>mycar</code> gán những giá trị cụ thể cho những thuộc tính của nó. Giá trị của <code>mycar.make</code> là chuỗi "Eagle", <code>mycar.year</code> là số 1993, và tiếp tuc như thế.</p> + +<p>Bạn có thể tạo bao nhiêu <code>Car</code> object đều được bằng toán tử <code>new</code>. Như ví dụ sau:</p> + +<pre class="brush: js">var kenscar = new Car('Nissan', '300ZX', 1992); +var vpgscar = new Car('Mazda', 'Miata', 1990); +</pre> + +<p>Một object có thể có một thuộc tính mà giá trị là một object khác. Ví dụ như, giả sử bạn định nghĩa một object tên <code>person</code> như sau:</p> + +<pre class="brush: js">function Person(name, age, sex) { + this.name = name; + this.age = age; + this.sex = sex; +} +</pre> + +<p>và sau đó khởi tạo hai object <code>person</code> mới như sau:</p> + +<pre class="brush: js">var rand = new Person('Rand McKinnon', 33, 'M'); +var ken = new Person('Ken Jones', 39, 'M'); +</pre> + +<p>Và rồi, bạn có thể viết lại định nghĩa của <code>Car</code> để thêm thuộc tính <code>owner</code> mà nhận giá trị là một đối tượng kiểu <code>person</code>, như sau:</p> + +<pre class="brush: js">function Car(make, model, year, owner) { + this.make = make; + this.model = model; + this.year = year; + this.owner = owner; +} +</pre> + +<p>Để khởi tạo object mới, bạn viết những câu lệnh sau:</p> + +<pre class="brush: js">var car1 = new Car('Eagle', 'Talon TSi', 1993, rand); +var car2 = new Car('Nissan', '300ZX', 1992, ken); +</pre> + +<p>Lưu ý rằng thay vì truyền vào một hằng chuỗi hoặc giá trị số khi tạo những object mới, câu lệnh trên truyền vào những đối tượng <code>rand</code> và <code>ken</code> như là đối số cho <code>owner</code>. Sau đó nếu bạn muốn tìm tên của <code>owner</code> của car2, bạn có thể truy xuất như sau:</p> + +<pre class="brush: js">car2.owner.name +</pre> + +<p>Lưu ý rằng bạn có thể luôn luôn thêm một thuộc tính mới vào những object đã được tạo ra. Như ví dụ câu lệnh sau:</p> + +<pre class="brush: js">car1.color = 'black'; +</pre> + +<p>thêm vào thuộc tính <code>color</code> cho car1, và gán giá trị cho nó là "black". Tuy nhiên, việc này không ảnh hưởng lên những object khác. Để thêm thuộc tính cho tất cả object của cùng một kiểu, bạn phải thêm thuộc tính đó khi định nghĩa kiểu đối tượng <code>Car</code>.<br> + </p> + +<h3 id="Sử_dụng_Object.create">Sử dụng <code>Object.create</code></h3> + +<p>Những object có thể được tạo ra bằng phương thức {{jsxref("Object.create()")}}. Phương thức này có thể rất hữu ích, bởi vì nó cho phép bạn chọn prototype cho object bạn muốn tạo ra, mà không cần phải định nghĩa hàm dựng.</p> + +<pre class="brush: js">// Animal properties and method encapsulation +var Animal = { + type: 'Invertebrates', // Default value of properties + displayType: function() { // Method which will display type of Animal + console.log(this.type); + } +}; + +// Create new animal type called animal1 +var animal1 = Object.create(Animal); +animal1.displayType(); // Output:Invertebrates + +// Create new animal type called Fishes +var fish = Object.create(Animal); +fish.type = 'Fishes'; +fish.displayType(); // Output:Fishes</pre> + +<h2 id="Sự_Kế_Thừa">Sự Kế Thừa</h2> + +<p>Tất cả object trong JavaScript kế thừa từ ít nhất một object khác. Object mà được kế thừa từ nó thì được xem như là prototype, và những thuộc tính được kế thừa có thể được tìm thấy trong đối tượng <code>prototype</code> của hàm dựng. Xem thêm <a href="/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">Inheritance and the prototype chain</a></p> + +<h2 id="Đánh_chỉ_mục_thuộc_tính_object">Đánh chỉ mục thuộc tính object</h2> + +<p>Bạn có thể tham chiếu tới một object hoặc là bằng tên thuộc tính hoặc là bằng chỉ mục. Nếu bạn định nghĩa thuộc tính bằng tên, thì sau đó bạn phải dùng tên để truy xuất thuộc tính đó, còn nếu bạn định nghĩa thuộc tính bằng chỉ mục (một số), bạn phải dùng chỉ mục để truy xuất.</p> + +<p>Giới hạn này áp dụng khi bạn tạo một object và thuộc tính của nó với hàm dựng (như chúng ta đã làm với kiểu <code>Car</code>) và khi bạn định nghĩa những thuộc tính riêng lẻ một cách tường minh (ví dụ như , <code>myCar.color = "red"</code>). Nếu bạn định nghĩa thuộc tính với một chỉ mục, chẳng hạn như <code>myCar[5] = "25 mpg"</code>, thì bạn phải tham chiếu đến thuộc tính đó với chỉ mục <code>myCar[5]</code>.</p> + +<p>Ngoại trừ nếu đó là object giống mảng (array-like), ví dụ như những object tạo ra từ HTML như <code>forms</code> object. Bạn có thể tham chiếu đến những object đó bằng cách hoặc là dùng số (dựa vào thứ tự nó xuất hiện trong document) hoặc là tên (nếu được định nghĩa). Ví dụ, nếu thẻ <code><FORM></code> thứ hai trong document có thuộc tính <code>NAME</code> là "myForm", bạn có thể tham chiếu đến form bằng cách <code>document.forms[1]</code> hoặc <code>document.forms["myForm"]</code> hoặc <code>document.forms.myForm</code>.</p> + +<h2 id="Định_nghĩa_những_thuộc_tính_cho_kiểu_dữ_liệu_object">Định nghĩa những thuộc tính cho kiểu dữ liệu object</h2> + +<p>Bạn có thể thêm một thuộc tính cho một object đã định nghĩa trước đó bằng cách sử dụng thuộc tính <code>prototype</code>. Điều này định nghĩa một thuộc tính mà sẽ được chia sẻ bởi tất các các thuộc tính của cùng kiểu dữ liệu đó, không riêng cho một thực thể nào của kiểu đó. Đoạn mã sau sẽ thêm thuộc tính <code>color</code> cho tất cả các object của kiểu <code>Car</code>, và rồi gán giá trị cho thuộc tính <code>color</code> của object <code>car1</code>.</p> + +<pre class="brush: js">Car.prototype.color = null; +car1.color = 'black'; +</pre> + +<p>Xem thêm <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/prototype" title="en-US/docs/JavaScript/Reference/Global Objects/Function/prototype"><code>prototype</code> property</a> của object <code>Function</code> trong <a href="/en-US/docs/Web/JavaScript/Reference">JavaScript reference</a>.</p> + +<h2 id="Định_nghĩa_phương_thức">Định nghĩa phương thức</h2> + +<p>Một phương thức là một hàm liên kết với một object, hoặc, có thể nói phương thức là một thuộc tính của object có giá trị là một hàm. Phương thức được định nghĩa giống như cách định nghĩa hàm, ngoài trừ việc chúng phải được gán như là thuộc tính của một object. Xem thêm <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions">method definitions</a>. Ví dụ:</p> + +<pre class="brush: js">objectName.methodname = functionName; + +var myObj = { + myMethod: function(params) { + // ...do something + } + + // OR THIS WORKS TOO + + myOtherMethod(params) { + // ...do something else + } +}; +</pre> + +<p><code>objectName</code> là một object đã được tạo trước đó, <code>methodname</code> là tên mà bạn đang gán cho phương thức, và <code>functionName</code> là tên của hàm.</p> + +<p>Sau đó bạn có thể gọi hàm trong ngữ cảnh của object như sau:</p> + +<pre class="brush: js">object.methodname(params); +</pre> + +<p>Bạn có thể định nghĩa phương thức của một kiểu object bằng cách thêm định nghĩa phương thức vào trong hàm dựng. Bạn có thể định nghĩa một hàm mà sẽ định dạng và hiển thị những thuộc tính của những đối tượng kiểu <code>Car</code> đã được định nghĩa trước, ví dụ:</p> + +<pre class="brush: js">function displayCar() { + var result = 'A Beautiful ' + this.year + ' ' + this.make + + ' ' + this.model; + pretty_print(result); +} +</pre> + +<p>trong đó <code>pretty_print</code> được giả định là một hàm đã được định nghĩa trước để hiển thị đường kẻ ngang và chuỗi kết quả. Lưu ý tham chiếu <code>this</code> đang trỏ đến đối tượng mà phương thức đang gắn trên đó.</p> + +<p>Bạn có thể tạo hàm này thành phương thức của lớp <code>Car</code> bằng câu lệnh sau:</p> + +<pre class="brush: js">this.displayCar = displayCar; +</pre> + +<p>khi định nghĩa kiểu object <code>Car</code>. Cài đặt đầy đủ của <code>Car</code> bây giờ sẽ là:</p> + +<pre class="brush: js">function Car(make, model, year, owner) { + this.make = make; + this.model = model; + this.year = year; + this.owner = owner; + this.displayCar = displayCar; +} +</pre> + +<p>Rồi sau đó bạn có thể gọi phương thức <code>displayCar</code> trên mỗi đối tượng như sau:</p> + +<pre class="brush: js">car1.displayCar(); +car2.displayCar(); +</pre> + +<h2 id="Sử_dụng_this_để_tham_chiếu_đối_tượng">Sử dụng <code>this</code> để tham chiếu đối tượng</h2> + +<p>JavaScript có từ khóa đặc biệt, <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/this">this</a></code>, mà bạn có thể sử dụng bên trong phương thức để tham chiếu đến object hiện tại. Ví dụ, giả sử bạn có một hàm tên là <code>validate</code> để kiểm tra giá trị của thuộc tính của một object là giá trị cao hay thấp:</p> + +<pre class="brush: js">function validate(obj, lowval, hival) { + if ((obj.value < lowval) || (obj.value > hival)) { + alert('Invalid Value!'); + } +} +</pre> + +<p>Sau đó, bên trong hàm handler của event <code>onchange</code> của mỗi phần tử của form bạn có thể gọi hàm <code>validate</code> như ví dụ sau:</p> + +<pre class="brush: html"><input type="text" name="age" size="3" + onChange="validate(this, 18, 99)"> +</pre> + +<p>Nói chúng, <code>this</code> trỏ đến object đang gọi bên trong hàm.</p> + +<p>Khi kết hợp với thuộc tính <code>form</code>, <code>this</code> có thể tham chiếu đến form cha của object hiện tại. Trong ví dụ sau, form <code>myForm</code> chứa đối tượng <code>Text</code> và một nút. Khi user nhấp lên cái nút, giá trị của đối tượng <code>Text</code> được gán bằng tên của form. Hàm thực thi của sự kiện <code>onclick</code> của cái nút sử dụng <code>this.form</code> để tham chiếu đến form cha, <code>myForm</code>.</p> + +<pre class="brush: html"><form name="myForm"> +<p><label>Form name:<input type="text" name="text1" value="Beluga"></label> +<p><input name="button1" type="button" value="Show Form Name" + onclick="this.form.text1.value = this.form.name"> +</p> +</form></pre> + +<h2 id="Định_nghĩa_getters_và_setters">Định nghĩa getters và setters</h2> + +<p>Một <a href="/en-US/docs/Web/JavaScript/Reference/Functions/get">getter</a> là một phương thức mà nhận giá trị của một thuộc tính cụ thể. Một <a href="/en-US/docs/Web/JavaScript/Reference/Functions/set">setter</a> là một phương thức thiết lập giá trị cho một thuộc tính cụ thể. Bạn có thể định nghĩa getters và setters cho bất kỳ object nào có thể là do runtime tạo sẵn hoặc do người dùng định nghĩa. Chúng ta dùng cú pháp của object literal để tạo getter và setter.</p> + +<p>Đoạn mã sau minh họa cách định nghĩa và thao tác trên getter và setter.</p> + +<pre class="brush: js">var o = { + a: 7, + get b() { + return this.a + 1; + }, + set c(x) { + this.a = x / 2; + } +}; + +console.log(o.a); // 7 +console.log(o.b); // 8 +o.c = 50; +console.log(o.a); // 25 +</pre> + +<p>Những thuộc tính của object <code>o</code> là:</p> + +<ul> + <li><code>o.a</code> — một số</li> + <li><code>o.b</code> — một getter trả về kết quả của <code>o.a</code> cộng 1</li> + <li><code>o.c</code> — một setter thiết lập giá trị cho <code>o.a</code> với giá trị là một nửa giá trị của đối số được truyền vào</li> +</ul> + +<p>Lưu ý ta dùng hàm để định nghĩa getter và setter, nhưng chúng ta truy xuất nó như một thuộc tính. Để định nghĩa một getter hoặc setter ta dùng cú pháp "[gs]et <em>property</em>()", Hoặc chúng ta một cách khác để định nghĩa getter hoặc setter là dùng <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty" title="en-US/docs/Core JavaScript 1.5 Reference/Global +Objects/Object/defineProperty">Object.defineProperty</a></code> (hoặc dùng cách cũ với <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineGetter" title="en-US/docs/Core JavaScript 1.5 Reference/Global +Objects/Object/defineGetter">Object.prototype.__defineGetter__</a></code>).</p> + +<p>Đoạn mã sau minh họa cách dùng getter và setter mở rộng prototype của {{jsxref("Date")}} để thêm thuộc tính <code>year</code> cho tất cả thực thể được tạo ra từ lớp <code>Date</code>. Và dùng phương thức <code>getFullYear</code> and <code>setFullYear</code> để hỗ trợ getter và setter <code>year</code>.</p> + +<p>Những câu lệnh sau định nghĩa getter và setter cho thuộc tính <code>year</code>:<br> + </p> + +<pre class="brush: js">var d = Date.prototype; +Object.defineProperty(d, 'year', { + get: function() { return this.getFullYear(); }, + set: function(y) { this.setFullYear(y); } +}); +</pre> + +<p>Những câu lệnh sau sử dụng getter và setter trong đối tượng <code>Date</code>:<br> + </p> + +<pre class="brush: js">var now = new Date(); +console.log(now.year); // 2000 +now.year = 2001; // 987617605170 +console.log(now); +// Wed Apr 18 11:13:25 GMT-0700 (Pacific Daylight Time) 2001 +</pre> + +<p>Điều cần ghi nhớ là, getter vad setter có thể:</p> + +<ul> + <li>hoặc được định nghĩa bằng cách sứ dụng <a href="#Object_initializers">bộ khởi tạo object</a></li> + <li>hoặc được thêm vào sau đó cho bất kỳ object nào tại bất kỳ thời điểm nào bằng cách sử dụng phương thức tạo getter & setter (Object.defineProperty).</li> +</ul> + +<p>Khi tạo getters và settes sử dụng <a href="#Object_initializers">bộ khởi tạo object</a> điều bạn cần làm là đặt từ khóa <code>get</code> trước tên phương thức getter và từ khóa <code>set</code> trước phương thức setter. Tất nhiên là phương thức getter không cần bất kỳ tham số nào, còn phương thức setter cần đúng một tham số. Như ví dụ sau:</p> + +<pre class="brush: js">var o = { + a: 7, + get b() { return this.a + 1; }, + set c(x) { this.a = x / 2; } +}; +</pre> + +<p>Getters and setters có thể được thêm vào một object bất kỳ khi nào sau khi được tạo bằng cách dùng phương thức <code>Object.defineProperties</code>. Tham số đầu tiên của phương thức này là object mà bạn muốn định nghĩa getter và setter. Tham số thứ hai là một object mà tên của thuộc tính là tên của getter và setter, giá trị của thuộc tính là object định nghĩa hàm getter và setter. Sau đây là ví dụ minh họa cách định nghĩa getter và setter</p> + +<pre class="brush: js">var o = { a: 0 }; + +Object.defineProperties(o, { + 'b': { get: function() { return this.a + 1; } }, + 'c': { set: function(x) { this.a = x / 2; } } +}); + +o.c = 10; // Runs the setter, which assigns 10 / 2 (5) to the 'a' property +console.log(o.b); // Runs the getter, which yields a + 1 or 6 +</pre> + +<p>Việc lựa chọn cách nào để định nghĩa getter và setter tùy thuộc vào phong cách lập trình và công việc cụ thể. Nếu bạn luôn dùng bộ khởi tạo object khi định nghĩa một prototype thì bạn nên chọn cách thứ nhất. Cách này đơn giản và tự nhiên. Tuy nhiên, nếu bạn cần thêm getters và setters sau đó — bởi vì bạn không viết prototype hoặc object cụ thể — bạn phải sử dụng cách thứ hai. Cách thứ hai thể hiện tính chất "động" tự nhiên của JavaScript — nhưng nó làm cho code khó đọc và khó hiểu.</p> + +<h2 id="Việc_xóa_bỏ_thuộc_tính">Việc xóa bỏ thuộc tính</h2> + +<p>Bạn có thể xóa bỏ một thuộc tính không kế thừa bằng toán tử <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/delete">delete</a></code>. Câu lệnh sau chỉ bạn cách để xóa bỏ một thuộc tính.</p> + +<pre class="brush: js">// Creates a new object, myobj, with two properties, a and b. +var myobj = new Object; +myobj.a = 5; +myobj.b = 12; + +// Removes the a property, leaving myobj with only the b property. +delete myobj.a; +console.log ('a' in myobj); // yields "false" +</pre> + +<p>Bạn cũng có thể dùng <code>delete</code> để xóa bỏ biến toàn cục nếu bạn không dùng từ khóa <code>var</code> khi định nghĩa biến.</p> + +<pre class="brush: js">g = 17; +delete g; +</pre> + +<h2 id="So_sánh_objects">So sánh objects</h2> + +<p>Trong JavaScript những object là kiểu tham chiếu. Hai đối tượng tách biệt không bao giờ bằng nhau, thậm chí nếu chúng có cùng những thuộc tính. Chỉ khi nó so sánh với chính nó thì kết quả mới là true.</p> + +<pre class="brush: js">// Two variables, two distinct objects with the same properties +var fruit = {name: 'apple'}; +var fruitbear = {name: 'apple'}; + +fruit == fruitbear; // return false +fruit === fruitbear; // return false</pre> + +<pre class="brush: js">// Two variables, a single object +var fruit = {name: 'apple'}; +var fruitbear = fruit; // assign fruit object reference to fruitbear + +// here fruit and fruitbear are pointing to same object +fruit == fruitbear; // return true +fruit === fruitbear; // return true +</pre> + +<pre class="brush: js">fruit.name = 'grape'; +console.log(fruitbear); // yields { name: "grape" } instead of { name: "apple" } +</pre> + +<p>Chi tiết về toán tử so sánh, xem thêm tại <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators">Comparison operators</a>.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li>Để hiểu sâu hơn về chủ đề này, bạn có thể đọc thêm <a href="/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model">details of javaScript's objects model</a>.</li> + <li>Để học về ECMAScript 2015 classes (cách mới để định nghĩa object) đọc thêm chương <a href="/en-US/docs/Web/JavaScript/Reference/Classes">JavaScript classes</a>.</li> +</ul> + +<p>{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Details_of_the_Object_Model")}}</p> |