1
0
mirror of https://github.com/adambard/learnxinyminutes-docs.git synced 2025-08-30 10:00:26 +02:00

Simplify language codes in directories

This commit is contained in:
Boris Verkhovskiy
2024-12-08 20:29:09 -07:00
parent 3da692272f
commit 912da583da
489 changed files with 0 additions and 0 deletions

391
vi/git.md Normal file
View File

@@ -0,0 +1,391 @@
---
category: tool
tool: Git
contributors:
- ["Jake Prather", "http://github.com/JakeHP"]
- ["Vinh Nguyen", "https://twitter.com/vinhnx"]
filename: LearnGit-vi.txt
lang: vi-vn
---
Git là một hệ quản lý mã nguồn và phiên bản phân tán (distributed version control and source code management system).
Nó làm được điều này là do một loạt các snapshot từ đề án của bạn, và nó hoạt động
với các snapshot đó để cung cấp cho bạn với chức năng đến phiên bản và
quản lý mã nguồn của bạn.
## Khái Niệm Versioning
### Version Control là gì?
Version Control là một hệ thống ghi lại những thay đổi ở một tập tin, hay một nhóm các tập tin, theo thời gian.
### So sánh giữa Centralized Versioning và Distributed Versioning
* Quản lý phiên bản tập trung (Centralized Versioning) tập trung vào việc đồng bộ hóa, theo dõi, và lưu trữ tập tin.
* Quản lý phiên bản phân tán (Distributed Versioning) tập trung vào việc chia sẻ các thay đổi. Mỗi sự thay đổi có một mã định dạng (id) duy nhất.
* Các hệ phân tán không có cấu trúc định sẵn. Bạn có thể thay đổi một kiểu SVN, hệ phân tán, với git.
[Thông tin thêm](https://git-scm.com/book/en/v2/Getting-Started-About-Version-Control)
### Tại Sao Dùng Git?
* Có thể hoạt động offline.
* Cộng tác với nhau rất dễ dàng!
* Phân nhánh dễ dàng!
* Trộn (Merging)
* Git nhanh.
* Git linh hoạt.
## Kiến Trúc Git
### Repository
Một nhóm các tập tin, thư mục, các ghi chép trong quá khứ, commit, và heads. Tưởng tượng nó như là một cấu trúc dữ liệu mã nguồn,
với thuộc tính mà một "nhân tố" mã nguồn cho bạn quyền truy cập đến lịch sử sửa đổi, và một số thứ khác.
Một git repository bao gồm thư mục .git & tree đang làm việc.
### Thư mục .git (thành phần của một repository)
Thư mục .git chứa tất cả các cấu hình, log, nhánh, HEAD, và hơn nữa.
[Danh Sách Chi Tiết.](https://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html)
### Tree Đang Làm (thành phần của một repository)
Đây cơ bản là các thư mục và tập tin trong repository của bạn. Nó thường được tham chiếu
thư mục đang làm việc của bạn
### Chỉ mục (thành phần của một thư mục .git)
Chỉ mục của là một staging area trong git. Nó đơn giản là một lớp riêng biệt với tree đang làm việc của bạn
từ Git repository. Điều này cho nhà phát triền nhiều lựa chọn hơn trong việc xem xét những gì được gửi đến Git
repository.
### Commit
Một git commit là một snapshot của một nhóm các thay đổi, hoặc các thao tác Working Tree của bạn.
Ví dụ, nếu bạn thêm 5 tập tin, và xóa 2 tập tin khác, những thay đổi này sẽ được chứa trong
một commit (hoặc snapshot). Commit này có thể được đẩy đến các repo khác, hoặc không!
### Nhánh
Nhánh thực chất là một con trỏ đến commit mới nhất mà bạn vừa thực hiện. Khi bạn commit,
con trỏ này sẽ cập nhật tự động và trỏ đến commit mới nhất.
### HEAD và head (thành phần của thư mục .git)
HEAD là một con trỏ đến branch hiện tại. Một repo chỉ có một HEAD *đang hoạt động*.
head là một con trỏ đến bất kỳ commit nào. Một repo có thể có nhiều head.
## Các Lệnh
### init
Tạo một repo Git rỗng. Các cài đặt, thông tin lưu trữ... của Git
được lưu ở một thư mục tên là ".git".
```bash
$ git init
```
### config
Để chỉnh tùy chọn. Bất kể là cho repo, hay cho hệ thống, hay điều chỉnh
toàn cục (global)
```bash
# In Ra & Và Gán Một Số Biến Tùy Chỉnh Cơ Bản (Toàn cục - Global)
$ git config --global user.email
$ git config --global user.name
$ git config --global user.email "MyEmail@Zoho.com"
$ git config --global user.name "My Name"
```
[Tìm hiểu thêm về git config.](https://git-scm.com/docs/git-config)
### help
Để cho bạn lối truy cập nhanh đến một chỉ dẫn cực kỳ chi tiết của từng lệnh. Hoặc chỉ để
nhắc bạn một số cú pháp.
```bash
# Xem nhanh các lệnh có sẵn
$ git help
# Xem tất các các lệnh
$ git help -a
# Lệnh help riêng biệt - tài liệu người dùng
# git help <command_here>
$ git help add
$ git help commit
$ git help init
```
### status
Để hiển thị sự khác nhau giữa tập tin index (cơ bản là repo đang làm việc) và HEAD commit
hiện tại.
```bash
# Sẽ hiển thị nhánh, các tập tin chưa track (chưa commit), các thay đổi và những khác biệt khác
$ git status
# Để xem các "tid bits" về git status
$ git help status
```
### add
Để thêm các tập vào tree/thư mục/repo hiện tại. Nếu bạn không `git add` các tập tin mới đến
tree/thư mục hiện tại, chúng sẽ không được kèm theo trong các commit!
```bash
# thêm một file vào thư mục hiện tại
$ git add HelloWorld.java
# thêm một file vào một thư mục khác
$ git add /path/to/file/HelloWorld.c
# Hỗ trợ Regular Expression!
$ git add ./*.java
```
### branch
Quản lý nhánh (branch). Bạn có thể xem, sửa, tạo, xóa các nhánh bằng cách dùng lệnh này.
```bash
# liệt kê các branch đang có và ở remote
$ git branch -a
# tạo branch mới
$ git branch myNewBranch
# xóa một branch
$ git branch -d myBranch
# đặt tên lại một branch
# git branch -m <oldname> <newname>
$ git branch -m myBranchName myNewBranchName
# chỉnh sửa diễn giải của một branch
$ git branch myBranchName --edit-description
```
### checkout
Cập nhật tất cả các file trong tree hiện tại để cho trùng khớp với phiên bản của index, hoặc tree cụ thể.
```bash
# Checkout (chuyển) một repo - mặc định là nhánh master
$ git checkout
# Checkout một nhánh cụ thể
$ git checkout branchName
# Tạo một nhánh mới và chuyển đến nó, tương tự: "git branch <name>; git checkout <name>"
$ git checkout -b newBranch
```
### clone
Nhân bản, hoặc sao chép, một repo hiện có thành một thư mục mới. Nó cũng thêm
các branch có remote-tracking cho mỗi branch trong một repo được nhân bản, mà
cho phép bạn push đến một remote branch.
```bash
# Nhân bản learnxinyminutes-docs
$ git clone https://github.com/adambard/learnxinyminutes-docs.git
```
### commit
Lưu trữ nội dung hiện tại của index trong một "commit" mới. Điều này cho phép tạo ra thay đổi và một ghi chú tạo ra bởi người dùng.
```bash
# commit với một ghi chú
$ git commit -m "Added multiplyNumbers() function to HelloWorld.c"
```
### diff
Hiển thị sự khác biệt giữa một file trong thư mục hiện tại, index và commits.
```bash
# Hiển thị sự khác biệt giữa thư mục hiện tại và index
$ git diff
# Hiển thị khác biệt giữa index và commit mới nhất.
$ git diff --cached
# Hiển thị khác biệt giữa thư mục đang làm việc và commit mới nhất
$ git diff HEAD
```
### grep
Cho phép bạn tìm kiếm nhanh một repo.
Các tinh chỉnh tùy chọn:
```bash
# Cảm ơn Travis Jeffery vì những lệnh này
# Đặt số của dòng được hiển thị trong kết quả tìm kiếm grep
$ git config --global grep.lineNumber true
# Làm cho kết quả tìm kiếm dễ đọc hơn, bao gồm cả gom nhóm
$ git config --global alias.g "grep --break --heading --line-number"
```
```bash
# Tìm "variableName" trong tất cả các file Java
$ git grep 'variableName' -- '*.java'
# Tìm một dòng mà có chứa "arrayListName" và, "add" hoặc "remove"
$ git grep -e 'arrayListName' --and \( -e add -e remove \)
```
Google để xem thêm các ví dụ
[Git Grep Ninja](https://travisjeffery.com/b/2012/02/search-a-git-repo-like-a-ninja)
### log
Hiển thị các commit đến repo.
```bash
# Hiện tất cả các commit
$ git log
# Hiện X commit
$ git log -n 10
# Chỉ hiện các commit đã merge merge commits
$ git log --merges
```
### merge
"Trộn" các thay đổi từ commit bên ngoài vào trong nhánh hiện tại.
```bash
# Merge branch cụ thể vào branch hiện tại.
$ git merge branchName
# Luôn khởi tạo một merge commit khi trộn (merge)
$ git merge --no-ff branchName
```
### mv
Đặt lại tên hoặc di chuyển một file
```bash
# Đặt lại tên một file
$ git mv HelloWorld.c HelloNewWorld.c
# Di chuyển một file
$ git mv HelloWorld.c ./new/path/HelloWorld.c
# Buộc đặt lại tên hoặc di chuyển
# "existingFile" đã tồn tại trong thự mục, sẽ bị ghi đè
$ git mv -f myFile existingFile
```
### pull
Pull về từ một repo và merge nó vào branch khác.
```bash
# Cập nhật repo local của bạn, bằng cách merge các thay đổi mới
# từ remote "origin" và nhánh "master".
# git pull <remote> <branch>
# git pull => hoàn toàn mặc định như => git pull origin master
$ git pull origin master
# Merge các thay đổi từ remote branch và rebase
# các commit trong branch lên trên local repo, như sau: "git pull <remote> <branch>, git rebase <branch>"
$ git pull origin master --rebase
```
### push
push và merge các thay đổi từ một branch đến một remote & branch.
```bash
# Push và merge các thay đổi từ một repo local đến một
# remote có tên là "origin" và nhánh "master".
# git push <remote> <branch>
# git push => mặc định ẩn đến => git push origin master
$ git push origin master
# Để liên kết đến một branch local với một branch remote, thêm vào cờ -u:
$ git push -u origin master
# Từ lúc này, bất cứ khi nào bạn muốn push từ cùng một nhánh local đó, sử dụng lối tắt:
$ git push
```
### rebase (thận trọng)
Lấy tất cả các thay đổi mà đã được commit trên một nhánh, và replay (?) chúng trên một nhánh khác.
*Không rebase các commit mà bạn đã push đến một repo công khai*.
```bash
# Rebase experimentBranch lên master
# git rebase <basebranch> <topicbranch>
$ git rebase master experimentBranch
```
[Đọc Thêm.](https://git-scm.com/book/en/v2/Git-Branching-Rebasing)
### reset (thận trọng)
Thiết lập lạo HEAD hiện tại đến một trạng thái cụ thể. Điều này cho phép bạn làm lại các merges,
pulls, commits, thêm, and hơn nữa. Nó là một lệnh hay nhưng cũng nguy hiểm nếu bạn không
biết mình đang làm gì.
```bash
# Thiết lập lại staging area, để trùng với commit mới nhất (để thư mục không thay đổi)
$ git reset
# Thiết lập lại staging area, để trùng với commit mới nhất, và ghi đè lên thư mục hiện tại
$ git reset --hard
# Di chuyển nhánh hiện tại đến một commit cụ thể (để thư mục không thay đổi)
# tất cả thay đổi vẫn duy trì trong thư mục.
$ git reset 31f2bb1
# Di chuyển nhánh hiện tại lùi về một commit cụ thể
# và làm cho thư mục hiện tại trùng (xóa các thay đổi chưa được commit và tất cả các commit
# sau một commit cụ thể).
$ git reset --hard 31f2bb1
```
### rm
Ngược lại với git add, git rm xóa file từ tree đang làm việc.
```bash
# xóa HelloWorld.c
$ git rm HelloWorld.c
# Xóa file từ thư mục khác
$ git rm /pather/to/the/file/HelloWorld.c
```
## Thông tin thêm
* [git-scm - Video Tutorials](https://git-scm.com/videos)
* [git-scm - Documentation](https://git-scm.com/docs)
* [Atlassian Git - Tutorials & Workflows](https://www.atlassian.com/git/)
* [Git - the simple guide](https://rogerdudler.github.io/git-guide/index.html)
* [Git For Computer Scientists](https://eagain.net/articles/git-for-computer-scientists/)

122
vi/html.md Normal file
View File

@@ -0,0 +1,122 @@
---
language: HTML
filename: learnhtml-vi.txt
contributors:
- ["Christophe THOMAS", "https://github.com/WinChris"]
translators:
- ["Robert Steed", "https://github.com/robochat"]
- ["Xuan (Sean) Luong", "https://github.com/xuanluong"]
lang: vi-vn
---
HTML là viết tắt của HyperText Markup Language (Ngôn ngữ đánh dấu siêu văn bản).
Nó là một ngôn ngữ cho phép chúng ta viết nên những trang web.
Nó là một ngôn ngữ đánh dấu, cho phép chúng ta viết trang web bằng code để chỉ định cách thức mà văn bản và dữ liệu nên được trình bày.
Tập tin html thực chất chỉ là một tập tin văn bản đơn giản.
Đánh dấu có nghĩa là gì? Nó là một phương pháp tổ chức dữ liệu của một trang web bằng cách bao quanh dữ liệu bởi các thẻ (tags) mở và đóng.
Việc đánh dấu phục vụ mục đích cung cấp tầm quan trọng của phần văn bản mà nó bao quanh.
Cũng như các ngôn ngữ máy tính khác, HTML có nhiều phiên bản. Ở đây chúng ta nói về HTML5.
**Lưu ý :** Bạn có thể thử nghiệm những thẻ và phần tử HTML khác nhau trong quá trình đọc bài viết bằng cách truy cập những trang web như [codepen](http://codepen.io/pen/) để có thể thấy được tác dụng của những thẻ hay phần tử HTML đó,
nhằm hiểu cách chúng hoạt động và làm quen với ngôn ngữ HTML.
Bài viết này chủ yếu bàn về cú pháp của HTML và một vài mẹo hữu dụng.
```html
<!-- Bình luận được bao quanh bởi các ký tự giống như trong ví dụ này -->
<!-- #################### Các thẻ #################### -->
<!-- Dưới đây là tập tin HTML ví dụ mà chúng ta sẽ phân tích. -->
<!doctype html>
<html>
<head>
<title>Trang web của tôi</title>
</head>
<body>
<h1>Xin chào!</h1>
<a href = "http://codepen.io/anon/pen/xwjLbZ">Truy cập để biết cái gì sẽ được hiển thị</a>
<p>Đây là một văn bản.</p>
<p>Một văn bản khác.</p>
<ul>
<li>Đây là một danh sách không liệt kê</li>
<li>Đây là một danh sách không liệt kê khác</li>
<li>Danh sách không liệt kê cuối cùng của danh sách cha</li>
</ul>
</body>
</html>
<!-- Một tập tin HTML luôn bắt đầu bằng việc thể hiện cho trình duyệt rằng nó là một trang HTML -->
<!doctype html>
<!-- Sau đó nó bắt đầu với một thẻ <html> mở -->
<html>
<!-- thẻ đó sẽ được đóng vào cuối tập tin bằng một thẻ đóng </html>. -->
</html>
<!-- Không nên viết gì sau thể đóng cuối cùng này. -->
<!-- Ở bên trong (giữa thẻ đóng và mở <html></html>), ta tìm thấy: -->
<!-- Phần đầu được định nghĩa bằng <head> (và phải được đóng lại bằng </head>). -->
<!-- Phần đầu chứa một vài định nghĩa và những thông tin khác không được dùng để hiển thị; đây gọi là siêu dữ liệu (metadata) -->
<head>
<title>Trang web của tôi</title><!-- Thẻ <title> cho trình duyệt biết dòng chữ để hiển thị trên thanh tựa đề của trình duyệt vả tên tab. -->
</head>
<!-- Sau phần <head> ta sẽ gặp thẻ <body> -->
<!-- Cho tới đây, chưa có gì được hiển thị trên cửa sổ trình duyệt. -->
<!-- Chúng ta phải đưa nội dùng vào phần <body> để hiển thị. -->
<body>
<h1>Xin chào!</h1> <!-- Thẻ h1 tạo ra một đề mục. -->
<!-- Ngoài <h1> ra ta còn có những đề mục cấp thấp hơn, từ h2 đến h6 -->
<a href = "http://codepen.io/anon/pen/xwjLbZ">Truy cập để biết cái gì sẽ được hiển thị</a> <!-- một liên kết đền một url được cung cấp bởi thuộc tính href="" -->
<p>Đây là một văn bản.</p> <!-- Thẻ <p> cho phép đưa văn bản vào trang html. -->
<p>Một văn bản khác.</p>
<ul> <!-- Thẻ <ul> tạo ra danh sách không đánh s. -->
<!-- Để có một danh sách có đánh số ta dùng thể <ol> thay vì <ul> từ đó sẽ có số thứ tự 1. cho phần tử đầu tiên, 2. cho phần tử thứ hai, v.v... -->
<li>Đây là một danh sách không liệt kê</li>
<li>Đây là một danh sách không liệt kê khác</li>
<li>Danh sách không liệt kê cuối cùng của danh sách cha</li>
</ul>
</body>
<!-- Và ta đã có một tập tim HTML. Việc tạo ra tập tin HTML có thể được thực hiện một cách đơn giản. -->
<!-- Những ta cũng có thể thêm vào những loại thẻ HTML khác. -->
<!-- Chèn vào một ảnh. -->
<img src="http://i.imgur.com/XWG0O.gif"/> <!-- Nguồn của ảnh sẽ được khai báo qua thuộc tính src="" -->
<!-- Nguồn ảnh có thể là một URL hoặc đường dẫn tới một tập tin trong máy. -->
<!-- Ta cũng có thể tạo ra một table. -->
<table> <!-- Tạo bảng với thẻ <table>. -->
<tr> <!-- <tr> dùng để tạo ra một hàng. -->
<th>Cột một</th> <!-- <th> dùng để khai báo tên cột. -->
<th>Cột hai</th>
</tr>
<tr>
<td>hàng một, cột một</td> <!-- <td> dùng để tạo ra một ô trong table. -->
<td>hàng một, cột hai</td>
</tr>
<tr>
<td>hàng hai, cột một</td>
<td>hàng hai, cột hai</td>
</tr>
</table>
```
## Cách sử dụng
HTML được viết trong tập tin có phần mở rộng `.html`.
## Thông tin mở rộng
* [wikipedia](https://vi.wikipedia.org/wiki/HTML)
* [HTML tutorial](https://developer.mozilla.org/en-US/docs/Web/HTML)
* [W3School](http://www.w3schools.com/html/html_intro.asp)

76
vi/json.md Normal file
View File

@@ -0,0 +1,76 @@
---
language: JSON
filename: learnjson-vi.json
contributors:
- ["Anna Harren", "https://github.com/iirelu"]
- ["Marco Scannadinari", "https://github.com/marcoms"]
- ["himanshu", "https://github.com/himanshu81494"]
translators:
- ["Thanh Phan", "https://github.com/thanhpd"]
lang: vi-vn
---
Do JSON là một ngôn ngữ trao đổi dữ liệu hết sức đơn giản, đây có thể sẽ là bài
đơn giản nhất của Học X trong Y phút (Learn X in Y Minutes) từ trước tới nay.
JSON ở dạng thuần túy nhất không có chú thích cho câu lệnh (comment) nào, nhưng
hầu hết các trình phân tích cú pháp (parser) đều chấp nhận chú thích theo phong
cách của ngôn ngữ C (`//`, `/* */`). Một số trình phân tích cú pháp còn chấp
nhận dấu phẩy cuối cùng (vd: một dấu phẩy sau phần tử cuối cùng của một mảng
hoặc sau thuộc tính cuối cùng của một object), nhưng những trường hợp này nên
tránh để có sự tương thích tốt hơn.
Để phục vụ cho mục đích bài học này, tất cả cú pháp JSON ở đây sẽ đều là 100% hợp lệ.
May mắn thay, chúng cũng tự trình bày cho chính mình mà không cần thêm giải thích.
Các kiểu dữ liệu được JSON hỗ trợ bao gồm: số (*numbers*), chuỗi kí tự
(*string*), toán tử đúng/sai (*boolean*), mảng (*array*), *object**null*.
Các trình duyệt hỗ trợ bao gồm: Mozilla Firefox phiên bản 3.5 trở lên,
Internet Explorer 8 trở lên, Google Chrome, Opera 10 trở lên, Safari 4 trở lên.
Kiểu tệp JSON có dạng ".json". Kiểu MIME (Multipurpose Internet Mail Extensions)
cho JSON là "application/json". Điểm yếu của JSON đó là thiếu các định dạng cho
kiểu dữ liệu cũng như quy chuẩn cú pháp chặt chẽ sử dụng DTD.
```json
{
"khóa": "dữ liệu",
"các khóa": "phải luôn được đặt trong dấu ngoặc kép",
"số": 0,
"chuỗi kí tự": "Xin chàø. Tất cả kí tự unicode đều được chấp nhận, sử dụng với dạng \"kí tự\".",
"có đúng không?": true,
"không có gì": null,
"số rất lớn": 1.2e+100,
"objects": {
"chú thích": "Hầu hết các cấu trúc dữ liệu bạn sẽ dùng sẽ sử dụng object.",
"mảng": [0, 1, 2, 3, "Mảng có thể chứa bất kì thứ gì bên trong.", 5],
"một object khác": {
"chú thích": "Những thứ này có thể lồng vào nhau, rất tiện."
}
},
"ngớ ngẩn": [
{
"nguồn cung cấp kali": ["chuối"]
},
[
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, "neo"],
[0, 0, 0, 1]
]
],
"phong cách khác": {
"chú thích": "kiểm tra cái này xem!"
, "vị trí dấu phẩy": "không quan trọng - chỉ cần nó ở trước khóa tiếp theo là được"
, "chú thích khác": "tiện phải không"
},
"nó rất ngắn": "Và bạn đã xong rồi đấy. Bạn đã biết tất cả những thứ mà JSON có thể cung cấp."
}
```

391
vi/less.md Normal file
View File

@@ -0,0 +1,391 @@
---
language: Less
contributors:
- ["Saravanan Ganesh", "http://srrvnn.me"]
translators:
- ["Thanh Duy Phan", "https://github.com/thanhpd"]
filename: learnless-vi.less
lang: vi-vn
---
Less là một CSS pre-processor (bộ tiền xử lí CSS), nó thêm các tính năng như biến (variable), lồng (nesting), mixin và nhiều thứ khác. Less cùng với các CSS pre-processor khác như [Sass](http://sass-lang.com/) giúp lập trình viên viết được các đoạn CSS bảo trì được và không bị lặp lại (DRY - Don't Repeat Yourself).
```less
// Comment (chú thích) một dòng sẽ bị xóa khi Less được biên dịch thành CSS
/* Comment trên nhiều dòng sẽ được giữ lại */
/* Biến
==============================*/
/* Ta có thể lưu giá trị CSS (ví dụ như color) vào một biến.
Sử dụng ký hiệu '@' để khai báo một biến. */
@primary-color: #a3a4ff;
@secondary-color: #51527f;
@body-font: 'Roboto', sans-serif;
/* Sau khi khai báo biến, ta có thể sử dụng nó ở trong tệp stylesheet.
Nhờ sử dụng biến ta chỉ cần thay đổi một lần
tại 1 nơi để thay đổi tất cả những đoạn sử dụng biến */
body {
background-color: @primary-color;
color: @secondary-color;
font-family: @body-font;
}
/* Đoạn code trên sẽ được biên dịch thành: */
body {
background-color: #a3a4ff;
color: #51527F;
font-family: 'Roboto', sans-serif;
}
/* Cách sử dụng này giúp ta dễ dàng bảo trì hơn
việc phải đổi giá trị mỗi lần nó xuất hiện
trong tệp stylesheet. */
/* Mixins
==============================*/
/* Nếu đang viết một đoạn code cho nhiều hơn một
element, ta có thể sử dụng lại nó dễ dàng. */
.center {
display: block;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
/* Ta có thể dùng mixin chỉ bằng việc thêm selector
vào trong nội dung style của element khác */
div {
.center;
background-color: @primary-color;
}
/* Đoạn code trên sẽ được biên dịch thành: */
.center {
display: block;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
div {
display: block;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
background-color: #a3a4ff;
}
/* Ta có thể ngăn không cho code mixin được biên dịch
bằng cách thêm cặp ngoặc tròn đằng sau selector */
.center() {
display: block;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
div {
.center;
background-color: @primary-color;
}
/* Đoạn code trên sẽ được biên dịch thành: */
div {
display: block;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
background-color: #a3a4ff;
}
/* Nesting - Lồng
==============================*/
/* Less cho phép ta có thể lồng selector bên trong selector */
ul {
list-style-type: none;
margin-top: 2em;
li {
background-color: #f00;
}
}
/* Selector bắt đầu bằng ký tự '&' sẽ thay thế ký tự '&'
với selector cha. */
/* Ta cũng có thể lồng các pseudo-class với nhau */
/* Nên lưu ý không nên lồng quá nhiều lần sẽ làm code kém tính bảo trì.
Kinh nghiệm cho thấy không nên lồng quá 3 lần.
Ví dụ: */
ul {
list-style-type: none;
margin-top: 2em;
li {
background-color: red;
&:hover {
background-color: blue;
}
a {
color: white;
}
}
}
/* Biên dịch thành: */
ul {
list-style-type: none;
margin-top: 2em;
}
ul li {
background-color: red;
}
ul li:hover {
background-color: blue;
}
ul li a {
color: white;
}
/* Function
==============================*/
/* Less cung cấp các function có thể được dùng để hoàn thành
các công việc khác nhau. */
/* Function được gọi sử dụng tên của nó và truyền vào
các tham số được yêu cầu. */
body {
width: round(10.25px);
}
.header {
background-color: lighten(#000, 0.5);
}
.footer {
background-color: fadeout(#000, 0.25)
}
/* Biên dịch thành: */
body {
width: 10px;
}
.header {
background-color: #010101;
}
.footer {
background-color: rgba(0, 0, 0, 0.75);
}
/* Ta có thể định nghĩa function mới.
Function khá tương tự với mixin bởi chúng đều có thể được tái
sử dụng. Khi lựa chọn giữa việc sử dụng function hay mixin,
hãy nhớ mixin được tối ưu cho việc tạo ra CSS trong khi
function sẽ được sử dụng tốt hơn cho logic sẽ được sử dụng
xuyên suốt Less code. Các ví dụ trong phần 'Toán tử' là ứng cử viên
sáng giá cho việc dùng function có thể tái sử dụng được.
*/
/* Function này tính giá trị trung bình của hai số: */
.average(@x, @y) {
@average-result: ((@x + @y) / 2);
}
div {
.average(16px, 50px); // gọi mixin
padding: @average-result; // sử dụng giá trị trả về của mixin
}
/* Biên dịch thành: */
div {
padding: 33px;
}
/* Mở rộng (Thừa kế)
==============================*/
/* Mở rộng là cách để chia sẻ thuộc tính của một selector cho selector khác */
.display {
height: 50px;
}
.display-success {
&:extend(.display);
border-color: #22df56;
}
/* Biên dịch thành: */
.display,
.display-success {
height: 50px;
}
.display-success {
border-color: #22df56;
}
/* Nên mở rộng một khai báo CSS có trước thay vì tạo một mixin mới
bởi cách nó nhóm các lớp có chung một style gốc.
Nếu thực hiện với mixin, các thuộc tính sẽ bị trùng lặp
cho mỗi khai báo có sử dụng mixin. Mặc dù không ảnh hưởng đến luồng công việc nhưng nó
tạo ra các đoạn code CSS thừa sau khi được biên dịch.
*/
/* Partials and Imports - Chia nhỏ và nhập vào
==============================*/
/* Less cho phép ta tạo các partial file (tệp con).
Sử dụng nó giúp ta có thể tổ chức code Less theo mô-đun có hệ thống.
Các tệp con thường bắt đầu với ký tự gạch dưới '_', vd: _reset.less
và được nhập vào file Less chính để được biên dịch thành CSS */
/* Quan sát ví dụ sau, ta sẽ đặt đoạn code dưới đây vào tệp tên là _reset.less */
html,
body,
ul,
ol {
margin: 0;
padding: 0;
}
/* Less cung cấp cú pháp @import cho phép nhập các partial vào một file.
Cú pháp này trong Less sẽ nhập các file và kết hợp chúng lại với
code CSS được sinh ra. Nó khác với cú pháp @import của CSS,
bản chất là tạo một HTTP request mới để tải về tệp tin được yêu cầu. */
@import 'reset';
body {
font-size: 16px;
font-family: Helvetica, Arial, Sans-serif;
}
/* Biên dịch thành: */
html, body, ul, ol {
margin: 0;
padding: 0;
}
body {
font-size: 16px;
font-family: Helvetica, Arial, Sans-serif;
}
/* Toán học
==============================*/
/* Less cung cấp các toán tử sau: +, -, *, / và %.
Điều này rất có ích cho việc tính toán giá trị trực tiếp
trong tệp Less thay vì phải tính toán thủ công.
Dưới đây là ví dụ về việc tạo một khung thiết kế đơn giản có hai cột. */
@content-area: 960px;
@main-content: 600px;
@sidebar-content: 300px;
@main-size: @main-content / @content-area * 100%;
@sidebar-size: @sidebar-content / @content-area * 100%;
@gutter: 100% - (@main-size + @sidebar-size);
body {
width: 100%;
}
.main-content {
width: @main-size;
}
.sidebar {
width: @sidebar-size;
}
.gutter {
width: @gutter;
}
/* Biên dịch thành: */
body {
width: 100%;
}
.main-content {
width: 62.5%;
}
.sidebar {
width: 31.25%;
}
.gutter {
width: 6.25%;
}
```
## Tập sử dụng Less
Nếu bạn cần xài thử Less trên trình duyệt, hãy ghé qua:
* [Codepen](http://codepen.io/)
* [LESS2CSS](http://lesscss.org/less-preview/)
## Tính tương thích
Less có thể được dùng trong bất kì dự án nào miễn là ta có chương trình để biên dịch nó thành CSS. Ta cần chắc chắn rằng đoạn CSS đang dùng tương thích với các phiên bản trình duyệt mong muốn.
[QuirksMode CSS](http://www.quirksmode.org/css/) và [CanIUse](http://caniuse.com) là nguồn thông tin tin cậy để kiểm tra tính tương thích của mã CSS.
## Tìm hiểu thêm
* [Tài liệu chính thức](http://lesscss.org/features/)
* [Less CSS - Hướng dẫn cho người mới bắt đầu](http://www.hongkiat.com/blog/less-basic/)

326
vi/markdown.md Normal file
View File

@@ -0,0 +1,326 @@
---
language: Markdown
contributors:
- ["Dan Turkel", "http://danturkel.com/"]
- ["Jacob Ward", "http://github.com/JacobCWard/"]
translators:
- ["Thanh Duy Phan", "https://github.com/thanhpd"]
filename: markdown-vi.md
lang: vi-vn
---
Ngôn ngữ Markdown được sáng lập bởi John Gruber vào năm 2004. Nó được tạo ra với mục đích dễ đọc với cú pháp có thể được dễ dàng chuyển đổi qua HTML và các ngôn ngữ khác
Markdown có sự khác biệt trong cách cài đặt giữa các trình phân tích cú pháp. Hướng dẫn này sẽ đề cập, giải thích tới nếu tính năng có thể được sử dụng chung hay nó chỉ áp dụng cho một trình phân tích riêng biệt.
## Phần tử HTML
Markdown là tập cha của HTML, vì vậy bất cứ file HTML nào đều là Markdown đúng.
```md
<!-- Điều này đồng nghĩa ta có thể sử dụng các phần tử HTML
trong Markdown, ví dụ như phần tử chú thích/comment.
Tuy nhiên, nếu sử dụng một phần tử HTML trong file Markdown,
ta không thể sử dụng cú pháp Markdown cho nội dung bên trong phần tử đó. -->
```
## Đầu mục
Ta có thể tạo các phần tử đầu mục HTML từ `<h1>` cho đến `<h6>` dễ dàng
bằng cách thêm số lượng dấu thăng (#) đằng trước chuỗi cần tạo đầu mục.
```md
# Đây là đầu mục <h1>
## Đây là đầu mục <h2>
### Đây là đầu mục <h3>
#### Đây là đầu mục <h4>
##### Đây là đầu mục <h5>
###### Đây là đầu mục <h6>
```
Markdown còn cung cấp cách khác để tạo đầu mục hạng nhất h1 và hạng nhì h2.
```md
Đây là đầu mục h1
=============
Đây là đầu mục h2
-------------
```
## Định dạng văn bản
Văn bản có thể được định dạng dễ dàng như in nghiêng hay làm đậm sử dụng Markdown.
```md
*Đoạn văn bản này được in nghiêng.*
_Và đoạn này cũng như vậy._
**Đoạn văn bản này được in đậm.**
__Và đoạn này cũng vậy.__
***Đoạn văn bản này được in nghiêng và đậm.***
**_Cách này cũng tương tự_**
*__Và cách này nữa__*
```
Trong cài đặt Markdown để hiển thị file của GitHub,ta còn có gạch ngang:
```md
~~Đoạn văn bản này được gạch ngang.~~
```
## Đoạn văn
Đoạn văn bao gồm một hay nhiều dòng văn bản liên tiếp nhau được phân cách
bởi một hay nhiều dòng trống.
```md
Đây là đoạn văn thứ nhất.
Đây là đoạn văn thứ hai.
Dòng này vẫn thuộc đoạn văn thứ hai, do không có cách dòng.
Đây là đoạn văn thứ ba.
```
Nếu cần chèn thêm thẻ ngắt dòng `<br />` của HTML, ta có thể kết thúc đoạn văn bản
bằng cách thêm vào từ 2 dấu cách (space) trở lên và bắt đầu đoạn văn bản mới.
```md
Dòng này kết thúc với 2 dấu cách (highlight để nhìn thấy).
Có phần tử <br /> ở bên trên.
```
Khối trích dẫn được sử dụng với kí tự >
```md
> Đây là khối trích dẫn. Ta có thể
> ngắt dòng thủ công và thêm kí tự `>` trước mỗi dòng hoặc ta có thể để dòng tự ngắt nếu cần thiệt khi quá dài.
> Không có sự khác biệt nào, chỉ cần nó bắt đầu với kí tự `>`
> Ta còn có thể dùng nhiều mức
>> của khối trích dẫn.
> Như vậy có tốt không?
```
## Danh sách
Danh sách không có thứ tự có thể được tạo sử dụng dấu sao, dấu cộng hay dấu trừ đầu dòng.
```md
* Một mục
* Một mục
* Một mục nữa
hoặc
+ Một mục
+ Một mục
+ Một mục khác
hay
- Một mục
- Một mục
- Một mục sau
```
Danh sách có thứ tự được tạo bởi một số theo sau bằng một dấu chấm.
```md
1. Mục thứ nhất
2. Mục thứ hai
3. Mục thứ ba
```
Ta không nhất thiết phải điền số thứ thự cho chỉ mục đúng mà Markdown sẽ tự hiển thị danh sách theo thứ tự đã được sắp xếp, tuy nhiên cách làm này không tốt!
```md
1. Mục thứ nhất
1. Mục thứ hai
1. Mục thứ ba
```
(Sẽ hiển thị như ví dụ trước đó)
Ta còn có thể sử dụng danh sách con
```md
1. Mục thứ nhất
2. Mục thứ hai
3. Mục thứ ba
* Mục nhỏ
* Mục nhỏ
4. Mục thứ tư
```
Markdown còn cung cấp danh mục (checklist). Nó sẽ hiển thị ra hộp đánh dấu dạng HTML.
```md
Boxes below without the 'x' are unchecked HTML checkboxes.
- [ ] First task to complete.
- [ ] Second task that needs done
This checkbox below will be a checked HTML checkbox.
- [x] This task has been completed
```
## Khối code
Ta có thể đánh dấu một đoạn code (tương tự sử dụng phần tử HTML `<code>`) bằng việc thụt đầu dòng sử dụng bốn dấu cách (space) hoặc một dấu nhảy (tab)
```md
This is code
So is this
```
Ta còn có thể thêm dấu nhảy (hoặc thêm vào bốn dấu cách nữa) để căn chỉnh phần bên trong đoạn code
```md
my_array.each do |item|
puts item
end
```
Code hiển thị cùng dòng có thể được đánh dấu sử dụng cặp ``.
```md
John didn't even know what the `go_to()` function did!
```
Trong Markdown của GitHub, ta còn có thêm cách để hiển thị code:
````md
```ruby
def foobar
puts "Hello world!"
end
```
````
Đoạn trên không cần sử dụng thụt đầu dòng, và GitHub sẽ tô sáng cú pháp sử dụng ngôn ngữ mà ta cung cấp sau đoạn kí tự <code>```</code>
## Kẻ ngang
Dòng kẻ ngang (`<hr />`) có thể được thêm vào dễ dàng sử dụng từ 3 kí tự sao (*) hoặc gạch ngang (-), không quan trọng có khoảng cách giữa các kí tự hay không.
```md
***
---
- - -
****************
```
## Liên kết
Một trong những thứ tốt nhất khi làm việc với Markdown là khả năng tạo liên kết hết sức dễ dàng. Đoạn text hiển thị được đóng trong cặp ngoặc vuông [] kèm theo đường dẫn url trong cặp ngoặc tròn ().
```md
[Click me!](http://test.com/)
```
Ta còn có thể tạo tiêu đề cho liên kết sử dụng cặp ngoặc nháy bên trong cặp ngoặc tròn
```md
[Click me!](http://test.com/ "Link to Test.com")
```
Đường dẫn tương đối cũng hoạt động.
```md
[Go to music](/music/).
```
Markdown còn hỗ trợ liên kết kiểu tham chiếu.
```md
[Nhấn vào đây][link1] để xem thêm!
[Ngoài ra nhấn vào đây][foobar] nếu bạn muốn xem qua.
[link1]: http://test.com/ "Tuyệt!"
[foobar]: http://foobar.biz/ "Tốt!"
```
Tiêu đề có thể được đóng trong dấu nháy hay ngoặc đơn, hoặc có thể được bỏ qua. Tham chiếu có thể được đặt bất kì đâu trong văn bản và ID của tham chiếu có thể là bất kì gì miễn là nó độc nhất.
Ngoài ra còn có kiểu đặt tên ngầm cho phép ta sử dụng đường dẫn làm ID.
```md
[This][] is a link.
[this]: http://thisisalink.com/
```
Nhưng nó không được sử dụng rộng rãi.
## Ảnh
Hiển thị ảnh tương tự như liên kết nhưng có thêm dấu chấm than đằng trước
```md
![Thuộc tính alt cho ảnh](http://imgur.com/myimage.jpg "Tiêu đề tùy chọn")
```
Và kiểu tham chiếu cũng hoạt động như vậy.
```md
![Đây là thuộc tính alt.][myimage]
[myimage]: relative/urls/cool/image.jpg "Đây là tiêu đề"
```
## Khác
### Tự động đặt liên kết
```md
<http://testwebsite.com/> tương đương với
[http://testwebsite.com/](http://testwebsite.com/)
```
### Tự động đặt liên kết cho email
```md
<foo@bar.com>
```
### Hiển thị Kí tự đặc biệt
```md
Khi ta muốn viết *đoạn văn bản này có dấu sao bao quanh* nhưng ta không muốn nó bị in nghiêng, ta có thể sử dụng: \*đoạn văn bản này có dấu sao bao quanh\*.
```
### Phím bàn phím
Trong Markdown của GitHub, ta có thể sử dụng thẻ `<kbd>` để thay cho phím trên bàn phím.
```md
Máy treo? Thử bấm tổ hợp
<kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Del</kbd>
```
### Bảng biểu
Bảng biểu được hỗ trợ trên Markdown của GitHub, Jira, Trello, v.v và khá khó viết:
```md
| Cột 1 | Cột2 | Cột 3 |
| :----------- | :------: | ------------: |
| Căn trái | Căn giữa | Căn phải |
| blah | blah | blah |
```
Hoặc có thể sử dụng kết quả dưới đây
```md
Cột 1 | Cột 2 | Cột 3
:-- | :-: | --:
blah | blah | blah
```
---
Để biết thêm thông tin, hãy ghé qua hướng dẫn chính thức về cú pháp của John Gruber [tại đây](http://daringfireball.net/projects/markdown/syntax) và cheatsheet của Adam Pritchard [tại đây](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).

314
vi/objective-c.md Normal file
View File

@@ -0,0 +1,314 @@
---
language: Objective-C
contributors:
- ["Eugene Yagrushkin", "www.about.me/yagrushkin"]
- ["Yannick Loriot", "https://github.com/YannickL"]
lang: vi-vn
filename: LearnObjectiveC-vi.m
---
Objective-C là ngôn ngữ lập trình chính được sử dụng bởi Apple cho các hệ điều hành macOS, iOS và các framework tương ứng của họ, Cocoa và Cocoa Touch.
Nó là một ngôn ngữ lập trình mục đích tổng quát, hướng đối tượng có bổ sung thêm kiểu truyền thông điệp giống Smalltalk vào ngôn ngữ lập trình C.
```objective-c
// Chú thích dòng đơn bắt đầu với //
/*
Chú thích đa dòng trông như thế này.
*/
// Nhập các headers của framework Foundation với cú pháp #import
#import <Foundation/Foundation.h>
#import "MyClass.h"
// Đầu vào chương trình của bạn là một hàm gọi là
// main với một kiểu trả về kiểu integer.
int main (int argc, const char * argv[])
{
// Tạo một autorelease pool để quản lý bộ nhớ vào chương trình
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// Sử dụng hàm NSLog() để in ra các dòng lệnh vào console
NSLog(@"Hello World!"); // Print the string "Hello World!"
///////////////////////////////////////
// Kiểu & Biến (Types & Variables)
///////////////////////////////////////
// Khai báo số nguyên
int myPrimitive1 = 1;
long myPrimitive2 = 234554664565;
// Khai báo đối tượng
// Đặt dấu nháy * vào trước tên biến cho khai báo đối tượng strong
MyClass *myObject1 = nil; // Strong
id myObject2 = nil; // Weak
// %@ là một đối tượng
// 'miêu tả' ('desciption') là thông lệ để trình bày giá trị của các Đối tượng
NSLog(@"%@ và %@", myObject1, [myObject2 description]); // In ra "(null) và (null)"
// Chuỗi
NSString *worldString = @"World";
NSLog(@"Hello %@!", worldString); // In ra "Hello World!"
// Ký tự literals
NSNumber *theLetterZNumber = @'Z';
char theLetterZ = [theLetterZNumber charValue];
NSLog(@"%c", theLetterZ);
// Số nguyên literals
NSNumber *fortyTwoNumber = @42;
int fortyTwo = [fortyTwoNumber intValue];
NSLog(@"%i", fortyTwo);
NSNumber *fortyTwoUnsignedNumber = @42U;
unsigned int fortyTwoUnsigned = [fortyTwoUnsignedNumber unsignedIntValue];
NSLog(@"%u", fortyTwoUnsigned);
NSNumber *fortyTwoShortNumber = [NSNumber numberWithShort:42];
short fortyTwoShort = [fortyTwoShortNumber shortValue];
NSLog(@"%hi", fortyTwoShort);
NSNumber *fortyTwoLongNumber = @42L;
long fortyTwoLong = [fortyTwoLongNumber longValue];
NSLog(@"%li", fortyTwoLong);
// Dấu phẩy động (floating point) literals
NSNumber *piFloatNumber = @3.141592654F;
float piFloat = [piFloatNumber floatValue];
NSLog(@"%f", piFloat);
NSNumber *piDoubleNumber = @3.1415926535;
double piDouble = [piDoubleNumber doubleValue];
NSLog(@"%f", piDouble);
// BOOL literals
NSNumber *yesNumber = @YES;
NSNumber *noNumber = @NO;
// Đối tượng Mảng
NSArray *anArray = @[@1, @2, @3, @4];
NSNumber *thirdNumber = anArray[2];
NSLog(@"Third number = %@", thirdNumber); // In ra "Third number = 3"
// Đối tượng Từ điển
NSDictionary *aDictionary = @{ @"key1" : @"value1", @"key2" : @"value2" };
NSObject *valueObject = aDictionary[@"A Key"];
NSLog(@"Đối tượng = %@", valueObject); // In ra "Object = (null)"
///////////////////////////////////////
// Toán Tử (Operators)
///////////////////////////////////////
// Các toán tử cũng hoạt động giống như ngôn ngữ C
// Ví dụ:
2 + 5; // => 7
4.2f + 5.1f; // => 9.3f
3 == 2; // => 0 (NO)
3 != 2; // => 1 (YES)
1 && 1; // => 1 (Logical and)
0 || 1; // => 1 (Logical or)
~0x0F; // => 0xF0 (bitwise negation)
0x0F & 0xF0; // => 0x00 (bitwise AND)
0x01 << 1; // => 0x02 (bitwise dịch trái (bởi 1))
/////////////////////////////////////////////
// Cấu Trúc Điều Khiển (Controls Structures)
/////////////////////////////////////////////
// Câu lệnh If-Else
if (NO)
{
NSLog(@"I am never run");
} else if (0)
{
NSLog(@"I am also never run");
} else
{
NSLog(@"I print");
}
// Câu lệnh Switch
switch (2)
{
case 0:
{
NSLog(@"I am never run");
} break;
case 1:
{
NSLog(@"I am also never run");
} break;
default:
{
NSLog(@"I print");
} break;
}
// Câu lệnh vòng lặp While
int ii = 0;
while (ii < 4)
{
NSLog(@"%d,", ii++); // ii++ tăng dần, sau khi sử dụng giá trị của nó.
} // => in ra "0,"
// "1,"
// "2,"
// "3,"
// Câu lệnh vòng lặp For
int jj;
for (jj=0; jj < 4; jj++)
{
NSLog(@"%d,", jj);
} // => in ra "0,"
// "1,"
// "2,"
// "3,"
// Câu lệnh Foreach
NSArray *values = @[@0, @1, @2, @3];
for (NSNumber *value in values)
{
NSLog(@"%@,", value);
} // => in ra "0,"
// "1,"
// "2,"
// "3,"
// Câu lệnh Try-Catch-Finally
@try
{
// Your statements here
@throw [NSException exceptionWithName:@"FileNotFoundException"
reason:@"Không Tìm Thấy Tập Tin trên Hệ Thống" userInfo:nil];
} @catch (NSException * e)
{
NSLog(@"Exception: %@", e);
} @finally
{
NSLog(@"Finally");
} // => in ra "Exception: Không Tìm Thấy Tập Tin trên Hệ Thống"
// "Finally"
///////////////////////////////////////
// Đối Tượng (Objects)
///////////////////////////////////////
// Tạo một thực thể đối tượng bằng cách phân vùng nhớ và khởi tạo đối tượng đó.
// Một đối tượng sẽ không thật sự hoạt động cho đến khi cả 2 bước alloc] init] được hoàn thành
MyClass *myObject = [[MyClass alloc] init];
// Mô hình lập trình hướng đối tượng của Objective-C dựa trên việc truyền thông điệp (message)
// và các thực thể đối tượng với nhau.
// Trong Objective-C một đối tượng không đơn thuần gọi phương thức; nó truyền thông điệp.
[myObject instanceMethodWithParameter:@"Steve Jobs"];
// Dọn dẹp vùng nhớ mà bạn đã dùng ở chương trình
[pool drain];
// Kết thúc chương trình
return 0;
}
///////////////////////////////////////
// Lớp và Hàm (Classes & Functions)
///////////////////////////////////////
// Khai báo lớp của bạn ở một tập tin header (MyClass.h):
// Cú pháp Khai Báo Lớp:
// @interface ClassName : ParentClassName <ImplementedProtocols>
// {
// Khai báo biến thành viên;
// }
// -/+ (type) Khai báo method;
// @end
@interface MyClass : NSObject <MyProtocol>
{
int count;
id data;
NSString *name;
}
// Ký hiệu (notation) tiện ích để tự động khởi tạo public getter và setter
@property int count;
@property (copy) NSString *name; // Sao chép đối tượng trong quá trình gán.
@property (readonly) id data; // Chỉ khai báo phương thức getter.
// Phương thức
+/- (return type)methodSignature:(Parameter Type *)parameterName;
// dấu '+' cho phương thức lớp
+ (NSString *)classMethod;
// dấu '-' cho phương thức thực thể
- (NSString *)instanceMethodWithParameter:(NSString *)string;
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number;
@end
// Thực thi các phương thức trong một tập tin thực thi (MyClass.m):
@implementation MyClass
// Gọi khi đối tượng được release
- (void)dealloc
{
}
// Phương thức khởi tạo (Constructors) là một cách để tạo các lớp
// Đây là phương thức khởi tạo mặc định được gọi khi đối tượng được khởi tạo
- (id)init
{
if ((self = [super init]))
{
self.count = 1;
}
return self;
}
+ (NSString *)classMethod
{
return [[self alloc] init];
}
- (NSString *)instanceMethodWithParameter:(NSString *)string
{
return @"New string";
}
- (NSNumber *)methodAParameterAsString:(NSString*)string andAParameterAsNumber:(NSNumber *)number
{
return @42;
}
// Các phương thức được khai báo vào MyProtocol
- (void)myProtocolMethod
{
// câu lệnh
}
@end
/*
* Một protocol khai báo các phương thức mà có thể thực thi bởi bất kỳ lớp nào.
* Các protocol chính chúng không phải là các lớp. Chúng chỉ đơn giản là định ra giao diện (interface)
* mà các đối tượng khác có trách nhiệm sẽ thực thi.
*/
@protocol MyProtocol
- (void)myProtocolMethod;
@end
```
## Xem Thêm
+ [Wikipedia Objective-C](http://en.wikipedia.org/wiki/Objective-C)
+ Apple Docs':
+ [Learning Objective-C](http://developer.apple.com/library/ios/referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/)
+ [Programming With Objective-C](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html)
+ [Object-Oriented Programming with Objective-C](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/OOP_ObjC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005149)
+ [Coding Guidelines for Cocoa](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html)
+ [iOS For High School Students: Getting Started](http://www.raywenderlich.com/5600/ios-for-high-school-students-getting-started)

909
vi/python.md Normal file
View File

@@ -0,0 +1,909 @@
---
language: Python
filename: learnpython-vi.py
contributors:
- ["Louie Dinh", "http://pythonpracticeprojects.com"]
- ["Steven Basart", "http://github.com/xksteven"]
- ["Andre Polykanine", "https://github.com/Oire"]
- ["Zachary Ferguson", "http://github.com/zfergus2"]
- ["evuez", "http://github.com/evuez"]
translators:
- ["Xuan (Sean) Luong, https://github.com/xuanluong"]
lang: vi-vn
---
Python được tạo ra bởi Guido van Rossum vào đầu những năm 90s. Ngày nay nó là một trong những ngôn ngữ phổ biến
nhất còn tồn tại. Tôi thích Python vì sự rõ ràng, trong sáng về mặt cú pháp. Về cơ bản, Python có thể coi
như một loại mã giả (pseudocode) có thể thực thi được.
Lưu ý: Bài viết này áp dụng riêng cho Python 3. Truy cập [vào đây](http://learnxinyminutes.com/docs/pythonlegacy/) nếu bạn muốn học phiên bản cũ Python 2.7
```python
# Dòng bình luận (comment) bắt đầu bằng dấu thăng (#)
""" Những chuỗi ký tự (string) nằm trên nhiều dòng
có thể được viết bằng cách dùng 3 dấu nháy " và thường
được dùng trong quá trình viết tài liệu (documentation).
"""
####################################################
## 1. Các kiểu dữ liệu cơ bản và Các phép toán
####################################################
# Bạn có những con số
3 # => 3
# Tính toán với những con số là những điều có thể bạn sẽ làm
1 + 1 # => 2
8 - 1 # => 7
10 * 2 # => 20
35 / 5 # => 7.0
# Kết quả của phép chia số nguyên sẽ được làm tròn xuống cho cả số dương và số âm
5 // 3 # => 1
5.0 // 3.0 # => 1.0 # phép chia số nguyên cũng áp dụng được cho kiểu dữ liệu float biểu diễn số thực
-5 // 3 # => -2
-5.0 // 3.0 # => -2.0
# Kết quả của phép chia luôn là số thực
10.0 / 3 # => 3.3333333333333335
# Phép toán lấy phần dư (modulo)
7 % 3 # => 1
# Phép lũy thừa (x**y, x lũy thừa y)
2**3 # => 8
# Áp đặt thứ tự tính toán bằng dấu ngoặc
(1 + 3) * 2 # => 8
# Kiểu Boolean cũng là một kiểu dữ liệu cơ bản (Lưu ý: ký tự đầu tiên viết hoa)
True
False
# Phủ định bằng từ khóa 'not'
not True # => False
not False # => True
# Các phép toán với kiểu Boolean
# Lưu ý từ khóa "and" và "or" là case-sensitive
True and False # => False
False or True # => True
# Lưu ý khi sử dụng các phép toán của kiểu Boolean với số nguyên 'int'
# False là 0 và True là 1
# Đừng nhầm lẫn các phép toán Boolean cho số nguyên và các phép toán and/or trên bit (& và |)
0 and 2 # => 0
-5 or 0 # => -5
0 == False # => True
2 == True # => False
1 == True # => True
-5 != False != True #=> True
# So sánh bằng với ==
1 == 1 # => True
2 == 1 # => False
# So sánh không bằng với !=
1 != 1 # => False
2 != 1 # => True
# Các phép so sánh khác
1 < 10 # => True
1 > 10 # => False
2 <= 2 # => True
2 >= 2 # => True
# Các phép so sánh có thể xâu chuỗi với nhau!
1 < 2 < 3 # => True
2 < 3 < 2 # => False
# (is vs. ==) từ khóa is kiểm tra xem 2 biến có cùng tham chiếu một đối tượng, còn == kiếm tra
# xem hai đối tượng có cùng giá trị hay không.
a = [1, 2, 3, 4] # a trỏ tới một danh sách (list) mới, [1, 2, 3, 4]
b = a # b trỏ tới nơi mà a cũng đang trỏ tới
b is a # => True, a và b cùng trỏ tới một đối tượng
b == a # => True, đối tượng mà a và b trỏ tới có cùng giá trị
b = [1, 2, 3, 4] # b trỏ tới một danh sách mới, [1, 2, 3, 4]
b is a # => False, a và b không cùng trỏ tới một đối tượng
b == a # => True, đối tượng mà a và b trỏ tới không có cùng giá trị
# Chuỗi ký tự được tạo ra bằng dấu nháy kép " hoặc nháy đơn '
"Đây là một chuỗi ký tự."
'Đây cũng là một chuỗi ký tự.'
# Chuỗi ký tự có thể được cộng với nhau can be added too! Tuy nhiên nên tránh làm như vậy
"Xin " + "chào!" # => "Xin chào!"
# Các chuỗi ký tự không phải là biến (literals) có thể được nối với nhau mà không cần dùng phép cộng '+'
"Xin " "chào!" # => "Xin chào!"
# Một chuỗi ký tự có thể xem như một danh sách (list) các ký tự
"Đây là một chuỗi ký tự"[0] # => 'Đ'
# Bạn có thể tìm chiều dài một chuỗi
len("Đây là một chuỗi") # => 16
# .format có thể được dùng để định dạng chuỗi, ví dụ như:
"{} có thể được {}".format("Chuỗi ký tự", "định dạng") # => "Chuỗi ký tự có thể được định dạng"
# Bạn có thể lặp lại đối số (arguments) khi định dạnh để không phải gõ nhiều lần
"{0} be nimble, {0} be quick, {0} jump over the {1}".format("Jack", "candle stick")
# => "Jack be nimble, Jack be quick, Jack jump over the candle stick"
# Bạn có thể dùng từ khóa nếu bạn không muốn đếm
"{name} wants to eat {food}".format(name="Bob", food="lasagna") # => "Bob wants to eat lasagna"
# Nếu code Python 3 của bạn cần phải chạy với Python 2.5 hoặc các bản cũ hơn, bạn cũng có thể
# dùng cách định dạng cũ:
"%s can be %s the %s way" % ("Strings", "interpolated", "old") # => "Strings can be interpolated the old way"
# None là một đối tượng
None # => None
# Đừng dùng so sánh bằng "==" để so sánh đối tượng với None
# Thay vào đó dùng is. Nó sẽ kiểm tra xem một đối tượng có đồng nhất với None hay không.
"etc" is None # => False
None is None # => True
# None, 0, và chuỗi/danh sách (list)/từ điển (dict)/tuple rỗng khi chuyển về kiểu Boolean đều có giá trị là False.
# Tất cả những giá trị khác đều là True
bool(0) # => False
bool("") # => False
bool([]) # => False
bool({}) # => False
bool(()) # => False
####################################################
## 2. Biến và Các kiểu dữ liệu gộp (Collections)
####################################################
# Hàm print trong Python
print("Tôi là Python. Rất hân hạnh được làm quen!") # => Tôi là Python. Rất hân hạnh được làm quen!
# Hàm print mặc định in thêm ký tự xuống dòng
# Dùng đối số tùy chọn (optional argument) để thay đổi cách kết thúc chuỗi.
print("Hello, World", end="!") # => Hello, World!
# Một cách đơn giản để lấy dữ liệu vào từ bàn phím
input_string_var = input("Nhập dữ liệu: ") # Trả về dữ liệu vào là một chuỗi
# Lưu ý: Trong những phiên bản cũ của Python input() có tên là raw_input()
# Không cần phải khai báo biến mà chỉ có gán giá trị cho biến.
# Quy ước là sử dụng chữ_viết_thường_có_dấu_gạch_dưới
some_var = 5
some_var # => 5
# Truy cập một biến chưa được gán trước đó sẽ tạo ra biệt lệ (exception).
# Đọc mục Luồng điều khiển để hiểu thêm về việc giải quyết các biệt lệ (exception handling)
some_unknown_var # Sinh ra một biệt lệ kiểu NameError
# if có thể dùng như một biểu thức
# Tương đương với phép toán ba ngôi trong C: '?:'
"yahoo!" if 3 > 2 else 2 # => "yahoo!"
# Kiểu danh sách (list) lưu trữ chuỗi đối tượng tuần tự
li = []
# Bạn có thể bắt đầu với một danh sách đã có sãn các phần tử
other_li = [4, 5, 6]
# Thêm phần tử vào cuối danh sách bằng phương thức append
li.append(1) # li bây giờ là [1]
li.append(2) # li bây giờ là [1, 2]
li.append(4) # li bây giờ là [1, 2, 4]
li.append(3) # li bây giờ là [1, 2, 4, 3]
# Xóa phần tử cuối cùng bằng phương thức pop
li.pop() # => 3 and li is now [1, 2, 4]
# Sau đó ta có thể đưa đối tượng trở lại danh sách
li.append(3) # li trở lại là [1, 2, 4, 3].
# Truy cập một danh sách như bạn làm với một mảng (array)
li[0] # => 1
# Truy cập phần tử cuối cùng
li[-1] # => 3
# Truy cập ngoài giới hạn sẽ tạo ra biệt lệ IndexError
li[4] # Sinh ra một biệt lệ kiểu IndexError
# Bạn có thể truy cập một đoạn bằng phép cắt (slice).
# Chỉ mục bắt đầu được tính làm điểm bắt đầu còn chỉ mục kết thúc thì không, mà là chỉ mục của phần tử tiếp theo phần tử kết thúc
# (Về mặt toán học thì đây là một đoạn đóng/mở, hay nửa đoạn)
li[1:3] # => [2, 4]
# Lấy từ vị trí thứ 3 đến hết
li[2:] # => [4, 3]
# Lấy từ đầu đến vị trí thứ 3
li[:3] # => [1, 2, 4]
# Lấy những phần tử có chỉ mục chẵn
li[::2] # =>[1, 4]
# Trả về bản sao của danh sách bị đảo ngược
li[::-1] # => [3, 4, 2, 1]
# Kết hợp 3 tham số để làm những phép cắt phức tạp hơn
# li[start:end:step]
# Tạo ra một bản sao sâu (deep copy) bằng phép cắt
li2 = li[:] # => li2 = [1, 2, 4, 3] but (li2 is li) will result in false.
# Xóa phần tử nào đó của danh sách bằng "del"
del li[2] # li is now [1, 2, 3]
# Xóa đi phần tử đầu tiên mang một giá trị nhất định
li.remove(2) # li bây giờ là [1, 3]
li.remove(2) # Sinh ra biệt lệ kiểu ValueError vì 2 không tồn tại trong danh sách
# Chèn một phần tử vào một vị trí cụ thể
li.insert(1, 2) # li bây giờ lại là [1, 2, 3]
# Tìm chỉ mục của của phần tử đầu tiên mang một giá trị nhất định
li.index(2) # => 1
li.index(4) # Sinh ra biệt lệ a ValueError as 4 is not in the list
# Bạn có thể cộng dồn các danh sách
# Lưu ý: giá trị của li và other_li không đổi
li + other_li # => [1, 2, 3, 4, 5, 6]
# Nối danh sách bằng "extend()"
li.extend(other_li) # Now li is [1, 2, 3, 4, 5, 6]
# Kiểm tra sự tồn tại của một phần tử trong danh sách bằng "in"
1 in li # => True
# Xác định độ dài bằng "len()"
len(li) # => 6
# Tuple cũng giống như danh sách nhưng không thể thay đổi giá trị được (immutable)
tup = (1, 2, 3)
tup[0] # => 1
tup[0] = 3 # Sinh ra biệt lệ kiểu TypeError
# Lưu ý rằng tuple có độ dài là 1 phải có dấu phẩy theo sau phần tử cuối
# nhưng tuples có độ dài khác, ngay cả tuple rỗng, thì không cần như vậy
type((1)) # => <class 'int'>
type((1,)) # => <class 'tuple'>
type(()) # => <class 'tuple'>
# Hầu hết các phép toán của danh sách đều áp dụng được cho tuples
len(tup) # => 3
tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6)
tup[:2] # => (1, 2)
2 in tup # => True
# Bạn có thể gán giá trị cho nhiều biến một lúc bằng tuple (tuple unpacking)
a, b, c = (1, 2, 3) # a is now 1, b is now 2 and c is now 3
# Sau đây là unpacking kiểu mở rộng
a, *b, c = (1, 2, 3, 4) # a bây giờ là 1, b là [2, 3] và c là 4
# Tuple được tự động tạo ra nếu bạn không để dấu ngoặc đơn
d, e, f = 4, 5, 6
# Hoán đổi hai biến trở nên dễ dàng
e, d = d, e # d bây giờ là 5 và e là 4
# Kiểu dữ liệu từ điển (dictionaries) lưu trữ ánh xạ từ các khóa (keys) đến các giá trị (values)
empty_dict = {}
# Sau đây là một từ điển có sẵn phần tử
filled_dict = {"one": 1, "two": 2, "three": 3}
# Lưu ý rằng khóa của từ điển phải có kiểu dữ liệu thuộc loại immutable. Điều này để bảo đảm rằng
# khóa đó luôn được chuyển hóa thành một giá trị băm (hash value) duy nhất khi tìm kiếm trong từ điển
# Những kiểu immutable bao gồm số nguyên (int), số thực (float), chuỗi ký tự (string), hay tuple
invalid_dict = {[1,2,3]: "123"} # => Sinh ra biệt lệ kiểu TypeError: unhashable type: 'list'
valid_dict = {(1,2,3):[1,2,3]} # Tuy nhiên, giá trị có thể thuộc bất kỳ kiểu gì
# Truy cập giá trị của một từ khóa bằng dấu []
filled_dict["one"] # => 1
# Tất cả khóa trong một từ điển có thể được chuyển thành một đối tượng khả lặp (iterable).
# Chúng ta cần phải gọi hàm list() để chuyển một iterable thành một danh sách.
# Chúng ta sẽ bàn về vấn đề này sau. Lưu ý - Thứ tự của khóa trong từ điển sẽ không được đảm bảo.
# Những gì bạn thấy khi chạy dòng code dưới đây có thể sẽ không hoàn toàn giống như vậy.
list(filled_dict.keys()) # => ["three", "two", "one"]
# Tất cả các giá trị có thể chuyển thành một đối tượng khả lặp bằng cách gọi hàm "values()".
# Chúng ta cũng vẫn phải gọi hàm list() nếu muốn chuyển nó thành một danh sách. Lưu ý - thứ
# tự của giá trị cũng không được đảm bảo
list(filled_dict.values()) # => [3, 2, 1]
# Sự tồn tại của khóa trong từ điển có thể kiểm tra được thông qua từ khóa "in"
"one" in filled_dict # => True
1 in filled_dict # => False
# Truy xuất giá trị của một khóa không tồn tại trong từ điển sẽ tạo ra biệt lệ KeyError
filled_dict["four"] # KeyError
# Dừng phương thức "get()" để tránh tạo ra biệt lệ KeyError
filled_dict.get("one") # => 1
filled_dict.get("four") # => None
# Phương thức get hỗ trợ một đối số mặt định khi không thể tìm thấy giá trị ứng với từ khóa
filled_dict.get("one", 4) # => 1
filled_dict.get("four", 4) # => 4
# "setdefault()" chèn một giá trị ứng với khóa nếu khóa đó không có sẵn trong từ điển
filled_dict.setdefault("five", 5) # filled_dict["five"] is set to 5
filled_dict.setdefault("five", 6) # filled_dict["five"] is still 5
# Thêm khóa và giá trị vào từ điển
filled_dict.update({"four":4}) # => {"one": 1, "two": 2, "three": 3, "four": 4}
filled_dict["four"] = 4 # another way to add to dict
# Xóa một khóa ra khỏi từ điển bằng từ khóa del
del filled_dict["one"] # Removes the key "one" from filled dict
# Bắt đầu từ Python 3.5 bạn có thể unpack từ điển trong một từ điển khác
{'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2}
{'a': 1, **{'a': 2}} # => {'a': 2}
# Kiểu tập hợp (set) lưu trữ ... tập hợp
empty_set = set()
# Khởi tạo giá trị một tập hợp với nhiều giá tri. Vâng, nhìn nó khá giống từ điển.
some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4}
# Tương tự như khóa của từ điển, phần tử của một tập hợp cũng phải là immutable
invalid_set = {[1], 1} # => Sinh ra biệt lệ TypeError: unhashable type: 'list'
valid_set = {(1,), 1}
# Thêm một phần tử vào tập hợp
filled_set.add(5) # filled_set is now {1, 2, 3, 4, 5}
# Thực hiện phép giao hai tập hợp bằng phép toán &
other_set = {3, 4, 5, 6}
filled_set & other_set # => {3, 4, 5}
# Thực hiện phép hợp bằng phép toán |
filled_set | other_set # => {1, 2, 3, 4, 5, 6}
# Lấy hiệu của hai tập hơp bằng phép toán -
{1, 2, 3, 4} - {2, 3, 5} # => {1, 4}
# Lấy hiệu đối xứng bằng phép toán ^
{1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5}
# Kiểm tra tập hợp bên trái là tập cha của bên phải
{1, 2} >= {1, 2, 3} # => False
# Kiểm tra xem tập hợp bên trái có phải là tập con của tập hợp bên phải
{1, 2} <= {1, 2, 3} # => True
# Kiểm tra sự tồn tại của một phần tử trong tập hợp bằng từ khóa in
2 in filled_set # => True
10 in filled_set # => False
####################################################
## 3. Luồng điều khiển và kiểu khả lặp
####################################################
# Đầu tiên hãy tạo ra một biến
some_var = 5
# Sau đây là một câu lệnh if. Khoảng cách lề rất quan trọng trong Python
# Quy ước chung là dùng khoảng trắng chứ không phải ký tự tab
# Chuỗi sau sẽ được in ra "some_var is smaller than 10"
if some_var > 10:
print("some_var is totally bigger than 10.")
elif some_var < 10: # Phần elif là tùy chọn.
print("some_var is smaller than 10.")
else: # else cũng là tùy chọn.
print("some_var is indeed 10.")
"""
Lặp qua một danh sách bằng for
in ra:
dog is a mammal
cat is a mammal
mouse is a mammal
"""
for animal in ["dog", "cat", "mouse"]:
# Bạn có thể dùng format() để gán một giá trị vào giữa chuỗi (string interpolation)
print("{} is a mammal".format(animal))
"""
"range(number)" trả về một đối tượng khả lặp kiểu số
từ 0 đến giá trị của number
in ra:
0
1
2
3
"""
for i in range(4):
print(i)
"""
"range(lower, upper)" trả về một đối tượng khả lặp kiểu số
từ giá trị lower đến giá trị upper
in ra:
4
5
6
7
"""
for i in range(4, 8):
print(i)
"""
"range(lower, upper, step)" trả về một đối tượng khả lặp kiểu số
từ giá trị lower đến giá trị upper, tăng dần theo giá trị
của step. Nếu không có giá trị của step thì mặc định là 1.
in ra:
4
6
"""
for i in range(4, 8, 2):
print(i)
"""
Vòng lặp while tiếp tục lặp khi điều kiện còn được thỏa mãn
in ra:
0
1
2
3
"""
x = 0
while x < 4:
print(x)
x += 1 # cách viết ngán cho x = x + 1
# Handle exceptions with a try/except block
# Đối phó với biệt lệ bằng khối lệnh try/except
try:
# Dùng "raise" để ném ra một biệt lệ
raise IndexError("This is an index error")
except IndexError as e:
pass # pass có nghĩa là không làm gì cả. Thông thường đây là nơi để khắc phụ vấn đề làm xảy ra biệt lệ
except (TypeError, NameError):
pass # Nhiều biệt lệ có thể được đối phó cùng một lúc nếu cần
else: # Không bắt buộc phải sử dụng else nhưng nếu dùng thì nó phải sau tất cả các khối except
print("All good!") # Chỉ thực thi nếu không có biệt lệ phát sinh
finally: # Luôn thực thi trong mọi hoàn cảnh
print("We can clean up resources here")
# Thay vì dùng try/finally để thu hồi tài nguyên (resources) ta có thể dùng with
with open("myfile.txt") as f:
for line in f:
print(line)
# Python hỗ trợ kiểu dữ liệu khả lặp (iterable).
# Một đối tượng khả lặp có thể được xem như là một chuỗi các đối tượng tuần tự (sequence)
# Đối tượng trả về bởi hàm range là một khả lặp.
filled_dict = {"one": 1, "two": 2, "three": 3}
our_iterable = filled_dict.keys()
print(our_iterable) # => dict_keys(['one', 'two', 'three']). Đây là một đối tượng khả lặp
# Ta có thể lặp qua đối tượng
for i in our_iterable:
print(i) # In ra một, hai, ba
# Tuy nhiên chúng ta không thể truy cập phần tử bằng chỉ mục
our_iterable[1] # Sinh ra biệt lệ TypeError
# Một đối tượng khả lặp là đối tượng có thể tạo ra một iterator
our_iterator = iter(our_iterable)
# iterator là một đối tượng ghi nhớ được trạng thái trong quá trình nó được duyệt qua
# đối tượng kế tiếp có thể truy cập được bằng hàm next
next(our_iterator) # => "one"
# Nó ghi nhớ trạng thái trong quá trình lặp
next(our_iterator) # => "two"
next(our_iterator) # => "three"
# Sau khi iterator đã trả về tất cả dữ liệu, nó sẽ sinh ra biệt lệ kiểu StopIteration
next(our_iterator) # Sinh ra biệt lệ StopIteration
# Ta có thể lấy tất cả phần tử của một iterator bằng cách gọi hàm list với nó
list(filled_dict.keys()) # => Returns ["one", "two", "three"]
####################################################
## 4. Hàm
####################################################
# Dùng từ khóa def để định nghĩa hàm
def add(x, y):
print("x is {} and y is {}".format(x, y))
return x + y # từ khóa return để trả về một giá trị
# Gọi một hàm với đối số
add(5, 6) # => In ra "x is 5 and y is 6" và trả về 11
# Một cách khác để gọi hàm là dùng đối số có từ khóa (keyword arguments)
add(y=6, x=5) # Đối số có từ khóa có thể xuất hiện với thứ tự bất kỳ
# Bạn có thể định nghĩa hàm có số lượng đối số vị trí (positional arguments) không biết trước
def varargs(*args):
return args
varargs(1, 2, 3) # => (1, 2, 3)
# Số lượng tham số từ khóa cũng có thể không cần biết trước
def keyword_args(**kwargs):
return kwargs
# Thử gọi hàm để xem điều gì xảy ra
keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"}
# Có thể định nghĩa hàm dùng cả hai loại đối số
def all_the_args(*args, **kwargs):
print(args)
print(kwargs)
"""
all_the_args(1, 2, a=3, b=4) in ra:
(1, 2)
{"a": 3, "b": 4}
"""
# Khi gọi hàm, bạn có thể làm ngược với khi định nghĩa
# Dùng dấu * để lấy giá trị từ args và ** với giá trị từ kwargs
args = (1, 2, 3, 4)
kwargs = {"a": 3, "b": 4}
all_the_args(*args) # tương đương với foo(1, 2, 3, 4)
all_the_args(**kwargs) # tương đương với foo(a=3, b=4)
all_the_args(*args, **kwargs) # tương đương với foo(1, 2, 3, 4, a=3, b=4)
# Trả về nhiều giá trị (gán vào một tuple)
def swap(x, y):
return y, x # Trả về nhiều giá trị dưới dạng một tuple mà không cần dấu ngoặc.
# (Lưu ý là dấu ngoặc đơn đã được bỏ đi những vẫn có thể được thêm vào)
x = 1
y = 2
x, y = swap(x, y) # => x = 2, y = 1
# (x, y) = swap(x,y) # dấu ngoặc đơn đã được bỏ đi những vẫn có thể được thêm vào
# Tầm vực của hàm
x = 5
def set_x(num):
# Biến cục bộ x không đồng nhất với biến toàn cục x
x = num # => 43
print(x) # => 43
def set_global_x(num):
global x
print(x) # => 5
x = num # biến toàn cục x được gán giá trị là 6
print(x) # => 6
set_x(43)
set_global_x(6)
# Hàm trong Python cũng là đối tượng
def create_adder(x):
def adder(y):
return x + y
return adder
add_10 = create_adder(10)
add_10(3) # => 13
# Có những hàm không tên
(lambda x: x > 2)(3) # => True
(lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5
# Có những hàm cấp cao được hỗ trọ sẵn
list(map(add_10, [1, 2, 3])) # => [11, 12, 13]
list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3]
list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7]
# list comprehension có thể dùng để hay thế map và filter
# list comprehension lưu giá trị xuất vào một danh sách mà bản thân nó có thể lồng trong danh sách khác
[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
# Tập hơp và từ điển cũng có thể được tao ra thông qua set comprehension và dict comprehension
{x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'}
{x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
####################################################
## 5. Mô đun
####################################################
# Bạn có thể import một mô đun
import math
print(math.sqrt(16)) # => 4.0
# Bạn có thể lấy một hàm cụ thể từ một mô đun
from math import ceil, floor
print(ceil(3.7)) # => 4.0
print(floor(3.7)) # => 3.0
# Hoặc import tất cả hàm từ một mô đun
# Cảnh báo: đây không phải là một cách hay
from math import *
# Có thể làm tên của module ngắn lại
import math as m
math.sqrt(16) == m.sqrt(16) # => True
# Mô đun trong Python chỉ là những tập tin Python bình thường. Bạn
# có thể viết mô đun của mình và import chúng. Tên của mô đun
# cũng là tên của tập tin.
# You can find out which functions and attributes
# are defined in a module.
# Bạn có thể liệt kê những hàm và thuộc tính
# được định nghĩa trong một mô đun
import math
dir(math)
# Nếu bạn có một tập tin code Python gọi là math.py ở cùng
# thư mục với tập tin hiện tai, tập tin math.py sẽ
# được nạp vào thay vì mô đun được cung cấp sẵn (built-in) trong Python.
# Điều này xảy ra vì thư mục hiện tại có ưu tiên
# hơn những thư viện cung cấp sẵn.
####################################################
## 6. Lớp (classes)
####################################################
# Ta dùng từ khóa "class" đề định nghĩa một lớp
class Human:
# Một thuộc tính của lớp được chia sẽ bởi tất cả đối tượng của lớp này
species = "H. sapiens"
# Hàm khởi tạo cơ bản sẽ được goi khi một đối tượng được tạo ra.
# Lưu ý 2 dấu gạch dưới ở đầu và cuối ám chỉ đối tượng
# hoặc thuộc tính dùng bở Python những tồn tại trong không gian tên
# do người dùng kiểm soát. Phương thức (hoặc thuộc tính) như: __init__, __str__,
# __repr__ v.v.. là những phương thức đặc biệt.
# Bạn không nên tự đặt những tên như vậy.
def __init__(self, name):
# Gán đối số vào thuộc tính name của đối tượng
self.name = name
# Khởi tạo thuộc tính
self._age = 0
# Một phương thức trên đối tượng. Tất cả đều có đối số đầu tiên là "self"
def say(self, msg):
print ("{name}: {message}".format(name=self.name, message=msg))
# Một phương thức trên đối tượng khác
def sing(self):
return 'yo... yo... microphone check... one two... one two...'
# Một phương thức trên lớp được chia sẻ với mọi đối tượng
# Lớp đó cũng là đối số thứ nhất của phương thức đó
@classmethod
def get_species(cls):
return cls.species
# Một phương thức tĩnh được gọi mà không có lớp hay đối tượng đi kèm
@staticmethod
def grunt():
return "*grunt*"
# Một thuộc tính chỉ giống như một hàm truy xuất.
# Nó biến phương thức age() thành một thuộc tính chỉ đọc cùng tên.
# Tuy nhiên trong Python không nhất thiết phải viết những hàm đọc và ghi quá đơn giản
@property
def age(self):
return self._age
# Đây là hàm để ghi giá trị cho thuộc tính
@age.setter
def age(self, age):
self._age = age
# Đây là hàm để xóa thuộc tính
@age.deleter
def age(self):
del self._age
# Khi trình thông dịch Python đọc một tập tin mã nguồn, nó thực thi tất cả code trong đó.
# Kiểm tra giá trị của __name__ bảo đảm rằng đoạn mã bên dưới chỉ thực thi khi
# mô đun này là chương trình chính
if __name__ == '__main__':
# Khởi tạo một đối tượng
i = Human(name="Ian")
i.say("hi") # "Ian: hi"
j = Human("Joel")
j.say("hello") # "Joel: hello"
# i và j là thực thể của kiểu Human, nói cách khác: chúng là những đối tượng Human
# Gọi những phương thức trên lớp
i.say(i.get_species()) # "Ian: H. sapiens"
# Thay đổi thuộc tính chung
Human.species = "H. neanderthalensis"
i.say(i.get_species()) # => "Ian: H. neanderthalensis"
j.say(j.get_species()) # => "Joel: H. neanderthalensis"
# Gọi phương thức tĩnh
print(Human.grunt()) # => "*grunt*"
# Không thể gọi phương thức tĩnh với một thực thể/đối tượng
# bởi vì i.grunt() sẽ tự động đặt "self" (tức là đối tượng i) làm đối số thứ nhất
print(i.grunt()) # => TypeError: grunt() takes 0 positional arguments but 1 was given
# Thay đổi thuộc tính của đối tượng
i.age = 42
# Truy cập thuộc tính
i.say(i.age) # => "Ian: 42"
j.say(j.age) # => "Joel: 0"
# Xóa thuộc tính
del i.age
# i.age # => dòng nãy sẽ tạo ra biệt lệ AttributeError
####################################################
## 6.1 Đa thừa kế
####################################################
# Một định nghĩa lớp khác
class Bat:
species = 'Baty'
def __init__(self, can_fly=True):
self.fly = can_fly
# Lớp này có phương thức say
def say(self, msg):
msg = '... ... ...'
return msg
# Và một phương thức khác
def sonar(self):
return '))) ... ((('
if __name__ == '__main__':
b = Bat()
print(b.say('hello'))
print(b.fly)
# Để tận dụng việc mô đun hóa thành từng tập tin, bạn có thể đặt những lớp định nghĩa ở trên vào các tập tin riêng,
# ví dụ như human.py và bat.py
# Để import hàm từ tập tin khác dừng cấu trúc sau
# from "filename-without-extension" import "function-or-class"
# superhero.py
from human import Human
from bat import Bat
# Batman thừa kế từ lớp Human và Bat
class Batman(Human, Bat):
# Batman có giá trị riêng cho thuộc tính trên lớp species
species = 'Superhero'
def __init__(self, *args, **kwargs):
# Cách điển hình để thừa kế thuộc tính là gọi super
# super(Batman, self).__init__(*args, **kwargs)
# Tuy nhiên với đa thừa kế, super() sẽ chỉ gọi lớp cơ sở tiếp theo trong danh sách MRO.
# Vì thế, ta sẽ gọi cụ thể hàm __init__ của các lớp chả.
# Sử dụng *args và **kwargs cho phép việc truyền đối số gọn gàng hơn,
# trong đó mỗi lớp cha sẽ chịu trách nhiệm cho những phần thuộc về nó
Human.__init__(self, 'anonymous', *args, **kwargs)
Bat.__init__(self, *args, can_fly=False, **kwargs)
# ghi đè giá trị của thuộc tính name
self.name = 'Sad Affleck'
def sing(self):
return 'nan nan nan nan nan batman!'
if __name__ == '__main__':
sup = Batman()
# Kiểm tra kiểu đối tượng
if isinstance(sup, Human):
print('I am human')
if isinstance(sup, Bat):
print('I am bat')
if type(sup) is Batman:
print('I am Batman')
# Truy xuất thứ tự phương thức của các lớp cha (Method Resolution search Order), vốn được dùng bởi cả getattr() và super9)
# Thuộc tính này động và có thể được cập nhật
print(Batman.__mro__) # => (<class '__main__.Batman'>, <class 'human.Human'>, <class 'bat.Bat'>, <class 'object'>)
# Gọi phương thức của lớp cha nhưng dùng thuộc tính trên chính lớp hiện tại
print(sup.get_species()) # => Superhero
# Gọi phương thức được nạp chồng
print(sup.sing()) # => nan nan nan nan nan batman!
# Gọi phương thức của Human, bởi vì thứ tự thừa kế ảnh hưởng đến phương thức được gọi
sup.say('I agree') # => Sad Affleck: I agree
# Gọi phương thức chỉ tồn tại ở lớp cha thứ 2
print(sup.sonar()) # => ))) ... (((
# Thuộc tính cấp lớp được thừa kế
sup.age = 100
print(sup.age)
# Thuộc tính thừa kế từ lớp cha thứ 2 có giá trị mặc định đã bị ghi đè
print('Can I fly? ' + str(sup.fly))
####################################################
## 7. Phần nâng cao
####################################################
# Generator giúp ta viết những đoạn code lười biếng (áp dụng nguyên tắc lazy evaluation)
def double_numbers(iterable):
for i in iterable:
yield i + i
# Generators tiết kiệm bộ nhớ vì nó chỉ tải dữ liệu khi cần
# xử lý giá trị kế tiếp của một đối tượng khả lặp. Điều này cho phép generator thực hiện
# những thao tác mà bình thường không làm được trên những khoảng giá trị lớn
# Lưu ý: `range` thay thế `xrange` trong Python3.
for i in double_numbers(range(1, 900000000)): # `range` là một generator.
print(i)
if i >= 30:
break
# Cũng như danh sách có list comprehension, generator cũng có generator
# comprehension
values = (-x for x in [1,2,3,4,5])
for x in values:
print(x) # in -1 -2 -3 -4 -5 ra màn hình dòng lệnh
# Một generator cũng có thể bị ép kiểu thành danh sách
values = (-x for x in [1,2,3,4,5])
gen_to_list = list(values)
print(gen_to_list) # => [-1, -2, -3, -4, -5]
# Decorators
# Trong ví dụ này hàm `beg` 'phủ lên' hàm `say`. Nếu say_please là True thì nó
# sẽ thay đội giá trị trả về
from functools import wraps
def beg(target_function):
@wraps(target_function)
def wrapper(*args, **kwargs):
msg, say_please = target_function(*args, **kwargs)
if say_please:
return "{} {}".format(msg, "Làm ơn! Tui rất nghèo :(")
return msg
return wrapper
@beg
def say(say_please=False):
msg = "Mua bia cho tui nhé?"
return msg, say_please
print(say()) # Mua bia cho tui nhé?
print(say(say_please=True)) # Mua bia cho tui nhé? Làm ơn! Tui rất nghèo :(
```
## Sẵn sàng để học nhiều hơn?
### Miễn phí trên mạng
* [Automate the Boring Stuff with Python](https://automatetheboringstuff.com)
* [Ideas for Python Projects](http://pythonpracticeprojects.com)
* [The Official Docs](http://docs.python.org/3/)
* [Hitchhiker's Guide to Python](http://docs.python-guide.org/)
* [Python Course](http://www.python-course.eu/index.php)
* [First Steps With Python](https://realpython.com/learn/python-first-steps/)
* [A curated list of awesome Python frameworks, libraries and software](https://github.com/vinta/awesome-python)
* [Official Style Guide for Python](https://peps.python.org/pep-0008/)
* [Python 3 Computer Science Circles](http://cscircles.cemc.uwaterloo.ca/)
* [Dive Into Python 3](http://www.diveintopython3.net/index.html)

148
vi/ruby-ecosystem.md Normal file
View File

@@ -0,0 +1,148 @@
---
category: tool
tool: Ruby ecosystem
contributors:
- ["Jon Smock", "http://github.com/jonsmock"]
- ["Rafal Chmiel", "http://github.com/rafalchmiel"]
- ["Vinh Nguyen", "http://rubydaily.net"]
lang: vi-vn
---
Nhìn chung các lập trình viên Ruby luôn có cách để cài đặt các phiên bản
Ruby khác nhau, quản lý các gói (hoặc gems), và quản lý các thư viện.
## Trình quản lý Ruby
Một vài nền tảng phải có Ruby đã được cài đặt trước hoặc có sẵn như một gói.
Số đông lập trình viên Ruby không sử dụng cái này, hoặc nếu có, họ chỉ sử
dụng chúng để bootstrap cài đặt Ruby. Thay vào đó, các lập trình viên Ruby
có xu hướng cài đặt trình quản lý Ruby để cài đặt và chuyển đổi các phiên
bản của Ruby và môi trường Ruby cho dự án của họ.
Dưới đây là các trình quản lý môi trường Ruby nổi tiếng:
* [RVM](https://rvm.io/) - Cài đặt và chuyển đổi các phiên bản Ruby. RVM cũng
có các khái niệm về tập các gems để quản lý môi trường dự án một
cách tốt nhất.
* [ruby-build](https://github.com/sstephenson/ruby-build) - Chỉ cài đặt các
phiên bản Ruby. Sử dụng cái này giúp cho việc cài đặt Ruby tốt hơn.
* [rbenv](https://github.com/sstephenson/rbenv) - Chỉ dùng để chuyển đổi các
phiên bản Ruby. Được sử dụng đi kèm với ruby-build. Tiện ích này sẽ giúp
cho việc dùng Ruby tốt hơn.
* [chruby](https://github.com/postmodern/chruby) - Chỉ dùng để chuyển đổi các
phiên bản Ruby. Tương tự như rbenv. Không quan tâm làm thế nào Ruby được
cài đặt.
## Các phiên bản Ruby
Ruby được tạo ra bởi Yukihiro "Matz" Matsumoto, người được xem như là một
[BDFL](https://en.wikipedia.org/wiki/Benevolent_Dictator_for_Life), mặc dầu gần
đây luôn thay đổi. Kết quả là, tham chiếu của Ruby được gọi là MRI(Matz'
Reference Implementation), và khi bạn biết về một phiên bản Ruby, nó đang
được tham chiếu để phát hành một phiên bản của MRI.
Có ba phiên bản Ruby chính thức được dùng là:
* 2.0.0 - Được phát hành vào tháng 2 năm 2013. Hầu hết các thư viện lớn, và
nền tảng đều hỗ trợ 2.0.0.
* 1.9.3 - Được phát hành vào tháng 10 năm 2011. Đây là phiên bản hầu hết các
lập trình viên Ruby đang dùng. [Nhưng đã không còn hỗ trợ](
https://www.ruby-lang.org/en/news/2015/02/23/support-for-ruby-1-9-3-has-ended
/)
* 1.8.7 - [Ruby 1.8.7 đã không còn được sử dụng](
http://www.ruby-lang.org/en/news/2013/06/30/we-retire-1-8-7/).
Sự thay đổi giữa phiên bản 1.8.7 đến 1.9.x lớn hơn nhiều so với thay đổi từ
1.9.3 đến 2.0.0. Ví dụ, các phiên bản 1.9 giới thiệu các bảng mã và một
byecote VM. Có các dự án vẫn đang ở 1.8.7, nhưng chúng chiếm một số lượng ít
, phần lớn cộng đồng đã chuyển sang ít nhất là 1.9.2 hoặc 1.9.3
## Các ứng dụng Ruby
Hệ sinh thái Ruby có rất nhiều ứng dụng, với mỗi thế mạnh độc đáo và khả
năng tương thích. Để rõ ràng hơn, sự khác nhau giữa các ứng dụng được viết
bằng các ngôn ngữ khác nhau, nhưng *chúng vẫn là Ruby*.
Mỗi ứng dụng có các hook đặc trưng và những tính năng đặc biệt, nhưng tất cả
đều chạy Ruby rất tốt. Ví dụ, JRuby được viết bằng Java, nhưng bạn không
cần biết Java để sử dụng.
Một số ứng dụng nổi tiếng/tương thích cao:
* [MRI](https://github.com/ruby/ruby) - Được viết bằng C, đây là ứng dụng
tham chiếu của Ruby. Nó tương thích 100%. Tất cả các phiên bản Ruby có khả
năng duy trì với MRI(xem [Ruby Spec](#ruby-spec) bên dưới).
* [JRuby](http://jruby.org/) - Được viết bằng Java và Ruby, ứng dụng này khá
nhanh. Điểm mạnh quan trọng nhất của JRuby là JVM/Java interop, tận dụng
các công cụ, dự án và ngôn ngữ hiện có của JVM.
* [Rubinius](http://rubini.us/) - Được viết bằng ngôn ngữ chính là Ruby với
một C++ bytecode VM. Rất nhanh. Bởi vì nó được phát triển bằng chính Ruby.
Một số ứng dụng khá nổi tiếng/tương thích:
* [Maglev](http://maglev.github.io/) - Đứng đầu Gemstone, một Smalltalk VM.
SmallTalk có một vài tiện ích hấp dẫn, và trong dự án này đã mang nó vào
môi trường Ruby.
* [RubyMotion](http://www.rubymotion.com/) - Mang Ruby đến việc phát triển iOS.
Một số ứng dụng tốt/tương thích:
* [Topaz](http://topazruby.com/) - Được biết bằng RPython (sử dụng Pypy),
Topaz vẫn còn rất trẻ và chưa hoàn toàn tương thích. Nó hứa hẹn khả năng
trở thành một ứng dụng Ruby tương thích cao.
* [IronRuby](http://ironruby.net/) - Được viết bằng C# hướng đến nền tảng .NET
, IronRuby dường như đã dừng hoạt động kể từ khi Microsoft rút hỗ trợ.
Các ứng dụng Ruby có các phiên bản riêng của mình, nhưng chúng luôn luôn
hướng đến sự một phiên bản đặc biệt của MRI cho sự tương thích. Nhiều ứng
dụng có khả năng đến các chế độ khác nhau (ví dụ, 1.8 hoặc 1.9) để hướng đến
phiên bản MRI.
## Ruby Spec
Hầu hết các ứng dụng Ruby dựa vào [Ruby Spec](https://github.com/ruby/spec). Ruby không
có thông báo chính thức, nhưng cộng đồng đã viết những specs thực thi trong
Ruby để kiểm tra sự tương thích với MRI.
## RubyGems
[RubyGems](http://rubygems.org/) là một cộng đồng quản lý các gói cho Ruby.
RubyGems đi kèm với Ruby, bởi vậy không cần cài đặt riêng lẻ.
Các gói Ruby được gọi là "gems", và chúng được host bởi cộng đồng tại
RubyGems.org. Một gem chứa mã nguồn của nó và một vài mô tả, bao gồm những
thứ như phiên bản, các thư viện độc lập, các tác giả và các loại giấy phép.
## Bundler
[Bundler](http://bundler.io/) là một gem giải quyết độc lập. Nó sử dụng một
Gemfile để tìm kiếm các thư viện độc lập trong dự án, và sau đó sẽ lấy về
các thư viện của các thư viện độc lập này. Nó thực hiện cho đến khi việc
tải các thư viện hoàn tất, hoặc nó sẽ dừng nếu xuất hiện bất kỳ xung đột nào.
Bundler sẽ hiển thị lỗi nếu tìm thấy bất kỳ xung đột giữa các thư viện. Ví
dụ, nếu như gem A yêu cầu gem Z có phiên bản 3 hoặc cao hơn, nhưng gem B lại
yêu cầu gem Z phiên bản 2. Bundler sẽ thông báo cho bạn sự xung đột này.
Điều này đã rất hữu ích khi nhiều gem tham chiếu các các gem khác (trong
gem này lại tham chiếu đến các gem khác nữa), có thể hình thành một đồ thị
lớn để nói.
# Kiểm thử
Kiểm thử là một phần lớn của Ruby. Ruby mang đến một nền tảng kiểm thử theo
kiểu Unit được gọi là minitest (hoặc TestUnit for phiên bản Ruby 1.8.x).
Có nhiều thư viện kiểm thử với các mục đích khác nhau.
* [TestUnit](http://ruby-doc.org/stdlib-1.8.7/libdoc/test/unit/rdoc/Test/
Unit.html) - Nền tảng kiểm thử theo kiểu Unit của Ruby 1.8.
* [minitest](http://ruby-doc.org/stdlib-2.0.0/libdoc/minitest
/rdoc/MiniTest.html) -Nền tảng kiểm thử được xây dựng cho Ruby 1.9/2.0
* [RSpec](http://rspec.info/) - Một nền tảng kiểm thử tập trung vào sự
hoạt động.
* [Cucumber](http://cukes.info/) - Một nền tảng kiểm thử theo kiểu BDD dưới
định dạng Gherkin.
## Be Nice
Cộng đồng Ruby tự hào là một cộng đồng mở, đa dạng và chào đón tất cả mọi
người. Bản thân Matz là một người cực kỳ thân thiện, và các lập trình viên
Ruby rất tuyệt vời.

548
vi/ruby.md Normal file
View File

@@ -0,0 +1,548 @@
---
language: Ruby
filename: learnruby-vi.rb
contributors:
- ["David Underwood", "http://theflyingdeveloper.com"]
- ["Joel Walden", "http://joelwalden.net"]
- ["Luke Holder", "http://twitter.com/lukeholder"]
- ["Tristan Hume", "http://thume.ca/"]
- ["Nick LaMuro", "https://github.com/NickLaMuro"]
- ["Marcos Brizeno", "http://www.about.me/marcosbrizeno"]
- ["Ariel Krakowski", "http://www.learneroo.com"]
- ["Dzianis Dashkevich", "https://github.com/dskecse"]
- ["Levi Bostian", "https://github.com/levibostian"]
- ["Rahil Momin", "https://github.com/iamrahil"]
- ["Vinh Nguyen", "http://rubydaily.net"]
lang: vi-vn
---
```ruby
# Đây là một comment
=begin
Đây là một comment nhiều dòng
Không ai dùng cách này
Bạn không nên dùng
=end
# Đầu tiên và quan trọng nhất: Mọi thứ là đối tượng.
# Các con số là các đối tượng.
3.class #=> Fixnum
3.to_s #=> "3"
# Một vài bài toán số học căn bản
1 + 1 #=> 2
8 - 1 #=> 7
10 * 2 #=> 20
35 / 5 #=> 7
2**5 #=> 32
# Số học vừa là các cú pháp thân thiện cho việc gọi
# một hàm trên một đối tượng
1.+(3) #=> 4
10.* 5 #=> 50
# Các giá trị đặc biệt là các đối tượng
nil # Ở đây không có gì để xem
true # luôn đúng
false # luôn sai
nil.class #=> Lớp Nil
true.class #=> Lớp True
false.class #=> Lớp False
# So sánh bằng
1 == 1 #=> true
2 == 1 #=> false
# So sánh không bằng
1 != 1 #=> false
2 != 1 #=> true
# Ngoài chính false, thì nil là một giá trị khác của false
!nil #=> true
!false #=> true
!0 #=> false
# Các loại so sánh khác
1 < 10 #=> true
1 > 10 #=> false
2 <= 2 #=> true
2 >= 2 #=> true
# Các toán tử logic
true && false #=> false
true || false #=> true
!true #=> false
# Có các cách khác của các toán tử logic với mức thấp hơn
# Chúng được sử dụng như các cấu trúc điều khiển luồng nối các mệnh đề
# với nhau cho đến khi một trong số chúng trả về đúng hoặc sai.
# `do_something_else` chỉ được gọi nếu như hàm `do_something` thành công.
do_something() and do_something_else()
# `log_error` chỉ được gọi nếu hàm `do_something` không thành công.
do_something() or log_error()
# Các chuỗi là các đối tượng
'I am a string'.class #=> String
"I am a string too".class #=> String
placeholder = 'use string interpolation'
"I can #{placeholder} when using double quoted strings"
#=> "I can use string interpolation when using double quoted strings"
# Nên đưa các chuỗi vào trong dấu nháy đơn
# Ngoài ra dấu nháy kép được sử dụng trong tính toán.
# Nối các chuỗi, nhưng không nối với các số.
'hello ' + 'world' #=> "hello world"
'hello ' + 3 #=> TypeError: can't convert Fixnum into String
'hello ' + 3.to_s #=> "hello 3"
# Xuất ra ngoài màn hình
puts "I'm printing!"
# Các biến
x = 25 #=> 25
x #=> 25
# Chú ý về việc gán các giá trị được trả về vào biến.
# Điều này có nghĩa là bạn có thể gán nhiều biến.
x = y = 10 #=> 10
x #=> 10
y #=> 10
# Theo quy ước, dùng snake_case cho các tên của biến.
snake_case = true
# Dùng để mô tả tên các biến
path_to_project_root = '/good/name/'
path = '/bad/name/'
# Ký tự (là các đối tượng)
# Các ký tự là bất biến, như các biến hằng số chỉ đến các số nguyên.
# Chúng thường xuyên được sử dụng thay cho các chuỗi để chuyển đổi các giá
# trị hiệu quả.
:pending.class #=> Symbol
status = :pending
status == :pending #=> true
status == 'pending' #=> false
status == :approved #=> false
# Các mảng
# Đây là một mảng
array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
# Các mảng có thể chứa nhiều phần tử khác nhau
[1, 'hello', false] #=> [1, "hello", false]
# Có thể truy cập các giá trị của mảng thông qua các chỉ mục
array[0] #=> 1
array[12] #=> nil
# Giống như số học, sử dụng [biến] là một cú pháp thông dụng
array.[] 0 #=> 1
array.[] 12 #=> nil
# Lấy phần tử cuối cùng
array[-1] #=> 5
# Bắt đầu từ chỉ mục và số phần tử cần lấy
array[2, 3] #=> [3, 4, 5]
# Đảo ngược một mảng
a=[1,2,3]
a.reverse! #=> [3,2,1]
# Lấy một khoảng
array[1..3] #=> [2, 3, 4]
# Thêm phần tử vào mảng bằng cách này
array << 6 #=> [1, 2, 3, 4, 5, 6]
# Hoặc cách này
array.push(6) #=> [1, 2, 3, 4, 5, 6]
# Kiểm tra phần tử có tồn tại trong mảng
array.include?(1) #=> true
# Băm là phần chính của Ruby với các cặp khoá/giá trị
# Băm được biểu thị bằng dấu ngoặc nhọn:
hash = { 'color' => 'green', 'number' => 5 }
hash.keys #=> ['color', 'number']
# Băm có thể được truy cập nhanh chóng thông qua khoá
hash['color'] #=> 'green'
hash['number'] #=> 5
# Khoá không tồn tại sẽ trả về nil
hash['nothing here'] #=> nil
# Kể từ Ruby bản 1.9, đây là một cú pháp đặc biệt, sử dụng symbol như khoá
new_hash = { defcon: 3, action: true }
new_hash.keys #=> [:defcon, :action]
# Kiểm tra khoá hoặc giá trị có tồn tại hay không
new_hash.has_key?(:defcon) #=> true
new_hash.has_value?(3) #=> true
# Mẹo: Cả Mảng và Băm đều là Enumberable
# Chúng cùng chia sẻ rất nhiều phương thức hữu ích như each, map, count...
# Cấu trúc điều khiển
if true
'if statement'
elsif false
'else if, optional'
else
'else, also optional'
end
for counter in 1..5
puts "iteration #{counter}"
end
#=> iteration 1
#=> iteration 2
#=> iteration 3
#=> iteration 4
#=> iteration 5
# TUY NHIÊN, không ai sử dụng vòng lặp for.
# Thay vào đó, ban nên dùng phương thức "each" và truyền vào đó một khối.
# Một khối là một loạt các mã mà bạn có thể truyền
# cho một phương thức giống như each.
# Nó tương tự với lambda, các hàm ẩn danh hoặc closures trong các ngôn ngữ
# lập trình khác.
#
# Phương thức "each" cho một khoản sẽ chạy qua từng phần tử của khoảng đó.
# Khối được truyền vào là một số đếm như là tham số.
# Gọi một method "each" với một khối sẽ trông như thế này:
(1..5).each do |counter|
puts "iteration #{counter}"
end
#=> iteration 1
#=> iteration 2
#=> iteration 3
#=> iteration 4
#=> iteration 5
# Bạn cũng có thể bao khối trong các dấu ngoặc nhọn.
(1..5).each { |counter| puts "iteration #{counter}" }
# Các nội dung của cấu trúc dữ liệu cũng có thể được lặp bằng each.
array.each do |element|
puts "#{element} is part of the array"
end
hash.each do |key, value|
puts "#{key} is #{value}"
end
counter = 1
while counter <= 5 do
puts "iteration #{counter}"
counter += 1
end
#=> iteration 1
#=> iteration 2
#=> iteration 3
#=> iteration 4
#=> iteration 5
grade = 'B'
case grade
when 'A'
puts 'Way to go kiddo'
when 'B'
puts 'Better luck next time'
when 'C'
puts 'You can do better'
when 'D'
puts 'Scraping through'
when 'F'
puts 'You failed!'
else
puts 'Alternative grading system, eh?'
end
#=> "Better luck next time"
# Cases cũng được dùng cho các dãy
grade = 82
case grade
when 90..100
puts 'Hooray!'
when 80...90
puts 'OK job'
else
puts 'You failed!'
end
#=> "OK job"
# Xử lý ngoại lệ:
begin
# Code ở đây có thể sẽ đưa ra một ngoại lệ.
raise NoMemoryError, 'You ran out of memory.'
rescue NoMemoryError => exception_variable
puts 'NoMemoryError was raised', exception_variable
rescue RuntimeError => other_exception_variable
puts 'RuntimeError was raised now'
else
puts 'This runs if no exceptions were thrown at all'
ensure
puts 'This code always runs no matter what'
end
# Hàm
def double(x)
x * 2
end
# Hàm (và tất cả các khối) được mặc định giá trị trả về ở mệnh đề cuối.
double(2) #=> 4
# Dấu ngoặc là một tuỳ chọn cho một kết quả rõ ràng.
double 3 #=> 6
double double 3 #=> 12
def sum(x, y)
x + y
end
# Các đối số được chia cắt bởi dấu phẩy.
sum 3, 4 #=> 7
sum sum(3, 4), 5 #=> 12
# yield
# Tất cả các hàm có thể có một tham số tuỳ chọn.
# Nó có thể được gọi với từ khóa "yield".
def surround
puts '{'
yield
puts '}'
end
surround { puts 'hello world' }
# {
# hello world
# }
# Bạn có thể truyền một khối đến một hàm
# Dấu "&" được đánh dấu đến một khối
def guests(&block)
block.call 'some_argument'
end
# Bạn có thể truyền một danh sách các tham số, nó sẽ được chuyển thành mảng.
# Thông qua việc sử dụng dấu *.
def guests(*array)
array.each { |guest| puts guest }
end
# Định nghĩ một lớp thông qua từ khoá class.
class Human
# Một biến class. Nó được chia sẽ cho tất cả các instance của lớp này.
@@species = 'H. sapiens'
# Các khởi tạo căn bản
def initialize(name, age = 0)
# Gán đối số đến biến instance "name"
@name = name
# Nếu không có age, sẽ lấy giá trị mặc định trong danh sách đối số.
@age = age
end
# Hàm nhập giá trị căn bản
def name=(name)
@name = name
end
# Hàm lấy giá trị căn bản
def name
@name
end
# Các hàm trên có thể được gọn lại bằng cách dùng hàm attr_accessor
attr_accessor :name
# Các hàm nhận/lấy cũng có thể được tạo riêng như sau:
attr_reader :name
attr_writer :name
# Một hàm lớp dùng self để phân biệt với hàm instance.
# Nó chỉ có thể được gọi trên lớp.
def self.say(msg)
puts msg
end
def species
@@species
end
end
# Khởi tạo một lớp
jim = Human.new('Jim Halpert')
dwight = Human.new('Dwight K. Schrute')
# Hãy gọi một cặp các hàm.
jim.species #=> "H. sapiens"
jim.name #=> "Jim Halpert"
jim.name = "Jim Halpert II" #=> "Jim Halpert II"
jim.name #=> "Jim Halpert II"
dwight.species #=> "H. sapiens"
dwight.name #=> "Dwight K. Schrute"
# Gọi một hàm lớp
Human.say('Hi') #=> "Hi"
# Phạm vi của biến được định nghĩa bởi cách chúng ta đặt tên cho chúng.
# Các biến bắt đầu với dấu $ là biến toàn cục.
$var = "I'm a global var"
defined? $var #=> "global-variable"
# Các biến bắt đầu với dấu @ là biến phạm vi.
@var = "I'm an instance var"
defined? @var #=> "instance-variable"
# Các biến bắt đầu với dấu @@ có pham vi là trong một lớp.
@@var = "I'm a class var"
defined? @@var #=> "class variable"
# Các biến bắt đầu với ký tự viết hoa là biến hằng.
Var = "I'm a constant"
defined? Var #=> "constant"
# Lớp cũng là một đối tượng trong Ruby. Bởi vậy lớp có các biến instance.
# Biến lớp được chia sẽ trong lớp và các lớp kế thừa nó.
# Lớp cơ sở
class Human
@@foo = 0
def self.foo
@@foo
end
def self.foo=(value)
@@foo = value
end
end
# Lớp kế thừa
class Worker < Human
end
Human.foo # 0
Worker.foo # 0
Human.foo = 2 # 2
Worker.foo # 2
# Các biến lớp instance không được chia sẽ trong lớp kế thừa.
class Human
@bar = 0
def self.bar
@bar
end
def self.bar=(value)
@bar = value
end
end
class Doctor < Human
end
Human.bar # 0
Doctor.bar # nil
module ModuleExample
def foo
'foo'
end
end
# Include một module sẽ đưa các hàm của module thành instances của lớp.
# Extend một module sẽ đưa các hàm của module thành các biến của lớp.
class Person
include ModuleExample
end
class Book
extend ModuleExample
end
Person.foo # => NoMethodError: undefined method `foo' for Person:Class
Person.new.foo # => 'foo'
Book.foo # => 'foo'
Book.new.foo # => NoMethodError: undefined method `foo'
# Hàm hồi quy được thực hiện khi include và extend một module.
module ConcernExample
def self.included(base)
base.extend(ClassMethods)
base.send(:include, InstanceMethods)
end
module ClassMethods
def bar
'bar'
end
end
module InstanceMethods
def qux
'qux'
end
end
end
class Something
include ConcernExample
end
Something.bar # => 'bar'
Something.qux # => NoMethodError: undefined method `qux'
Something.new.bar # => NoMethodError: undefined method `bar'
Something.new.qux # => 'qux'
```
## Các nguồn tham khảo thêm.
- [Official Documentation](http://www.ruby-doc.org/core-2.1.1/)
- [Ruby from other languages](https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/)
- [Programming Ruby](http://www.amazon.com/Programming-Ruby-1-9-2-0-Programmers/dp/1937785491/) - An older [free edition](http://ruby-doc.com/docs/ProgrammingRuby/) is available online.
- [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide)

587
vi/sass.md Normal file
View File

@@ -0,0 +1,587 @@
---
language: Sass
filename: learnsass-vi.scss
contributors:
- ["Laura Kyle", "https://github.com/LauraNK"]
- ["Sean Corrales", "https://github.com/droidenator"]
- ["Kyle Mendes", "https://github.com/pink401k"]
- ["Keith Miyake", "https://github.com/kaymmm"]
translators:
- ["Thanh Duy Phan", "https://github.com/thanhpd"]
lang: vi-vn
---
Less là một ngôn ngữ mở rộng CSS/ CSS pre-processor, thêm các tính năng như biến (variable), lồng (nesting), mixin và nhiều thứ khác. Sass cùng với các CSS pre-processor khác như [Less](http://lesscss.org/) giúp lập trình viên viết được các đoạn CSS bảo trì được và không bị lặp lại (DRY - Don't Repeat Yourself).
Sass có hai lựa chọn sử dụng cú pháp khác nhau. Một là SCSS, sử dụng cú pháp giống như CSS nhưng bổ sung thêm các tính năng của Sass. Hai là Sass (cú pháp nguyên bản), sử dụng thụt đầu dòng - indention thay vì ngoặc nhọn và dấu chấm phẩy.
Bài hướng dẫn này sử dụng SCSS.
Nếu bạn đọc đã quen thuộc với CSS3 thì sẽ tương đối nhanh chóng để nắm được Sass. Nó không cung cấp thuộc tính để style CSS mới nhưng đưa ra những công cụ để có thể viết CSS hiệu quả hơn và có thể bảo trì dễ dàng hơn.
```sass
// Comment (chú thích) một dòng sẽ bị xóa khi Less được biên dịch thành CSS
/* Comment trên nhiều dòng sẽ được giữ lại */
/* Variable - Biến
============================== */
/* Ta thể lưu giá trị CSS ( dụ như color) vào một biến.
Sử dụng hiệu '$' để khai báo một biến. */
$primary-color: #A3A4FF;
$secondary-color: #51527F;
$body-font: 'Roboto', sans-serif;
/* Sau khi khai báo biến, ta thể sử dụng trong tệp stylesheet.
Nhờ sử dụng biến ta chỉ cần thay đổi một lần
tại 1 nơi để thay đổi tất cả những đoạn sử dụng biến */
body {
background-color: $primary-color;
color: $secondary-color;
font-family: $body-font;
}
/* Đoạn code trên sẽ được biên dịch thành: */
body {
background-color: #A3A4FF;
color: #51527F;
font-family: 'Roboto', sans-serif;
}
/* Cách sử dụng này giúp ta dễ dàng bảo trì hơn
việc phải đổi giá trị mỗi lần xuất hiện
trong tệp stylesheet. */
/* Control Directive - Chỉ thị
============================== */
/* Sass cho phép sử dụng @if, @else, @for, @while @each để quản luồng code sinh ra CSS */
/* Khối điều kiện @if/@else hoạt động như các ngôn ngữ khác */
$debug: true !default;
@mixin debugmode {
@if $debug {
@debug "Debug mode enabled";
display: inline-block;
}
@else {
display: none;
}
}
.info {
@include debugmode;
}
/* Trong đoạn code trên, nếu $debug được đặt true thì class .info sẽ được sinh ra ngược lại.
Lưu ý: @debug sẽ sinh ra thông tin debug trên dòng lệnh (command line).
Chế độ này rất ích khi thực hiện debug trên file SCSS. */
.info {
display: inline-block;
}
/* @for khối vòng lặp trên một khoảng các giá trị.
rất ích cho việc đặt style của một tập hợp các phần tử.
hai cách để lặp, "through" sẽ lặp tới kể cả giá trị cuối cùng, "to" sẽ lặp tới dừng khi đến giá trị cuối cùng. */
// Lặp 3 lần (không kể 4)
@for $c from 1 to 4 {
div:nth-of-type(#{$c}) {
left: ($c - 1) * 900 / 3;
}
}
// Lặp 3 lần (kể cả 3)
@for $c from 1 through 3 {
.myclass-#{$c} {
color: rgb($c * 255 / 3, $c * 255 / 3, $c * 255 / 3);
}
}
/* Biên dịch thành */
div:nth-of-type(1) {
left: 0;
}
div:nth-of-type(2) {
left: 300;
}
div:nth-of-type(3) {
left: 600;
}
.myclass-1 {
color: #555555;
}
.myclass-2 {
color: #aaaaaa;
}
.myclass-3 {
color: white;
// SASS tự động chuyển #FFFFFF thành white (trắng)
}
/* Khối lặp @while rất bản: */
$columns: 4;
$column-width: 80px;
@while $columns > 0 {
.col-#{$columns} {
width: $column-width;
left: $column-width * ($columns - 1);
}
$columns: $columns - 1;
}
/* Sẽ được biên dịch thành: */
.col-4 {
width: 80px;
left: 240px;
}
.col-3 {
width: 80px;
left: 160px;
}
.col-2 {
width: 80px;
left: 80px;
}
.col-1 {
width: 80px;
left: 0px;
}
/* @each hoạt động giống như @for, nhưng sử dụng một danh sách (list) thay thứ tự số đếm.
List được khai báo như những biến khác, sử dụng dấu cách để làm dấu phân cách. */
$social-links: facebook twitter linkedin reddit;
.social-links {
@each $sm in $social-links {
.icon-#{$sm} {
background-image: url("images/#{$sm}.png");
}
}
}
/* Sẽ sinh ra: */
.social-links .icon-facebook {
background-image: url("images/facebook.png");
}
.social-links .icon-twitter {
background-image: url("images/twitter.png");
}
.social-links .icon-linkedin {
background-image: url("images/linkedin.png");
}
.social-links .icon-reddit {
background-image: url("images/reddit.png");
}
/* Mixin
==============================*/
/* Nếu đang viết một đoạn code cho nhiều hơn một
element, ta thể sử dụng lại dễ dàng.
Sử dụng pháp '@mixin' kèm theo tên để tạo một mixin. */
@mixin center {
display: block;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
/* Ta thể dùng mixin bằng pháp '@include' kèm theo tên của mixin. */
div {
@include center;
background-color: $primary-color;
}
/* Được biên dịch thành: */
div {
display: block;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
background-color: #A3A4FF;
}
/* Ta thể dùng mixin để tạo nhanh các thuộc tính. */
@mixin size($width, $height) {
width: $width;
height: $height;
}
/* Trong dụ này ta thể tạo nhanh 2 thuộc tính width height
bằng cách sử dụng mixin size truyền vào tham số cho width height. */
.rectangle {
@include size(100px, 60px);
}
.square {
@include size(40px, 40px);
}
/* Biên dịch thành: */
.rectangle {
width: 100px;
height: 60px;
}
.square {
width: 40px;
height: 40px;
}
/* Function - Hàm
============================== */
/* Less cung cấp các hàm thể được dùng để hoàn thành
các công việc khác nhau. */
/* Hàm được gọi sử dụng tên của truyền vào
các tham số được yêu cầu. */
body {
width: round(10.25px);
}
.footer {
background-color: fade_out(#000000, 0.25);
}
/* Biên dịch thành: */
body {
width: 10px;
}
.footer {
background-color: rgba(0, 0, 0, 0.75);
}
/* Ta thể định nghĩa hàm mới.
hàm khá tương tự với mixin bởi chúng đều thể được tái
sử dụng. Khi lựa chọn giữa việc sử dụng hàm hay mixin,
hãy nhớ mixin được tối ưu cho việc tạo ra CSS trong khi
hàm sẽ được sử dụng tốt hơn cho logic sẽ được sử dụng
xuyên suốt Less code. Các dụ trong phần 'Toán tử toán học' ứng cử viên
sáng giá cho việc dùng hàm thể tái sử dụng được.
*/
/* Hàm này sẽ tính độ tương đối giữa hai giá trị kích thước. */
@function calculate-percentage($target-size, $parent-size) {
@return $target-size / $parent-size * 100%;
}
$main-content: calculate-percentage(600px, 960px);
.main-content {
width: $main-content;
}
.sidebar {
width: calculate-percentage(300px, 960px);
}
/* Biên dịch thành: */
.main-content {
width: 62.5%;
}
.sidebar {
width: 31.25%;
}
/* Mở rộng (Thừa kế)
============================== */
/* Mở rộng cách để chia sẻ thuộc tính của một selector cho selector khác */
.display {
@include size(5em, 5em);
border: 5px solid $secondary-color;
}
.display-success {
@extend .display;
border-color: #22df56;
}
/* Biên dịch thành: */
.display, .display-success {
width: 5em;
height: 5em;
border: 5px solid #51527F;
}
.display-success {
border-color: #22df56;
}
/* Nên mở rộng một khai báo CSS trước thay tạo một mixin mới
bởi cách nhóm các lớp chung một style gốc.
Nếu thực hiện với mixin, các thuộc tính sẽ bị trùng lặp
cho mỗi khai báo sử dụng mixin. Mặc không ảnh hưởng đến luồng công việc nhưng
tạo ra các đoạn code CSS thừa sau khi được biên dịch.
*/
/* Nesting - Lồng
============================== */
/* Sass cho phép ta thể lồng selector bên trong selector */
ul {
list-style-type: none;
margin-top: 2em;
li {
background-color: #FF0000;
}
}
/* Selector bắt đầu bằng tự '&' sẽ thay thế tự '&'
với selector cha. */
/* Ta cũng thể lồng các pseudo-class với nhau */
/* Nên lưu ý không nên lồng quá nhiều lần sẽ làm code kém tính bảo trì.
Kinh nghiệm cho thấy không nên lồng quá 3 lần.
dụ: */
ul {
list-style-type: none;
margin-top: 2em;
li {
background-color: red;
&:hover {
background-color: blue;
}
a {
color: white;
}
}
}
/* Biên dịch thành: */
ul {
list-style-type: none;
margin-top: 2em;
}
ul li {
background-color: red;
}
ul li:hover {
background-color: blue;
}
ul li a {
color: white;
}
/* Partials and Imports - Chia nhỏ thành tệp con nhập vào
============================== */
/* Less cho phép ta tạo các partial file (tệp con).
Sử dụng giúp ta thể tổ chức code Less theo mô-đun hệ thống.
Các tệp con thường bắt đầu với tự gạch dưới '_', vd: _reset.less
được nhập vào file Less chính để được biên dịch thành CSS.
File con không được biên dịch thành file CSS riêng. */
/* Quan sát dụ sau, ta sẽ đặt đoạn code dưới đây vào tệp tên _reset.less */
html,
body,
ul,
ol {
margin: 0;
padding: 0;
}
/* Sass cung cấp pháp @import cho phép nhập các partial vào một file.
pháp này trong Sass sẽ nhập các file kết hợp chúng lại với
code CSS được sinh ra. khác với pháp @import của CSS,
bản chất tạo một HTTP request mới để tải về tệp tin được yêu cầu. */
@import 'reset';
body {
font-size: 16px;
font-family: Helvetica, Arial, Sans-serif;
}
/* Biên dịch thành: */
html, body, ul, ol {
margin: 0;
padding: 0;
}
body {
font-size: 16px;
font-family: Helvetica, Arial, Sans-serif;
}
/* Placeholder Selectors - Selector trống
============================== */
/* Khai báo trống rất hữu dụng khi ta cần tạo một khai báo CSS cần được mở rộng.
Nếu bạn cần tạo một khai báo CSS gốc cho các lần mở rộng sau ta thể
sử dụng một khai báo trống. Khai báo trống bắt đầu với tự '$' thay
sử dụng '.' hay '#'. Khai báo trống sẽ không xuất hiện trong code CSS được biên dịch. */
%content-window {
font-size: 14px;
padding: 10px;
color: #000;
border-radius: 4px;
}
.message-window {
@extend %content-window;
background-color: #0000ff;
}
/* Biên dịch thành: */
.message-window {
font-size: 14px;
padding: 10px;
color: #000;
border-radius: 4px;
}
.message-window {
background-color: #0000ff;
}
/* Toán tử toán học
============================== */
/* Sass cung cấp các toán tử sau: +, -, *, / %.
Điều này rất ích cho việc tính toán giá trị trực tiếp
trong tệp Sass thay phải tính toán thủ công.
Dưới đây dụ về việc tạo một khung thiết kế đơn giản hai cột. */
$content-area: 960px;
$main-content: 600px;
$sidebar-content: 300px;
$main-size: $main-content / $content-area * 100%;
$sidebar-size: $sidebar-content / $content-area * 100%;
$gutter: 100% - ($main-size + $sidebar-size);
body {
width: 100%;
}
.main-content {
width: $main-size;
}
.sidebar {
width: $sidebar-size;
}
.gutter {
width: $gutter;
}
/* Biên dịch thành: */
body {
width: 100%;
}
.main-content {
width: 62.5%;
}
.sidebar {
width: 31.25%;
}
.gutter {
width: 6.25%;
}
```
## SASS hay Sass?
Bạn đã bao giờ thắc mắc liệu Sass có phải là từ viết tắt hay không? Nhiều nguwòi lầm tưởng nó là từ viết tắt nhưng thực chất tên của ngôn ngữ này lại là một từ - Sass.
Do sự lầm tưởng như vậy và mọi người thường xuyên viết nó là "SASS", người sáng lập ra ngôn ngữ này đã đặt một cái tên hài hước cho nó là "Syntactically Awesome StyleSheets" (Thiết lập style có cú pháp một cách tuyệt vời đáng kinh ngạc).
## Tập sử dụng Sass
Nếu bạn muốn thử dùng Sass trên trình duyệt, hãy ghé qua [SassMeister](http://sassmeister.com/). Bạn có thể dùng cả hai cú pháp, hoặc mở cài đặt và chọn Sass hoặc SCSS.
## Tính tương thích
Sass có thể được dùng trong bất kì dự án nào miễn là ta có chương trình để biên dịch nó thành CSS. Ta cần chắc chắn rằng đoạn CSS đang dùng tương thích với các phiên bản trình duyệt mong muốn.
[QuirksMode CSS](http://www.quirksmode.org/css/) và [CanIUse](http://caniuse.com) là nguồn thông tin tin cậy để kiểm tra tính tương thích của mã CSS.
## Tìm hiểu thêm
* [Tài liệu chính thức](http://sass-lang.com/documentation/file.SASS_REFERENCE.html)
* [The Sass Way](http://thesassway.com/) cung cấp các hướng dẫn từ cơ bản đến nâng cao cùng với các tin tức.

189
vi/typescript.md Normal file
View File

@@ -0,0 +1,189 @@
---
language: TypeScript
contributors:
- ["Philippe Vlérick", "https://github.com/pvlerick"]
translators:
- ["Thanh Duy Phan", "https://github.com/thanhpd"]
filename: learntypescript-vi.ts
lang: vi-vn
---
TypeScript là ngôn ngữ được viết nhằm tinh giản quá trình phát triển ứng dụng quy mô lớn được viết bằng JavaScript.
TypeScript bổ sung thêm các khái niệm phổ biến như Class, Module, Interface, Generic và Static typing (tùy chọn) vào JavaScript.
Ngôn ngữ này là tập lớn hơn của JavaScript: tất cả code JavaScript đều là code TypeScript đúng nên nó có thể được thêm vào các dự án một cách nhanh chóng. Trình biên dịch TypeScript sẽ sinh ra JavaScript.
Bài viết này sẽ chỉ tập trung tới các cú pháp bổ sung mà TypeScript thêm vào thay vì nói đến cả các cú pháp [JavaScript](javascript-vi.html.markdown).
Để thử dùng TypeScript với trình biên dịch, đi đến [Sân chơi TypeScript](https://www.typescriptlang.org/play) nơi mà bạn có thể nhập code, sử dụng chức năng hỗ trợ tự hoàn thành code - autocompletion và trực tiếp quan sát mã JavaScript được sinh ra.
```ts
// Đây là 3 khai báo kiểu biến cơ bản trong TypeScript
// (JavaScript chỉ có kiểu của giá trị, không có kiểu của biến)
let isDone: boolean = false;
let lines: number = 42;
let name: string = "Anders";
// Bạn có thể bỏ khai báo kiểu của biến nếu như nó đã được suy ra từ kiểu giá trị cơ bản
let isDone = false;
let lines = 42;
let name = "Anders";
// Có kiểu biến "any" tương thích với mọi kiểu của biến,
// được dùng khi ta không chắc chắn về kiểu của biến khi được khai báo
let notSure: any = 4;
notSure = "có thể là một biến kiểu string";
notSure = false; // cũng có thể là biến kiểu boolean
// Dùng từ khóa const cho khái báo biến không thay đổi (constant variable)
const numLivesForCat = 9;
numLivesForCat = 1; // Có lỗi!
// Khi khai báo tập hợp ta có thể dùng mảng có kiểu được khai báo trước - typed array
let list: number[] = [1, 2, 3];
// Ta cũng có thể sử dụng mảng kiểu chung - generic array
let list: Array<number> = [1, 2, 3];
// Để dùng enumeration - danh sách của một tập hợp:
enum Color { Red, Green, Blue };
let c: Color = Color.Green;
// Nếu function không trả về kết quả, sử dụng "void" cho kết quả trả về
function bigHorribleAlert(): void {
alert("I'm a little annoying box!");
}
// Function trong TypeScript là first-class citizen (tạm dịch: phần tử hạng nhất), hỗ trợ thao tác tới các thực thể khác
// (vd: truyền vào như tham số, được trả về từ function, chỉnh sửa, gán vào một biến)
// TypeScript hỗ trợ sử dụng function với cú pháp lambda (mũi tên) và suy luận kiểu trả về
// Các cú pháp dưới đây tương đương với nhau,
// trình biên dịch sẽ tự nhận biết và sinh ra mã JavaScript giống nhau
let f1 = function (i: number): number { return i * i; }
// Kiểu trả về nếu không khai báo được tự suy diễn
let f2 = function (i: number) { return i * i; }
// Cú pháp mũi tên (arrow syntax)
let f3 = (i: number): number => { return i * i; }
// Cú pháp mũi tên với kiểu trả về được suy diễn
let f4 = (i: number) => { return i * i; }
// Cú pháp mũi tên với kiểu trả về được suy diễn
// khi không sử dụng dấu ngoặc nhọn {} thì không cần sử dụng return
let f5 = (i: number) => i * i;
// Interface mang tính cấu trúc, mọi thứ có các đặc điểm (property) đều tương thích
interface IPerson {
name: string;
// Đặc điểm có thể tùy chọn bằng sử dụng dấu "?"
age?: number;
// Có thể sử dụng function
move(): void;
}
// Object sử dụng interface IPerson nói trên
// có thể được coi là 1 thực thể Person vì nó có đặc điểm name và chức năng move
let p: Person = { name: "Bobby", move: () => { } };
// Object sử dụng property tùy chọn
let validPerson: Person = { name: "Bobby", age: 42, move: () => { } };
// Khai báo dưới đây gây lỗi vì giá trị đặc điểm age không mang kiểu number
let invalidPerson: Person = { name: "Bobby", age: true };
// Interface cũng có thể mô tả đặc tả của function
interface SearchFunc {
(source: string, subString: string): boolean;
}
// Chỉ có kiểu của tham số là quan trọng còn tên không quan trọng
let mySearch: SearchFunc;
mySearch = function (src: string, sub: string) {
return src.search(sub) != -1;
}
// Class - các khai báo mặc định là public
class Point {
// Property
x: number;
// Constructor - sử dụng tham số với từ khóa public/private
// sẽ tạo ra property tương ứng (ví dụ với property y)
// Có thể khai báo giá trị mặc định
constructor(x: number, public y: number = 0) {
this.x = x;
}
// Function
dist() { return Math.sqrt(this.x * this.x + this.y * this.y); }
// Biến Static
static origin = new Point(0, 0);
}
let p1 = new Point(10, 20);
let p2 = new Point(25); // y sử dụng giá trị mặc định là 0
// Thừa kế - Inheritance
class Point3D extends Point {
constructor(x: number, y: number, public z: number = 0) {
super(x, y); // Bắt buộc phải gọi constructor của class cha
}
// Overwrite/Polymorphism - Ghi đè/Đa hình
dist() {
let d = super.dist();
return Math.sqrt(d * d + this.z * this.z);
}
}
// module, "." có thể được dùng như những module con
module Geometry {
export class Square {
constructor(public sideLength: number = 0) {
}
area() {
return Math.pow(this.sideLength, 2);
}
}
}
let s1 = new Geometry.Square(5);
// Bí danh (alias) có thể được sử dụng để tham vấn module khác
import G = Geometry;
let s2 = new G.Square(10);
// Generic
// Class
class Tuple<T1, T2> {
constructor(public item1: T1, public item2: T2) {
}
}
// Interface
interface Pair<T> {
item1: T;
item2: T;
}
// Function
let pairToTuple = function <T>(p: Pair<T>) {
return new Tuple(p.item1, p.item2);
};
let tuple = pairToTuple({ item1: "hello", item2: "world" });
// Các thư viện viết bằng JavaScript thường đi kèm file định nghĩa kiểu để có thể sử dụng cho TypeScript
// Thêm vào tham vấn tới file định nghĩa:
/// <reference path="jquery.d.ts" />
// Template Strings - Chuỗi dạng mẫu (string sử dụng dấu `)
// String Interpolation - Nội suy chuỗi with với template string
let name = 'Tyrone';
let greeting = `Chào ${name}, bạn khỏe không?`
// Chuỗi nhiều dòng với template string
let multiline = `Đây là ví dụ
cho chuỗi nhiều dòng`;
```
## Tìm hiểu thêm
* [Website TypeScript chính thức](https://www.typescriptlang.org/)
* [Mã nguồn trên GitHub](https://github.com/microsoft/TypeScript)

170
vi/xml.md Normal file
View File

@@ -0,0 +1,170 @@
---
language: XML
filename: learnxml.xml
contributors:
- ['João Farias', 'https://github.com/JoaoGFarias']
- ['Rachel Stiyer', 'https://github.com/rstiyer']
- ['Deepanshu Utkarsh', 'https://github.com/duci9y']
translators:
- ['Thanh Duy Phan', 'https://github.com/thanhpd']
lang: vi-vn
---
XML là ngôn ngữ đánh dấu được thiết kế để lưu trữ và truyền tải dữ liệu. Nó có thể được đọc hiểu bởi cả người và máy.
Không giống như HTML, XML không biểu đạt cách hiển thị hoặc định dạng dữ liệu, chỉ chứa dữ liệu mà thôi.
Có những sự khác biệt rõ ràng giữa **nội dung****các đánh dấu**. Nói vắn tắt thì nội dung có thể là bất cứ gì trong khi các đánh dấu được định nghĩa trước.
## Một số định nghĩa và giới thiệu
Các XML Document (Văn bản XML) được cấu thành bởi các _elements (phần tử)_ và chúng có thể có các _attributes (thuộc tính)_ để mô tả, đồng thời cũng có thể chứa các nội dung theo ngữ cảnh và một hoặc nhiều phần tử con. Tất cả XML document phải có một phần tử gốc đóng vai trò tổ tiên cho tất cả các phần tử khác trong văn bản.
Các trình phân tích cú pháp XML (XML Parser) được thiết kế để phân tích rất chặt chẽ, và sẽ dừng phân tích các văn bản không đúng định dạng. Vì vậy cần đảm bảo tất cả văn bản XML tuân theo [Các luật cú pháp XML](http://www.w3schools.com/xml/xml_syntax.asp).
```xml
<!-- Đây là một bình luận. Nó không được phép chứa hai dấu gạch ngang (-) liên tiếp -->
<!-- Comments can span
trải dài nhiều dòngmultiple lines -->
<!-- Element - Phần tử -->
<!-- Một element là thành phần XML cơ bản nhất. Có hai loại, thử nhất là rỗng nô -->
<element1 thuoc-tinh="gia trialue" /> <Các element rỗng không chứa bất nội dung gìtent -->
<!-- và không rỗng nội dung: -->
<element2 thuoc-tinh="gia tri">Nội dung</element2>
<!-- Tên của element chỉ được phép chứa chữ cái và chữ số -->
<empty /> <!-- Một element có thể là một element với tag rỗng… -->
<!-- …không chứa bất cứ nội dung gì và chỉ là markup đơn thuần. -->
<notempty> <!-- Hoặc nó chứa một tag bắt đầu… -->
<!-- …nội dung… -->
</notempty> <!-- và kết thúc với tag đóng. -->
<!-- Tên element phân biệt chữ hoa và thường. -->
<element />
<!-- không giống như -->
<eLEMENT />
<!-- Attribute - Thuộc tính -->
<!-- Một thuộc tính là một cặp key-value và tồn tại bên trong element. -->
<element thuoctinh="giatri" thuoctinhkhac="giatrikhac" nhieugiatri="danhsach phanbiet bangdaucach" />
<!-- Một thuộc tính chỉ xuất hiện một lần trong một element. Nó chỉ chứa một giá trị.
Một cách giải quyết là sử dụng danh sách giá trị được phân biệt bởi dấu cách. -->
<!-- Nesting element - Phần tử lồng nhau -->
<!-- Nội dung một element có thể chứa các element khác -->
<cha>
<con>Text</con>
<elementrong />
</cha>
<!-- Danh pháp cây tiêu chuẩn được tuân theo. Mỗi phần tử được gọi là một nút.
Phần tử cấp trên là cha, phần tử cấp dưới là con.
Các element trong cùng một element cha có mức tương đương nhau như anh chị em. -->
<!-- XML bảo lưu dấu cách. -->
<child>
Văn bản
</child>
<!-- sẽ không giống như -->
<child>Văn bản</child>
```
## Một văn bản XML - XML document
Đây là thứ làm cho XML rất linh hoạt do nó giúp con người cũng đọc được. Văn bản sau đây cho ta biết nó định nghĩa một hiệu sách bản ba quyển sách, trong đó có một cuốn tên Learning XML bởi Erik T. Ray. Tất cả những việc này chưa cần phải sử dụng XML Parser.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Đây là phần mở đầu, không bắt buộc cần nhưng nên có -->
<hieusach>
<sach danhmuc="NAUAN">
<tieude lang="en">Everyday Italian</tieude>
<tacgia>Giada De Laurentiis</tacgia>
<nam>2005</nam>
<giaban>30.00</giaban>
</sach>
<sach danhmuc="TREEM">
<tieude lang="en">Harry Potter</tieude>
<tacgia>J K. Rowling</tacgia>
<nam>2005</nam>
<giaban>29.99</giaban>
</sach>
<sach danhmuc="WEB">
<tieude lang="en">Learning XML</tieude>
<tacgia>Erik T. Ray</tacgia>
<nam>2003</nam>
<giaban>39.95</giaban>
</sach>
</hieusach>
```
## Tính đúng đắn và việc xác minh
Một văn bản XML là _đúng đắn (well-formed)_ nếu nó có cú pháp chính xác. Ty nhiên, ta có thể thêm nhiều ràng buộc vào văn bản, sử dụng Document Type Definition (DTD) - Định dạng loại văn bản. Một văn bản mà các phần tử và thuộc tính được khai báo trong một DTĐ và tuân theo ngữ pháp được đưa ra trong DTD đó được gọi là _valid - được chấp nhận_ và tuân theo DTD bên cạnh việc đúng đắn.
```xml
<!-- Khai báo DTD lấy từ tệp bên ngoài: -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hieusach SYSTEM "Hieusach.dtd">
<!-- Khai báo hieusach là phần tử gốc và 'Hieusach.dtd' là đường dẫn
tới tệp DTD. -->
<hieusach>
<sach danhmuc="NAUAN">
<tieude lang="en">Everyday Italian</tieude>
<tacgia>Giada De Laurentiis</tacgia>
<nam>2005</nam>
<giaban>30.00</giaban>
</sach>
</hieusach>
<!-- Tệp DTD: -->
<!ELEMENT hieusach (sach+)>
<!-- Element hieusach có thể chứa một hoặc nhiều element sach. -->
<!ELEMENT sach (tieude, giaban)>
<!-- Mỗi sach cần có các element con tên tieude và giaban. -->
<!ATTLIST sach danhmuc CDATA "Vanhoc">
<!-- Mỗi sach cần có một thuộc tính danhmuc. Nếu không có, giá trị mặc định
sẽ là 'Vanhoc'. -->
<!ELEMENT tieude (#PCDATA)>
<!-- Element tieude chỉ được chứa nội dung dữ liệu kĩ tự được phân tích.
Nói cách khác, nó có thể
chỉ chứa văn bản được phân tích bởi parser và không được phép chứa element con
So sánh với CDATA, hay dữ liệu kí tự -->
<!ELEMENT giaban (#PCDATA)>
]>
<!-- DTD có thể được khai báo bên trong chính tệp XML.-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hieusach [
<!ELEMENT hieusach (sach+)>
<!ELEMENT sach (tieude, giaban)>
<!ATTLIST sach danhmuc CDATA "Vanhoc">
<!ELEMENT tieude (#PCDATA)>
<!ELEMENT giaban (#PCDATA)>
]>
<hieusach>
<sach danhmuc="NAUAN">
<tieude lang="en">Everyday Italian</tieude>
<giaban>30.00</giaban>
</sach>
</hieusach>
```
## DTD Compatibility and XML Schema Definitions (Tương thích DTD và định nghĩa XML Schema)
Hỗ trợ cho DTD khá nhiều do chúng đã quá cũ. Tuy nhiên, nhiều tính năng hiện đại của XML như namespace không được hỗ trợ bởi DTD. XML Schema Definition (XSD) - Định nghĩa lược đồ XML được coi như sẽ thay thế DTD để định nghĩa cấu trúc ngữ pháp của văn bản XML.
## Tra cứu
- [Validate your XML (Xác minh XML)](http://www.xmlvalidation.com)
## Đọc thêm
- [Hướng dẫn XML Schema Definitions](http://www.w3schools.com/schema/)
- [Hướng dẫn DTD](http://www.w3schools.com/xml/xml_dtd_intro.asp)
- [Hướng dẫn XML](http://www.w3schools.com/xml/default.asp)
- [Dùng XPath queries để phân tích cú pháp XML](http://www.w3schools.com/xml/xml_xpath.asp)