Sự khác biệt giữa traditional function và arrow function
Function trong JavaScript có thể được tạo bằng 3 cách: function declaration, function expression, và arrow function.
Arrow function ra đời sau
Nhìn lại lịch sử JavaScript, ban đầu chỉ có function declaration và function expression. Hai cách này hầu như không có sự khác biệt về chức năng. Chúng được gọi chung là "traditional function". Arrow function được giới thiệu sau để giải quyết các vấn đề của traditional function.
Tính ngắn gọn của cú pháp
Traditional function có vấn đề về độ dài cú pháp. Trong JavaScript, chúng ta thường viết callback function. Callback function là function được truyền làm tham số của function khác. Với traditional function, bạn phải viết từ khóa function mỗi khi viết function. Ngay cả khi chỉ có 1 dòng xử lý, vẫn có coding style yêu cầu nhiều dòng. Code trở nên rườm rà cả khi viết và khi đọc. Ngược lại, arrow function có cú pháp ngắn gọn và đơn giản.
js// Traditional function (function expression)[1, 2, 3].map (function (n ) {returnn + 1;});// Arrow function[1, 2, 3].map ((n ) =>n + 1);
js// Traditional function (function expression)[1, 2, 3].map (function (n ) {returnn + 1;});// Arrow function[1, 2, 3].map ((n ) =>n + 1);
Arrow function được thiết kế lại bằng cách loại bỏ
Khi nghe arrow function ra đời sau, bạn có thể nghĩ rằng nó có thêm tính năng so với traditional function. Thực ra là ngược lại. Arrow function được thiết kế lại bằng approach loại bỏ. Nó loại bỏ các tính năng thừa đối với function hoặc đơn giản hóa các đặc tả phức tạp từ traditional function. Do đó, nó trở nên đơn giản hơn và "bản chất function" nổi bật hơn. Hãy xem những tính năng nào đã được loại bỏ.
Constructor
Bản chất của function là nhận input và trả về kết quả tính toán. Traditional function trong JavaScript không chỉ có bản chất này mà còn đảm nhận vai trò constructor để tạo object. Để sử dụng function như constructor, bạn dùng toán tử new.
jsfunctionCat (name ) {this.name =name ;}// Tạo object Catconstcat = newCat ("Mimi");console .log (cat );
jsfunctionCat (name ) {this.name =name ;}// Tạo object Catconstcat = newCat ("Mimi");console .log (cat );
Thoạt nhìn, việc function có tính năng constructor có vẻ tiện lợi. Tuy nhiên, điều này khiến người sử dụng phải quyết định có nên thêm toán tử new vào function hay không. Để quyết định điều đó, bạn phải đọc nội dung xử lý của function. Nếu gọi function nên được thực thi như constructor bằng cách gọi bình thường có thể dẫn đến bug.
Arrow function không thể trở thành constructor. Nếu dùng toán tử new trong JavaScript, sẽ xảy ra lỗi runtime. Không có lo ngại về việc sử dụng sai.
jsconstCat = (name ) => {};constcat = newCat ("Mimi");
jsconstCat = (name ) => {};constcat = newCat ("Mimi");
Trong TypeScript, ngay cả traditional function cũng không thể được sử dụng như constructor. Nếu bạn nhầm lẫn new function, bạn sẽ được cảnh báo bằng compile error nên yên tâm.
tsfunctionCat (name : string) {/* ... */}const'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.7009'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.cat = newCat ("Mimi");
tsfunctionCat (name : string) {/* ... */}const'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.7009'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.cat = newCat ("Mimi");
Tóm lại, trong JavaScript bạn cần chú ý đến việc có thể trở thành constructor hay không, nhưng trong TypeScript bạn có thể nhận ra qua compile error nên không cần chú ý nhiều như JavaScript.
this trỏ đến gì
Với traditional function, có đặc tả là biến this trỏ đến thứ gì đó được xác định bởi context runtime. Nói cách khác, ngay cả với cùng một function, this có thể tham chiếu đến những thứ khác nhau tùy theo cách gọi function hoặc môi trường gọi. Hãy xem ví dụ về traditional function hiển thị this ra console.
jsfunctionshowThis () {console .log (this);}
jsfunctionshowThis () {console .log (this);}
Khi thực thi function showThis này bình thường, this trỏ đến global object. Global object trong browser là object Window. Object Window cung cấp API để thao tác kích thước trang, URL, HTML hiển thị (DOM), v.v.
jsshowThis ();
jsshowThis ();
JavaScript có strict mode. Đây là execution mode hạn chế các xử lý nguy hiểm. Để bật strict mode, viết "use strict" ở đầu code. Khi thực thi showThis trong strict mode, giá trị this trở thành undefined.
js"use strict";showThis ();
js"use strict";showThis ();
Nhân tiện, trong TypeScript, khi bật compiler option alwaysStrict, JavaScript sau compile sẽ ở strict mode.
Ngoài ra, JavaScript có script mode và module mode. Trong module mode JavaScript, bạn có thể sử dụng cú pháp export và import. Mode này tự động ở strict mode. Do đó, khi thực thi showThis trong module mode, giá trị this là undefined.
jsexport {};showThis ();
jsexport {};showThis ();
Function cũng có thể được gọi như method của object. Khi gọi function showThis như method, giá trị this trỏ đến là object mà method gắn với.
jsconstfoo = {name : "Foo" };// Đặt function làm member của objectfoo .showThis =showThis ;// Gọi như methodfoo .showThis ();
jsconstfoo = {name : "Foo" };// Đặt function làm member của objectfoo .showThis =showThis ;// Gọi như methodfoo .showThis ();
Đã giải thích rằng traditional function có thể được gọi như constructor, khi gọi như constructor, this trỏ đến object đang được tạo.
jsfunctionshowThis () {this.name = "Foo";console .log (this);}newshowThis ();
jsfunctionshowThis () {this.name = "Foo";console .log (this);}newshowThis ();
Như đã minh họa ở trên, với traditional function, nội dung của this được xác định động theo context thực thi. Do đó, cần chú ý cách gọi traditional function. Sử dụng sai có thể dẫn đến bug.
| Context | Giá trị this |
|---|---|
Gọi thông thườngshowThis() | Global object (Window) |
Gọi thông thường + strict modeshowThis() | undefined |
Gọi methodobj.showThis() | Object mà method thuộc về (obj) |
Gọi constructornew showThis() | Object đang được tạo |
this của arrow function là lexical scope và static. Nghĩa là, thứ mà this trỏ đến được xác định khi định nghĩa, không bị ảnh hưởng bởi cách gọi function (context). Giá trị của this rõ ràng.
Ví dụ, object timer sau có method start hiển thị message sau 1 giây. Method start đặt lịch xuất giá trị field message của timer sau 1 giây.
this của function start trỏ đến timer (❶). Sau 1 giây, cố gắng xuất this.message. Traditional function có this trỏ đến global object Window, nên xuất undefined (❷). Còn arrow function có this trỏ đến this của lexical scope (❸). this này là timer. Do đó, giá trị field message "Time's up!" được xuất ra đúng.
jsconstoneSecond = 1000;consttimer = {message : "Time's up!",start : function () {console .log (this); // ❶// Traditional functionsetTimeout (function () {console .log (this.message ); // ❷},oneSecond );// Arrow functionsetTimeout (() => {console .log (this.message ); // ❸},oneSecond );},};timer .start ();
jsconstoneSecond = 1000;consttimer = {message : "Time's up!",start : function () {console .log (this); // ❶// Traditional functionsetTimeout (function () {console .log (this.message ); // ❷},oneSecond );// Arrow functionsetTimeout (() => {console .log (this.message ); // ❸},oneSecond );},};timer .start ();
Hành vi của call, apply, bind
Function trong JavaScript là object, và có 3 method call, apply, bind. Các method này gọi function, nhưng với traditional function, bạn có thể chỉ định this trỏ đến gì qua tham số đầu tiên.
jsfunctionshowThis () {console .log (this);}constobj = {name : "foo" };showThis .bind (obj )(); // bind obj vào this và gọi function
jsfunctionshowThis () {console .log (this);}constobj = {name : "foo" };showThis .bind (obj )(); // bind obj vào this và gọi function
Arrow function cũng có call, apply, bind, nhưng ngay cả khi truyền giá trị vào tham số đầu tiên, this không bị ghi đè.
jsconstshowThis = () => {console .log (this);};constobj = {name : "foo" };showThis .bind (obj )();
jsconstshowThis = () => {console .log (this);};constobj = {name : "foo" };showThis .bind (obj )();
Có biến arguments hay không
Với traditional function, biến đặc biệt arguments được định nghĩa tự động. Giá trị này là mảng các tham số.
jsfunctionfoo () {console .log (arguments );}foo (1, 2, 3);
jsfunctionfoo () {console .log (arguments );}foo (1, 2, 3);
arguments tiện lợi để thực hiện variadic arguments, nhưng cũng có thể xem nó là biến thừa không được sử dụng trong hầu hết các trường hợp implement function. Arrow function không có arguments. Để thực hiện variadic arguments với arrow function, dùng rest parameter ....
jsconstfoo = (...args ) => {console .log (args );};foo (1, 2, 3);
jsconstfoo = (...args ) => {console .log (args );};foo (1, 2, 3);
Generator
JavaScript có generator là function đặc biệt có thể tạo nhiều giá trị. Generator được viết bằng cách thêm dấu hoa thị vào từ khóa function và mô tả giá trị tạo ra bằng câu lệnh yield.
jsfunction*generateNumbers () {yield 1;yield 2;yield 3;}
jsfunction*generateNumbers () {yield 1;yield 2;yield 3;}
Giá trị của generator có thể được lấy ra bằng xử lý lặp như for-of.
jsfor (constvalue ofgenerateNumbers ()) {console .log (value ); // Xuất theo thứ tự 1, 2, 3}
jsfor (constvalue ofgenerateNumbers ()) {console .log (value ); // Xuất theo thứ tự 1, 2, 3}
Chỉ traditional function mới có thể định nghĩa generator. Arrow function không hỗ trợ cú pháp generator từ đầu nên không thể định nghĩa generator.
Arrow function với tính an toàn được tăng cường
Arrow function đã cải thiện các đặc tả nguy hiểm của traditional function.
Trùng tên tham số
Traditional function trong JavaScript cho phép trùng tên tham số. Khi tham số trùng, giá trị được truyền cho tham số cuối cùng sẽ được chọn.
jsfunctionfoo (a ,a ,a ) {console .log (a );}foo (1, 2, 3);
jsfunctionfoo (a ,a ,a ) {console .log (a );}foo (1, 2, 3);
Đặc tả này dễ gây bug, nhưng với traditional function cũng có thể biến trùng tên tham số thành syntax error bằng cách bật strict mode.
js"use strict";functionfoo (a ,a ) {}// ^Syntax error
js"use strict";functionfoo (a ,a ) {}// ^Syntax error
Khi arrow function được giới thiệu, các đặc tả nguy hiểm như thế này đã được loại bỏ từ đầu. Với arrow function, khi tên tham số trùng, luôn là syntax error bất kể strict mode bật hay tắt.
jsconstfoo = (a ,a ) => {};// ^Syntax error
jsconstfoo = (a ,a ) => {};// ^Syntax error
Trong TypeScript, ngay cả traditional function cũng có lỗi compile khi trùng tên tham số.
tsfunctionDuplicate identifier 'a'.foo (: number, a : number) {} a
Duplicate identifier 'a'.2300
2300Duplicate identifier 'a'.
Duplicate identifier 'a'.
tsfunctionDuplicate identifier 'a'.foo (: number, a : number) {} a
Duplicate identifier 'a'.2300
2300Duplicate identifier 'a'.
Duplicate identifier 'a'.
Do đó, trong TypeScript, không có sự khác biệt về an toàn giữa traditional function và arrow function.
Trùng tên function
Trong JavaScript, khi khai báo biến, bạn dùng một trong const, let, hoặc var. var tồn tại từ đầu JavaScript, còn const và let được thêm vào năm 2015. Sự khác biệt lớn là const chỉ có thể gán giá trị khi khai báo, còn let có thể thay đổi giá trị sau khi khai báo.
const và let được giới thiệu để giải quyết vấn đề của var. Một trong những vấn đề của var là có thể khai báo biến nhiều lần với cùng tên biến. Ví dụ, ngay cả khi biến value đã được khai báo, nếu khai báo lại bằng var value, nó vẫn thực thi mà không có lỗi.
jsvarvalue = 1;varvalue = 2;console .log (value );
jsvarvalue = 1;varvalue = 2;console .log (value );
Đặc tả này khiến khó nhận ra việc ghi đè biến không mong muốn và thường là nguyên nhân gây lỗi. const và let sẽ báo lỗi khi tên biến trùng. Nghĩa là, có thể coding an toàn hơn so với var.
jsletCannot redeclare block-scoped variable 'value'.2451Cannot redeclare block-scoped variable 'value'.= 1; value letCannot redeclare block-scoped variable 'value'.2451Cannot redeclare block-scoped variable 'value'.= 2; // Syntax error value
jsletCannot redeclare block-scoped variable 'value'.2451Cannot redeclare block-scoped variable 'value'.= 1; value letCannot redeclare block-scoped variable 'value'.2451Cannot redeclare block-scoped variable 'value'.= 2; // Syntax error value
Function được tạo bằng function declaration tương đương với var. Do đó, có thể tạo function với tên trùng.
jsfunctionfoo () {console .log ("Function thứ nhất");}functionfoo () {console .log ("Function thứ hai");}foo ();
jsfunctionfoo () {console .log ("Function thứ nhất");}functionfoo () {console .log ("Function thứ hai");}foo ();
Arrow function được tạo bằng cú pháp giống khai báo biến, nên miễn là coding tránh var và dùng let hoặc const, không thể xảy ra trùng tên function.
jsconstCannot redeclare block-scoped variable 'foo'.2451Cannot redeclare block-scoped variable 'foo'.= () => {}; foo constCannot redeclare block-scoped variable 'foo'.2451Cannot redeclare block-scoped variable 'foo'.= () => {}; foo
jsconstCannot redeclare block-scoped variable 'foo'.2451Cannot redeclare block-scoped variable 'foo'.= () => {}; foo constCannot redeclare block-scoped variable 'foo'.2451Cannot redeclare block-scoped variable 'foo'.= () => {}; foo
Tất nhiên, nếu tạo arrow function bằng var, vẫn có thể trùng tên function. Tuy nhiên, trong best practice JavaScript hiện đại, không khuyến khích dùng var. Do đó, arrow function giảm thiểu lỗi trùng tên function nhiều hơn so với function declaration trong hầu hết các tình huống.
Trong TypeScript, ngay cả function declaration cũng có lỗi compile khi trùng tên function.
tsfunctionDuplicate function implementation.2393Duplicate function implementation.() {} foo functionDuplicate function implementation.2393Duplicate function implementation.() {} foo
tsfunctionDuplicate function implementation.2393Duplicate function implementation.() {} foo functionDuplicate function implementation.2393Duplicate function implementation.() {} foo
Do đó, về vấn đề trùng tên function, TypeScript không có sự khác biệt về an toàn.
Hoisting và thứ tự định nghĩa và gọi function
Function declaration và arrow function có sự khác biệt về việc hoisting có xảy ra hay không. Hoisting là đặc tả cho phép tham chiếu biến trong code trước khi biến được khai báo.
Hoisting là đặc tả tự động đưa khai báo biến được khai báo ở giữa variable scope lên đầu variable scope. Biến được hoist sẽ được khởi tạo với undefined. Trong ví dụ sau, tham chiếu biến value trước khai báo biến value, nhưng không có lỗi và xuất undefined.
jsconsole .log (value );varvalue = 1;
jsconsole .log (value );varvalue = 1;
Đây là do hoisting xảy ra với biến value, khai báo value được đưa lên trước console.log(value). Code trên thực chất có ý nghĩa giống code sau.
jsvarvalue ;console .log (value );value = 1;
jsvarvalue ;console .log (value );value = 1;
Hoisting tương tự cũng xảy ra với function declaration. Điểm khác với hoisting của var là function không được khởi tạo với undefined mà cả implementation của function cũng được hoist. Do đó, có thể gọi function trước function declaration.
jsfoo ();functionfoo () {console .log ("Đã thực thi");}
jsfoo ();functionfoo () {console .log ("Đã thực thi");}
Thứ tự viết trong code là gọi function, function declaration, nhưng không có vấn đề gì với hoisting của function.
Chia sẻ kiến thức
Đặc điểm của arrow function trong JavaScript
・Cú pháp ngắn gọn
・this là lexical scope
・Không thể trở thành constructor
・Không thể trở thành generator
・Không xảy ra trùng tham số
・Khó xảy ra trùng khai báo function
・Khó xảy ra hoisting
Từ 『Survival TypeScript』
Cách sử dụng traditional function và arrow function
Ở trên, chúng ta đã xem sự khác biệt về chức năng giữa traditional function (function declaration và function expression) và arrow function. Dựa trên sự khác biệt, nên dùng cái nào trong hai cái này? Nếu dùng cả hai, nên phân biệt theo tiêu chí nào?
Việc nên dùng traditional function hay arrow function là vấn đề ý kiến khác nhau. Vì arrow function là tính năng mới giải quyết vấn đề của traditional function, có người nghĩ nên dùng arrow function càng nhiều càng tốt. Ngược lại, có người nghĩ nên phân biệt hợp lý giữa function declaration và arrow function. Cũng có người nghĩ nên dùng function declaration tích cực hơn arrow function. Tiêu chí dùng arrow function ở đâu và dùng traditional function ở đâu là vấn đề không có hồi kết. Không thể khẳng định tiêu chí nào là đúng.
Dù vậy, cách phân biệt traditional function và arrow function quan trọng là phải nhất quán trong phạm vi cá nhân hoặc team chia sẻ cùng một source code. Từ đây, tôi muốn đưa ra manh mối để bạn có thể tự suy nghĩ cách phân biệt của riêng mình. Điều tôi trình bày ở đây không nhất thiết đúng phổ biến. Hãy đọc và suy nghĩ cách phân biệt của riêng bạn.
Nếu không có lý do đặc biệt, dùng arrow function sẽ an toàn hơn. Lý do là arrow function là function đơn giản với chức năng tối thiểu của function. Như đã thấy ở trên, traditional function có nhiều tính năng như constructor, giải thích động this, v.v., và nếu không dùng các tính năng đó thì chúng trở thành tính năng thừa. Càng nhiều tính năng thì càng phải cân nhắc nhiều khi coding. Arrow function hạn chế ở chức năng tối thiểu nên có ưu điểm là viết mà không cần lo lắng chi tiết.
Arrow function đặc biệt phù hợp với callback function. Ví dụ, object array Array có một số method xử lý từng phần tử. Các method này cần truyền function vào tham số. Ví dụ sau dùng method filter cho array số để trích xuất chỉ số chẵn. Code này truyền function expression làm callback function.
jsconstnums = [1, 2, 3, 4];consteven =nums .filter (function (n ) {returnn % 2 === 0;});console .log (even );
jsconstnums = [1, 2, 3, 4];consteven =nums .filter (function (n ) {returnn % 2 === 0;});console .log (even );
Nếu thay bằng arrow function, sẽ trở thành cú pháp đơn giản như sau.
jsconstnums = [1, 2, 3, 4];consteven =nums .filter ((n ) =>n % 2 === 0);console .log (even );
jsconstnums = [1, 2, 3, 4];consteven =nums .filter ((n ) =>n % 2 === 0);console .log (even );
Với callback function như thế này, việc dùng arrow function tích cực sẽ mang lại lợi ích như giảm lượng code viết hoặc làm nổi bật xử lý mà code muốn thực hiện.
Traditional function cũng có chỗ dùng. Khi muốn thực hiện xử lý khi button HTML được click, dùng method addEventListener. Bằng cách truyền xử lý tùy ý làm callback function cho method này, có thể thực hiện xử lý mong muốn.
jsbutton .addEventListener ("click",callbackFunction );
jsbutton .addEventListener ("click",callbackFunction );
Khi muốn tham chiếu button được click trong xử lý, nếu function được truyền là traditional function, có thể tham chiếu button bằng biến this. Ví dụ dưới đây là code thay đổi hiển thị button "Save" đã click thành "Saving...". Thay đổi hiển thị button bằng this.innerText. Với cách dùng this như thế này, không thể viết bằng arrow function.
html<button id="save">Save</button><script>const button = document.getElementById("save");button.addEventListener("click", function () {this.innerText = "Saving...";});</script>
html<button id="save">Save</button><script>const button = document.getElementById("save");button.addEventListener("click", function () {this.innerText = "Saving...";});</script>
Ngay cả trong trường hợp trên, nếu tham chiếu button thì cũng có thể dùng arrow function. Vì vậy không phải là lý do quyết định phải dùng traditional function.
html<button id="save">Save</button><script>const button = document.getElementById("save");button.addEventListener("click", () => {button.innerText = "Saving...";// ^^^Tham chiếu button});</script>
html<button id="save">Save</button><script>const button = document.getElementById("save");button.addEventListener("click", () => {button.innerText = "Saving...";// ^^^Tham chiếu button});</script>
Khi tạo function làm method của object, có lý do chọn traditional function. Vì có thể tham chiếu object bằng this. Ví dụ, như method fullName1 trong ví dụ sau, khi method sử dụng property của object, tiện lợi khi tham chiếu bằng this.
jsconsttaroYamada = {firstName : "Taro",lastName : "Yamada",// Traditional functionfullName1 : function () {return this.firstName + " " + this.lastName ;},// Arrow functionfullName2 : () => {return this.firstName + " " + this.lastName ;},};console .log (taroYamada .fullName1 ());console .log (taroYamada .fullName2 ());
jsconsttaroYamada = {firstName : "Taro",lastName : "Yamada",// Traditional functionfullName1 : function () {return this.firstName + " " + this.lastName ;},// Arrow functionfullName2 : () => {return this.firstName + " " + this.lastName ;},};console .log (taroYamada .fullName1 ());console .log (taroYamada .fullName2 ());
fullName2 dùng arrow function không hoạt động như mong đợi vì this không trỏ đến object. Nếu dùng arrow function, phải tham chiếu tên biến object như taroYamada.firstName thay vì this.
jsconsttaroYamada = {firstName : "Taro",lastName : "Yamada",fullName : () => {returntaroYamada .firstName + " " +taroYamada .lastName ;},};console .log (taroYamada .fullName ());
jsconsttaroYamada = {firstName : "Taro",lastName : "Yamada",fullName : () => {returntaroYamada .firstName + " " +taroYamada .lastName ;},};console .log (taroYamada .fullName ());
Có trường hợp code dễ hiểu hơn nhờ hoisting của traditional function. Ví dụ, nhóm xử lý theo từng giai đoạn bằng function và liệt kê gọi function ở đầu chương trình có thể làm tổng quan xử lý của chương trình dễ hiểu ở chỗ bắt đầu đọc.
js// Tổng quan chương trìnhstep1 ();step2 ();step3 ();// Chi tiết từng xử lýfunctionstep1 () {/* Chi tiết xử lý */}functionstep2 () {/* Chi tiết xử lý */}functionstep3 () {/* Chi tiết xử lý */}
js// Tổng quan chương trìnhstep1 ();step2 ();step3 ();// Chi tiết từng xử lýfunctionstep1 () {/* Chi tiết xử lý */}functionstep2 () {/* Chi tiết xử lý */}functionstep3 () {/* Chi tiết xử lý */}
Arrow function cần tạo bằng const, let, hoặc var nên không có hoisting của function. Do đó, không thể viết trực tiếp pattern hiển thị tổng quan xử lý trước như sample code trên.
jsstep1 ();step2 ();step3 ();conststep1 = () => {};conststep2 = () => {};conststep3 = () => {};
jsstep1 ();step2 ();step3 ();conststep1 = () => {};conststep2 = () => {};conststep3 = () => {};
Nếu muốn biểu hiện gần với cách viết trên bằng arrow function, cần định nghĩa function viết tổng quan xử lý và gọi function đó ở cuối chương trình.
jsconstmain = () => {step1 ();step2 ();step3 ();};conststep1 = () => {};conststep2 = () => {};conststep3 = () => {};main ();
jsconstmain = () => {step1 ();step2 ();step3 ();};conststep1 = () => {};conststep2 = () => {};conststep3 = () => {};main ();
Cũng có lựa chọn dùng function declaration khi muốn làm nổi bật rằng function là function. Vì arrow function được viết giống khai báo biến, một số người cảm thấy khó phân biệt ngay đó là giá trị hay function. Hãy so sánh ví dụ sau có arrow function và function declaration xen giữa các khai báo biến. Cái nào dễ nhận ra là function ngay khi nhìn?
js// Arrow function xen giữa khai báo biếnconststr = "foo";constobj = {value :str };constfunc = (n ) =>n + 1;constnums = [1, 2, 3];
js// Arrow function xen giữa khai báo biếnconststr = "foo";constobj = {value :str };constfunc = (n ) =>n + 1;constnums = [1, 2, 3];
js// Function declaration xen giữa khai báo biếnconststr = "foo";constobj = {value :str };functionfunc (n ) {returnn + 1;}constnums = [1, 2, 3];
js// Function declaration xen giữa khai báo biếnconststr = "foo";constobj = {value :str };functionfunc (n ) {returnn + 1;}constnums = [1, 2, 3];