Javascript: Học Javascript cơ bản-Các khái niệm cần nắm trong JS.

Javascript: Học Javascript cơ bản-Các khái niệm cần nắm trong JS.

Series hiện tại có 2 bài viết:

  1. Học Javascript cơ bản – Kiến thức chung về lập trình.
  2. Học Javascript cơ bản – Các khái niệm cần nắm trong JS.

phần trước, tôi đã giới thiệu cho các bạn những phần hết sức cơ bản trong lập trình như biến, vòng lặp, điều kiện, hàm, … Và nó được minh họa bằng ngôn ngữ Javascript. Nhưng trong phần này, chúng ta sẽ đi sâu về Javascript hơn để nắm được các khái niệm nền tảng.

Có thể bạn bắt gặp nhiều kiến thức mới mẻ và hữu ích mà trước đây chưa được nhắc tới. Đây là những viên gạch đầu tiên cho những lập trình viên JS.

Values & Types

Như ở phần trước, chúng ta đã nói sơ qua thế nào là Values & Types trong lập trình nói chung, và sau đây là một số type có sẵn trong JS:

  • string
  • number
  • boolean
  • null and undefined
  • object
  • symbol(mới từ ES6)

JS cung cấp cho chúng ta cú pháp typeof để kiểm tra type của một biên như sau:

var a;
typeof a;				// "undefined"

a = "hello world";
typeof a;				// "string"

a = 42;
typeof a;				// "number"

a = true;
typeof a;				// "boolean"

a = null;
typeof a;				// "object" -- weird, bug

a = undefined;
typeof a;				// "undefined"

a = { b: "c" };
typeof a;				// "object"

Giá trị trả về của typeof chỉ là một trong 6 giá trị như trên(hay 7 với ES6). Một điều thú vị là typeof null trả về là một object. Trong khi bạn hi vọng nó trả về là null.

Cũng chú ý rằng khi khai báo let a = undefined cũng giống như let a. Vì cả hai trường hợp giá trị của biến a là chưa được gán, có nghĩa là chúng ta khai báo một biến mà ko có giá trị khởi tạo.

Objects

Một đối tượng(object) trong JS là một kiểu dữ liệu phức tạp. Nó cho phép chúng ta cài đặt nhiều kiểu giá trị khác nhau thông qua properties.

var obj = {
	a: "hello world",
	b: 42,
	c: true
};

obj.a;		// "hello world"
obj.b;		// 42
obj.c;		// true

obj["a"];	// "hello world"
obj["b"];	// 42
obj["c"];	// true

Bạn có thể hình dùng một object được lưu như sau trong bộ nhớ:

fig4.png

Properties(thuộc tính) có thể được truy xuất bằng cách dot notation(obj.a) hoặc bracket notation(obj[“a”]). Cách dùng dấu chấm có vẻ ngắn gọn và dễ hiểu hơn. Nhưng trong một số trường hợp dùng dấu ngoặc vuông lại tiện lợi hơn.

var obj = {
	a: "hello world",
	b: 42
};

var b = "a";

obj[b];			// "hello world"
obj["b"];		// 42

Về chi tiết Object chúng ta sẽ bàn ở những phần sau.

Có một số kiểu dữ liệu thường dùng trong JS như Array Function. Chúng là những kiểu dữ liệu con của Object.

Arrays

Một mảng là một đối tượng chứa giá trị mà không dùng đến key/values mà dùng các chỉ số index để truy cập phần tử:

var arr = [
	"hello world",
	42,
	true
];

arr[0];			// "hello world"
arr[1];			// 42
arr[2];			// true
arr.length;		// 3

typeof arr;		// "object"

Index được bắt đầu với giá trị là 0, 1, 2 ,3, …

Functions

Một dạng đặc biệt khác của object nữa đó là function.

function foo() {
	return 42;
}

foo.bar = "hello world";

typeof foo;			// "function"
typeof foo();		// "number"
typeof foo.bar;		// "string"

Một lần nữa function là một dạng dữ liệu con của object.

Built-in Type Methods

Những kiểu dữ liệu chúng ta đề cập ở trên thông thường đều có properties(thuộc tính) và method(phương thức)

const a = "hello world";
const b = 3.14159;

a.length;				// 11
a.toUpperCase();		// "HELLO WORLD"
b.toFixed(4);			// "3.1416"

Mỗi một kiểu dữ liệu trong JS đều được thừa kế từ một object nào đó. Ví dụ ở đây ta có biến a là một chuỗi thì nó sẽ được thừa kế những phương phức từ cha của nó là String. Với string chúng ta có sẵn nhiều thuộc tính và phương pháp như: a.length, a.toUpperCase(), …

Tương tự với Number, Array, chúng ta đều có sẵn nhiều thuộc tính và phương thức để dùng. Với Array, chúng ta có nhiều phương thức hay ho như: push, pop, some, map, reduce, filter, find,

Comparing Values

Có hai dạng so sánh là bằng nhau và ko bằng nhau. Và giá trị trả về luôn là true hoặc false.

Coercion

Ở bài trước chúng ta đã nói sơ qua về coercion(ép kiểu). Ép kiểu có hai dạng là: explicit implicit.

Explicit có nghĩa là chúng ta muốn ép kiểu một giá trị theo ý thích của chúng ta. Chúng ta điều khiển và nhận biết được điều này.

Implicit có nghĩa là được thực hiện ngầm định bên trong ngôn ngữ JS. Chúng ta không có ý định ép kiểu nhưng JS làm dùm chúng ta. 🙁

Mọi người thường chê trách việc ép kiểu implicit trong JS. Bởi vì chúng ta thường không hiểu tại sao nó như vậy và đôi lúc kết quả trả về không như chúng ta mong muốn.

Ví dụ về explict coercion:

const a = "42";

const b = Number( a );

a;				// "42"
b;				// 42 -- the number!

Ở đây chúng ta dùng hàm Number để ép từ một kiểu string sang kiểu number.

Một ví dụ về implicit coercion:

const a = "42";

const b = a * 1;	// "42" implicitly coerced to 42 here

a;				// "42"
b;				// 42 -- the number!

Biến a sẽ tự động được chuyển thành kiểu number khi chúng ta thực hiện phép tính: a * 1.

Truthy & Falsy

Ở phần trước chúng ta đã tìm hiểu sơ lược về Boolean. Nó có hai giá trị là truefalse. Nhưng trong một số trường hợp JS sẽ ép kiểu một số dữ liệu khác về kiểu Boolean. Ví dụ như kiểu false như sau:

  • "" (empty string)
  • 0-0NaN (invalid number)
  • nullundefined
  • false

Những giá trị khác là true như sau:

  • "hello"
  • 42
  • true
  • [ ][ 1, "2", 3 ] (arrays)
  • { }{ a: 42 } (objects)
  • function foo() { .. } (functions)

Equality

Có một số phép so sánh bằng và không bằng như: =====!=, and !== Trong đó toán tử ! có nghĩa là không(not).

Sự khác nhau giữa phép toán == và === thường được hiểu là với == so sánh về giá trị. Và với === so sánh cả giá trị và kiểu dữ liệu. Nhưng thực chất nó chưa đúng lắm, với == JS sẽ tự động ép kiểu dữ liệu để so sánh. Ví dụ như:

const a = "42";
const b = 42;

a == b;			// true
a === b;		// false

Ở phép so sánh a == b thì a hoặc b sẽ được ép kiểu để chúng có type giống nhau. Bạn sẽ tự hỏi rắng ép kiểu sẽ diễn ra như thế nào: 42 == 42 hay “42” = = “42”. Câu trả lời là a sẽ được ép kiểu từ string thành number(42 == 42). Và do đó kết quả sẽ là true.

Ở phép so sánh a === b kết quả là false vì nó khắc khe hơn và không được ép kiểu. Cho nên giữa hai biến a và b vừa phải có value và type giống nhau thì phép so sánh mới đúng.

Theo tôi để tránh sự phức tạp một tip nhỏ chúng ta nên sử dụng === khi so sánh. Khi đó chúng ta sẽ nhận thức được rằng cả giá trị và kiểu giá trị đều rất quan trọng.

Variables

Trong Javascript, tên biến(bao gồm cả tên hàm) phải được đặt theo chuẩn. Nó phải bắt đầu bằng a-z, A-Z, $, hoặc _. Sau đó nó có thể bao gồm các ký tự bất kỳ hay các chữ số từ 0-9.

Nói chung, khi đặt tên biến bạn phải tránh một số từ khóa trong Javascript như for, if, else, null, true, false, ...

Functions Scopes

Mỗi một function đề có scope của nó. Ra khỏi scope thì chúng ta sẽ không thể truy cập những biến trong đó được. Ví dụ như khi bạn ở trong một cửa hàng bán điện thoại thì bạn có thể thoải mái lựa chọn và vọc điện thoại trong cửa hàng đó. Khi bạn ra khỏi cửa hàng thì bạn không thể được xem hay vọc điện thoại được nữa. Vì bạn đã ra ngoài phạm vi các shop đó. Cũng dễ hiểu phải không nào.

Function scopes qui định một phạm vi truy cập và thực thi của một hàm.

Bạn có thể sử dụng var để khai báo một biến thuộc về một function hoặc nếu bạn khai báo một biến nằm ngoài tất cả các hàm thì nó sẽ là global scope.

Hoisting

Khi nào bạn khai báo var có nghĩa là biến đó có thể được sử dụng ở bất kỳ đâu trong file đó. Bởi vì JS sẽ kéo biến bạn khai báo lên trên cùng của file đó. Ví dụ như sau:

var a = 2;

foo();					// works because `foo()`
						// declaration is "hoisted"

function foo() {
	a = 3;

	console.log( a );	// 3

	var a;				// declaration is "hoisted"
						// to the top of `foo()`
}

console.log( a );	// 2

Chúng ta có thể gọi hàm foo() ở trước khi nó khởi tạo bởi vì hàm này đã bị hoisting. Trong hàm foo bạn có thể thấy một điều kỳ lạ là việc gán a = 3 có thể không đúng nhưng do biến a đã bị kéo lên đầu hàm foo(biến a cũng đã bị hoisting)

Lưu ý đây không phải là một ý tưởng tốt khi mà chúng ta luôn dựa vào hoisting. Nó có thể dẫn đến nhầm lẫn và không tường minh trong code. Chúng ta nên từ bỏ dùng var và nên dùng let, const. Riêng trường hợp với function có thể phổ biến hơn và chúng ta có thể sử dụng hoisting cho function.

Conditionals

Điều kiện trong JS có thể hiểm nôm na là dùng if…else. Bên cạch đó JS cũng cung cấp cho chúng ta một số cú pháp khác đê chúng ta làm việc như sau:

if (a == 2) {
	// do something
}
else if (a == 10) {
	// do another thing
}
else if (a == 42) {
	// do yet another thing
}
else {
	// fallback to here
}

Có thể dùng switch … case:

switch (a) {
	case 2:
		// do something
		break;
	case 10:
		// do another thing
		break;
	case 42:
		// do yet another thing
		break;
	default:
		// fallback to here
}

Từ khóa break ở trong switch khá quan trọng vì nếu khi đúng một điều kiện nào đó lệnh sẽ được return và thoát ra khỏi switch. Nếu bạn quên break thì câu lệnh sẽ tiếp tục chạy tới case tiếp theo.

switch (a) {
	case 2:
	case 10:
		// some cool stuff
		break;
	case 42:
		// other stuff
		break;
	default:
		// fallback
}

Trong trường hợp này nếu a bằng 2 hoặc 10 thì sẽ thực hiện some cool stuff.

Ngoài ra, JS còn cung cấp cú pháp ngắn gọn như sau:

var a = 42;

var b = (a > 41) ? "hello" : "world";

// similar to:

// if (a > 41) {
//    b = "hello";
// }
// else {
//    b = "world";
// }

Strict Mode

Trong Javascript có rất nhiều qui tắc về scope, khai báo, cú pháp mà chúng ta cần tuân thủ. Mặc định một số qui tắc này bị lờ đi và đôi khi chính vì lí do này mà code của chúng ta bị một số lỗi ngớ ngẫn. Để tránh việc này, JS cung cấp một phương thức gọi là strict mode, được sử dụng với cú pháp “use strict”.

function foo() {
	"use strict";

	// this code is strict mode

	function bar() {
		// this code is strict mode
	}
}

// this code is not strict mode

Strict mode là một best practice trong JS. Chúng ta nên bật tính năng này lên để JS engine rà soát và phát hiện một số lỗi về cú pháp, cách khai báo biến,…

"use strict";

function foo() {
	// this code is strict mode

	function bar() {
		// this code is strict mode
	}
}

// this code is strict mode

Chúng ta có thể sử dụng strict mode trong phạm vị một function hay toàn bộ một file.

Ví dụ với strict mode, JS sẽ bắt được một số lỗi như:

function foo() {
	"use strict";	// turn on strict mode
	a = 1;			// `var` missing, ReferenceError
}

foo();

Functions As Values

Khi khai báo một function trong JS, chúng ta đã biết đến cú pháp này trong phần trước:

function foo() {
	// ..
}

Về bản chất hàm foo cũng giống như một cách khai báo biến khác như const a = 42, array = [3,2,1]. Bao gồm phần tên và phần giá trị. Nên với hàm foo là tên biến và giá trị của nó chính là phần câu lệnh bên trong dấu ngoặc nhọn({ … })

var foo = function() {
	// ..
};

var x = function bar(){
	// ..
};

Chúng ta có thể khai một function sử dụng expression như trên. Function đầu tiên được gọi là anonymous function. Bởi vì nó không có tên.

Function thứ hai có tên là bar và được gán cho biến x được gọi là named function expressions .

Immediately Invoked Function Expressions (IIFEs)

Ở những phần trước, chúng ta đã biết cách để khai báo một function và sau đó thực thi nó như foo() hay call().

Với IIFE đơn giản là chúng ta cũng khai báo một hàm và thực thi nó ngay tức khắc. Có vẻ cú pháp của nó hơi lạ một chút và cũng hơi khó nhớ:

(function IIFE(){
	console.log( "Hello!" );
})();
// "Hello!"

Trong dấu ngoăc (…) bao quanh (function IIFE(){ .. }) chỉ là cú pháp để phân biệt với những function thông thường.

Dấu () ở cuối hàm có nghĩa là thực thi một hàm. Nó cũng tương tự khi cú pháp foo(), bar(), …

function foo() { .. }

// `foo` function reference expression,
// then `()` executes it
foo();

// `IIFE` function expression,
// then `()` executes it
(function IIFE(){ .. })();

Vậy tại sao lại sinh IIFE chi cho rườm rà? Lý do là ở đây IIFE sẽ tạo ra một scope riêng của nó. Cho nên khi vô tình bạn khai một biến cùng tên với bên ngoài thì cũng không ảnh hưởng đến biến bên ngoài. Và dĩ nhiên bên ngoài cũng không làm thay đổi những biến bên trong IIFE.

var a = 42;

(function IIFE(){
	var a = 10;
	console.log( a );	// 10
})();

console.log( a );		// 42

Chúng ta cũng có thể return về một giá trị trong IIFE:

var x = (function IIFE(){
	return 42;
})();

x;	// 42

Closure

Closure là một trong những phần quan trọng và đặc biệt trong JS. Nhưng nó cũng là một phần mà nhiều developer bỏ qua nhất. Trong bài này, chúng ta sẽ không đi sâu về closure. Nhưng tôi sẽ điểm qua một số nét cơ bản nhất về nó để mọi người có cái nhìn toàn diện hơn. Xin nhắc lại đây là một kỹ năng đặc biệt nhất trong JS so với những ngôn ngữ khác.

Bạn có thể hiểu closure là một cách để nhớ và truy cập scope của function(những biến trong function đó) khi mà function đó đã được thực thi xong. Điều đặc biệt ở đây là với những function thông thường thì khi function nó thực thi xong, sau đó những biến trong nó sẽ bị phá hủy. Nhưng với closure thì không, những biến trong một function sẽ được nhớ lại và truy xuất ngay cả khi function nó đã thực thi xong.

Để tạo một closure chúng ta cần khai báo một function như sau:

function makeAdder(x) {
	// parameter `x` is an inner variable

	// inner function `add()` uses `x`, so
	// it has a "closure" over it
	function add(y) {
		return y + x;
	};

	return add;
}

Hàm makeAdder return về một hàm khác là add. Nào xem cách sử dụng nó như thế nào:

// `plusOne` có một tham chiếu tới hàm inner `add(..)`
// có closure với `x` là tham số của hàm bên ngoài là //`makeAdder(..)`
var plusOne = makeAdder( 1 );

// `plusTen` có một tham chiếu tới hàm inner `add(..)`
// có closure vơi `x` là tham số của hàm outer 
// `makeAdder(..)`
var plusTen = makeAdder( 10 );

plusOne( 3 );		// 4  <-- 1 + 3
plusOne( 41 );		// 42 <-- 1 + 41

plusTen( 13 );		// 23 <-- 10 + 13

Đoạn code trên được thực thi như sau:

  1. Khi bạn gọi makeAdder(1), hàm này sẽ trả về hàm bên trong là add() mà nó sẽ nhớ biến x được gán là 1. Sau đó chúng ta gọi plusOne(3) thì nó sẽ lấy 3 + với x là 1 bằng 4.
  2. Tương tự khi bạn gọi bạn gọi makeAdder(10), hàm này sẽ trả về hàm bên trong là add() mà nó sẽ nhớ biến x được gán là 10. Sau đó chúng ta gọi plusTen(13) thì nó sẽ lấy 13 + với x là 10 bằng 23.

Đừng lo lắng vì nó có vẻ hơi dị nhưng sau đây chúng ta sẽ có nhiều bài tập hơn để hiểu về cách closure hoạt động.

Và tin tôi, một khi bạn thực hành nhiều bạn sẽ thấy được đây là một trong những kỹ thuật đặc biệt mà chỉ có ở Javascript. Nên nó xứng đáng để bạn nghiên cứu sâu hơn và áp dụng nhiều hơn.

Modules

Một trong những ứng dụng phổ biến của closure là dùng để tạo nên những modules. Modules là cách bạn tạo những API cho một chức năng gì đó. Ví dụ bạn sẽ có một module chuyên xử lí dữ liệu ngày tháng như: định dạng ngày tháng theo format, hay chuyển đổi từ local time sang UTC, hay cộng trừ ngày tháng,… Khi đó bạn viết một module và tạo ra những API để các developer khác dùng module của bạn.

Ví dụ khác như sau:

function User(){
	var username, password;

	function doLogin(user,pw) {
		username = user;
		password = pw;

		// do the rest of the login work
	}

	var publicAPI = {
		login: doLogin
	};

	return publicAPI;
}

// create a `User` module instance
var fred = User();

fred.login( "fred", "12Battery34!" );

Hàm User() sẽ là một outer function để ghi nhớ các giá trị của username password, cũng như tạo thêm một function khác tên là doLogin(). Đây là những thông tin riêng tư bên trong module User() mà chúng sẽ không được truy xuất từ bên ngoài.

Thực thi User() sẽ tạo nên một instance của User module- một scope mới sẽ được hình thành bao gồm các biến username, password, hàm doLogin. Chúng ta gán nó cho fred. Nếu chúng ta chạy User() lần nữa, chúng ta sẽ nhận được một instance hoàn toàn khác với fred.

Hàm inner doLogin() có một closure với username password. Nghĩa là nó vẫn có thể truy cập được các biến nó sau khi hàm User() thực thi xong.

publicAPI là một object với một thuộc tính là login là hàm doLogin. Khi chúng ta trả về publicAPI từ User() thì nó sẽ trở thành một instance khi gọi fred.

Tại thời điểm này outer User() function thực thi xong. Như bình thường thì chúng ta nghĩ rằng biến username passoword sẽ bị mất đi. Nhưng chúng không mất, bởi vì có một closure bên trong login() giữ cho nhứng biến này còn được lưu trong bộ nhớ.

Đó là lý do mà khi gọi fred.login()-giống như chúng ta gọi doLogin() nó có thể truy cập các biến username password.

What is THIS?

Một khái niệm khác gây nhiều tranh cãi nữa là THIS. Và chúng ta có riêng một bài chi tiết về nó sau phần này. Sau đây chúng ta chỉ tìm hiểu sơ lược về nó.

Trong khi nhiều người thường hiểu THIS thường liên quan tới lập trình hướng đối tượng, nhưng trong JS nó còn hơn thê nữa.

Nếu một function có THIS bên trong nó, thì this này sẽ trỏ tới một đối tượng nào đó. Và đối tượng nào là tùy thuộc vào function đó được gọi như thế nào. THIS chỉ được nhận biết trong khi function đó được gọi từ ngữ cảnh nào: global hay một object.

Một điều quan trọng là this không liên kết với hàm của chính nó. Đây là mấu chốt của vấn đề. Sau đây là một ví dụ:

function foo() {
	console.log( this.bar );
}

var bar = "global";

var obj1 = {
	bar: "obj1",
	foo: foo
};

var obj2 = {
	bar: "obj2"
};

// --------

foo();				// "global"
obj1.foo();			// "obj1"
foo.call( obj2 );		// "obj2"
new foo();			// undefined

Có 4 qui tắc để biết this trỏ về đâu và nó được minh họa bằng 4 câu lệnh ở trên:

  1. foo() có this là global object và sẽ in ra giá tri là global trong non-strict mode. Với strict mode bạn sẽ có giá trị this là undefined và một error khi truy xuất thuộc tính bar của this đó.
  2. obj1.foo() this trỏ về đối tượng obj1.
  3. foo.call(obj2) this trỏ về đối tượng obj2.
  4. new foo() khởi tạo một đối tượng hoàn toàn mới là một object rỗng.

Kết luận: Để hiểu THIS trỏ về đâu bạn phải biết được function đó được gọi từ đâu hay từ ngữ cảnh thực thị nào.

Prototypes

Prototype trong JS khá là phức tạp. Chúng ta chỉ sơ lược một chút về nó trong phần này. Bạn sẽ muốn dành nhiều thời gian cho nó vào phần tiếp theo.

Khi mà bạn truy xuất một thuộc tính của một object trong JS, nếu thuộc tính đó không tồn tại, JS sẽ tự động sử dụng một object khác liên kêt bên trong object đó để tìm thuộc tính đó. Bạn có thể hiểu prototype như một object fallback khi mà chúng ta tìm một thuộc tính không có trong object đó.

Hơi khó hiểu phải không nào, chúng ta thử tìm hiểu ví dụ cụ thể sau nhé:

var foo = {
	a: 42
};

// create `bar` and link it to `foo`
var bar = Object.create( foo );

bar.b = "hello world";

bar.b;		// "hello world"
bar.a;		// 42 <-- delegated to `foo`

Chúng ta có thể vẽ sơ đồ như sau:

Thuộc tính a không tồn tai trong object bar, bởi vì bar có một prototyp liên kết với foo cho nên JS sẽ tự động tìm a trong foo.

Liên kết prototype có vẻ lạ trong lập trình. Nhưng trong JS đây là kỹ thuật được dùng để tạo nên sự thừa kế của các đối tượng với nhau.

Old & New

Hiện tại chúng ta có khá nhiều trình duyệt khác nhau như: Chrome, Safari, Firefox, Edge, … Cho nên một trong những thử thách của nhà làm web là phải hỗ trợ được tính năng hoạt động đúng đắn trên nhiều trình duyệt khác nhau(cross-browser support)

Với những trình duyệt hiện đại như Chrome chúng ta sẽ có sử dụng được phiên bản mơi nhất của JS là ES6 nhưng chúng ta cần có giải pháp để hỗ trợ những trình duyệt cũ hơn như: Safiri, Edge,…

Có hai kỹ thuật chính để bạn có thể sử dụng những thứ mới mẻ của JS trên những trình duyệt cũ hơn đó là: polyfilling và transpilling.

Polyfilling

Đây là cách kiểm tra xem nếu một function hay chức năng không hỗ trợ trên những trình duyệt cũ thì sẽ có nhưng cài đặt thay thế như trong ES6 có một hàm gọi là Number.isNaN(…)

if (!Number.isNaN) {
	Number.isNaN = function isNaN(x) {
		return x !== x;
	};
}


Transpiling

Không có cách nào để polyfill những cú pháp mới được thêm vào trong một ngôn ngữ. Cho nên cách tốt nhất là sử dụng tool để chuyển đổi từ cú pháp mới sang cú pháp cũ.

Ví dụ như chúng ta có tính năng default parameter trong ES6:

function foo(a = 2) {
	console.log( a );
}

foo();		// 2
foo( 42 );	// 42

Cú pháp này chỉ chạy được trên những trình duyệt hiện đại như Chrome và với những trình duyệt chưa hỗ trợ ES6, chúng ta cần chuyển đổi đoạn code trên thành(Babel):

function foo() {
  var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 2;
  console.log(a);
}

Có một số transpiler thông dụng hiện nay là:

Non-Javasccript

Cho đến lúc này chúng ta đã tìm hiểu về một số thành phần trong JS. Nhưng để tạo nên một website chúng ta cần một số thao tác lên DOM như sau:

const element = document.querySelector('#id');

JS không quản lí những biến global như document, window, alert, console ,… Những thằng này là do trình duyệt sinh ra nhằm thao tác với DOM. Nhưng bạn chắc chắn sẽ gặp chúng thường xuyên bởi vì để tạo nên những website có tương tác với người dùng thì chúng ta cần những API như querySelector hay getElementById.

Review

Chúc mừng bạn đã tìm hiểu được một số khái niệm cơ bản nhất trong JS. Đây là bước đầu tiên đê chúng ta có thể tiến sâu hơn và trở thành một lập trình viên chuyên nghiệp. Cho tới thời điểm này chúng ta đã có thể năm được những thành phần như: values, types, scope, function, variable, closure, this, prototype.

Tất nhiên là chúng ta sẽ đi sâu hơn từng phần ở những bài viết sau.

thaunguyen.com via You don’t know JS

Leave a Comment