summaryrefslogtreecommitdiffhomepage
path: root/zh-cn
diff options
context:
space:
mode:
Diffstat (limited to 'zh-cn')
-rw-r--r--zh-cn/java-cn.html.markdown15
-rw-r--r--zh-cn/javascript-cn.html.markdown516
-rw-r--r--zh-cn/swift-cn.html.markdown590
3 files changed, 785 insertions, 336 deletions
diff --git a/zh-cn/java-cn.html.markdown b/zh-cn/java-cn.html.markdown
index f7d319e6..f08d3507 100644
--- a/zh-cn/java-cn.html.markdown
+++ b/zh-cn/java-cn.html.markdown
@@ -124,7 +124,7 @@ public class LearnJava {
// HashMaps
///////////////////////////////////////
- // 操作符
+ // 操作符
///////////////////////////////////////
System.out.println("\n->Operators");
@@ -161,10 +161,13 @@ public class LearnJava {
// 自增
int i = 0;
System.out.println("\n->Inc/Dec-rementation");
- System.out.println(i++); //i = 1 后自增
- System.out.println(++i); //i = 2 前自增
- System.out.println(i--); //i = 1 后自减
- System.out.println(--i); //i = 0 前自减
+ // ++ 和 -- 操作符使变量加或减1。放在变量前面或者后面的区别是整个表达
+ // 式的返回值。操作符在前面时,先加减,后取值。操作符在后面时,先取值
+ // 后加减。
+ System.out.println(i++); // 后自增 i = 1, 输出0
+ System.out.println(++i); // 前自增 i = 2, 输出2
+ System.out.println(i--); // 后自减 i = 1, 输出2
+ System.out.println(--i); // 前自减 i = 0, 输出0
///////////////////////////////////////
// 控制结构
@@ -192,7 +195,7 @@ public class LearnJava {
}
System.out.println("fooWhile Value: " + fooWhile);
- // Do While循环
+ // Do While循环
int fooDoWhile = 0;
do
{
diff --git a/zh-cn/javascript-cn.html.markdown b/zh-cn/javascript-cn.html.markdown
index 7dee9cc4..64b0aadc 100644
--- a/zh-cn/javascript-cn.html.markdown
+++ b/zh-cn/javascript-cn.html.markdown
@@ -5,17 +5,19 @@ name: javascript
filename: javascript-zh.js
contributors:
- ["Adam Brenecki", "http://adam.brenecki.id.au"]
+ - ["Ariel Krakowski", "http://www.learneroo.com"]
translators:
- ["Chenbo Li", "http://binarythink.net"]
+ - ["Guodong Qu", "https://github.com/jasonqu"]
lang: zh-cn
---
Javascript于1995年由网景公司的Brendan Eich发明。
最初发明的目的是作为一个简单的网站脚本语言,来作为
-复杂网站应用java的补充。但由于javascript和网站结合度很高
-所以javascript逐渐变得比java在前端更为流行了。
+复杂网站应用java的补充。但由于它与网页结合度很高并且由浏览器内置支持,
+所以javascript变得比java在前端更为流行了。
-JavaScript 不仅仅只可以用于浏览器, 也可用于 Node.js 等后台环境。
+不过 JavaScript 可不仅仅只用于浏览器: Node.js,一个基于Google Chrome V8引擎的独立运行时环境,也越来越流行。
很欢迎来自您的反馈,您可以通过下列方式联系到我:
[@adambrenecki](https://twitter.com/adambrenecki), 或者
@@ -29,145 +31,167 @@ JavaScript 不仅仅只可以用于浏览器, 也可用于 Node.js 等后台环
// 语句可以以分号结束
doStuff();
-// ... 但是分号也可以省略,每当遇到一个新行时,分号会自动插入
+// ... 但是分号也可以省略,每当遇到一个新行时,分号会自动插入(除了一些特殊情况)。
doStuff()
-// 我们在这里会去掉分号,但是否添加最后的分号取决于你个人的习惯
-// 及你所在团队的编程风格
+// 因为这些特殊情况会导致意外的结果,所以我们在这里保留分号。
///////////////////////////////////
// 1. 数字、字符串与操作符
-// Javascript 只有一种数字类型 (即 64位 IEEE 754 双精度浮点).
-3 // = 3
-1.5 // = 1.5
+// Javascript 只有一种数字类型(即 64位 IEEE 754 双精度浮点 double)。
+// double 有 52 位表示尾数,足以精确存储大到 9✕10¹⁵ 的整数。
+3; // = 3
+1.5; // = 1.5
-// 所有基本的算数运算
-1 + 1 // = 2
-8 - 1 // = 7
-10 * 2 // = 20
-35 / 5 // = 7
+// 所有基本的算数运算都如你预期。
+1 + 1; // = 2
+0.1 + 0.2; // = 0.30000000000000004
+8 - 1; // = 7
+10 * 2; // = 20
+35 / 5; // = 7
-// 包括无法整除的除法
-5 / 2 // = 2.5
+// 包括无法整除的除法。
+5 / 2; // = 2.5
-// 位运算也和其他语言一样。当你对浮点数进行位运算时,
-// 浮点数会转换为至多 32 位的无符号整数
-1 << 2 // = 4
+// 位运算也和其他语言一样;当你对浮点数进行位运算时,
+// 浮点数会转换为*至多* 32 位的无符号整数。
+1 << 2; // = 4
-// 括号可以决定优先级
-(1 + 3) * 2 // = 8
+// 括号可以决定优先级。
+(1 + 3) * 2; // = 8
// 有三种非数字的数字类型
-Infinity // 1/0 的结果
--Infinity // -1/0 的结果
-NaN // 0/0 的结果
+Infinity; // 1/0 的结果
+-Infinity; // -1/0 的结果
+NaN; // 0/0 的结果
-// 也有布尔值
-true
-false
+// 也有布尔值。
+true;
+false;
-// 可以通过单引号或双引号来构造字符串
-'abc'
-"Hello, world"
+// 可以通过单引号或双引号来构造字符串。
+'abc';
+"Hello, world";
// 用!来取非
-!true // = false
-!false // = true
+!true; // = false
+!false; // = true
-// 相等 ==
-1 == 1 // = true
-2 == 1 // = false
+// 相等 ===
+1 === 1; // = true
+2 === 1; // = false
// 不等 !=
-1 != 1 // = false
-2 != 1 // = true
+1 !== 1; // = false
+2 !== 1; // = true
// 更多的比较操作符
-1 < 10 // = true
-1 > 10 // = false
-2 <= 2 // = true
-2 >= 2 // = true
+1 < 10; // = true
+1 > 10; // = false
+2 <= 2; // = true
+2 >= 2; // = true
// 字符串用+连接
-"Hello " + "world!" // = "Hello world!"
+"Hello " + "world!"; // = "Hello world!"
// 字符串也可以用 < 、> 来比较
-"a" < "b" // = true
+"a" < "b"; // = true
-// 比较时会进行类型转换...
-"5" == 5 // = true
+// 使用“==”比较时会进行类型转换...
+"5" == 5; // = true
+null == undefined; // = true
// ...除非你是用 ===
-"5" === 5 // = false
+"5" === 5; // = false
+null === undefined; // = false
-// 你可以用charAt来得到字符串中的字符
-"This is a string".charAt(0)
+// ...但会导致奇怪的行为
+13 + !0; // 14
+"13" + !0; // '13true'
-// 还有两个特殊的值:null和undefined
-null // 用来表示刻意设置成的空值
-undefined // 用来表示还没有设置的值
+// 你可以用`charAt`来得到字符串中的字符
+"This is a string".charAt(0); // = 'T'
-// null, undefined, NaN, 0 和 "" 都是假的(false),其他的都视作逻辑真
-// 注意 0 是逻辑假而 "0"是逻辑真, 尽管 0 == "0".
+// ...或使用 `substring` 来获取更大的部分。
+"Hello world".substring(0, 5); // = "Hello"
+
+// `length` 是一个属性,所以不要使用 ().
+"Hello".length; // = 5
+
+// 还有两个特殊的值:`null`和`undefined`
+null; // 用来表示刻意设置的空值
+undefined; // 用来表示还没有设置的值(尽管`undefined`自身实际是一个值)
+
+// false, null, undefined, NaN, 0 和 "" 都是假的;其他的都视作逻辑真
+// 注意 0 是逻辑假而 "0"是逻辑真,尽管 0 == "0"。
///////////////////////////////////
// 2. 变量、数组和对象
-// 变量需要用 var 这个关键字声明. Javascript是动态类型语言
-// 所以你在声明时无需指定类型。 赋值需要用 =
-var someVar = 5
+// 变量需要用`var`关键字声明。Javascript是动态类型语言,
+// 所以你无需指定类型。 赋值需要用 `=`
+var someVar = 5;
-// 如果你在声明时没有加var关键字,你也不会得到错误
-someOtherVar = 10
+// 如果你在声明时没有加var关键字,你也不会得到错误...
+someOtherVar = 10;
-// ...但是此时这个变量就会拥有全局的作用域,而非当前作用域
+// ...但是此时这个变量就会在全局作用域被创建,而非你定义的当前作用域
-// 没有被赋值的变量都会返回undefined这个值
-var someThirdVar // = undefined
+// 没有被赋值的变量都会被设置为undefined
+var someThirdVar; // = undefined
-// 对变量进行数学运算有一些简写法
-someVar += 5 // 等价于 someVar = someVar + 5; someVar 现在是 10
-someVar *= 10 // 现在 someVar 是 100
+// 对变量进行数学运算有一些简写法:
+someVar += 5; // 等价于 someVar = someVar + 5; someVar 现在是 10
+someVar *= 10; // 现在 someVar 是 100
// 自增和自减也有简写
-someVar++ // someVar 是 101
-someVar-- // 回到 100
+someVar++; // someVar 是 101
+someVar--; // 回到 100
// 数组是任意类型组成的有序列表
-var myArray = ["Hello", 45, true]
+var myArray = ["Hello", 45, true];
+
+// 数组的元素可以用方括号下标来访问。
+// 数组的索引从0开始。
+myArray[1]; // = 45
-// 数组的元素可以用方括号下标来访问
-// 数组的索引从0开始
-myArray[1] // = 45
+// 数组是可变的,并拥有变量 length。
+myArray.push("World");
+myArray.length; // = 4
-// javascript中的对象相当于其他语言中的字典或映射:是键-值的集合
-{key1: "Hello", key2: "World"}
+// 在指定下标添加/修改
+myArray[3] = "Hello";
-// 键是字符串,但是引号也并非是必须的,如果键本身是合法的js标识符
-// 而值则可以是任意类型的值
-var myObj = {myKey: "myValue", "my other key": 4}
+// javascript中的对象相当于其他语言中的“字典”或“映射”:是键-值对的无序集合。
+var myObj = {key1: "Hello", key2: "World"};
-// 对象的访问可以通过下标
-myObj["my other key"] // = 4
+// 键是字符串,但如果键本身是合法的js标识符,则引号并非是必须的。
+// 值可以是任意类型。
+var myObj = {myKey: "myValue", "my other key": 4};
+
+// 对象属性的访问可以通过下标
+myObj["my other key"]; // = 4
// ... 或者也可以用 . ,如果属性是合法的标识符
-myObj.myKey // = "myValue"
+myObj.myKey; // = "myValue"
-// 对象是可变的,键和值也可以被更改或增加
-myObj.myThirdKey = true
+// 对象是可变的;值也可以被更改或增加新的键
+myObj.myThirdKey = true;
-// 如果你想要访问一个还没有被定义的属性,那么会返回undefined
-myObj.myFourthKey // = undefined
+// 如果你想要获取一个还没有被定义的值,那么会返回undefined
+myObj.myFourthKey; // = undefined
///////////////////////////////////
// 3. 逻辑与控制结构
-// if语句和其他语言中一样
-var count = 1
+// 本节介绍的语法与Java的语法几乎完全相同
+
+// `if`语句和其他语言中一样。
+var count = 1;
if (count == 3){
// count 是 3 时执行
-} else if (count == 4) {
+} else if (count == 4){
// count 是 4 时执行
} else {
// 其他情况下执行
@@ -179,219 +203,273 @@ while (true) {
}
// Do-while 和 While 循环很像 ,但前者会至少执行一次
-var input
+var input;
do {
- input = getInput()
+ input = getInput();
} while (!isValid(input))
-// for循环和C、Java中的一样
-// 初始化; 继续执行的条件; 遍历后执行.
+// `for`循环和C、Java中的一样:
+// 初始化; 继续执行的条件; 迭代。
for (var i = 0; i < 5; i++){
// 遍历5次
}
// && 是逻辑与, || 是逻辑或
if (house.size == "big" && house.colour == "blue"){
- house.contains = "bear"
+ house.contains = "bear";
}
if (colour == "red" || colour == "blue"){
// colour是red或者blue时执行
}
-// && 和 || 是“短路”语句,在初始化值时会变得有用
-var name = otherName || "default"
+// && 和 || 是“短路”语句,它在设定初始化值时特别有用
+var name = otherName || "default";
+
+// `switch`语句使用`===`检查相等性。
+// 在每一个case结束时使用 'break'
+// 否则其后的case语句也将被执行。
+grade = 'B';
+switch (grade) {
+ case 'A':
+ console.log("Great job");
+ break;
+ case 'B':
+ console.log("OK job");
+ break;
+ case 'C':
+ console.log("You can do better");
+ break;
+ default:
+ console.log("Oy vey");
+ break;
+}
///////////////////////////////////
// 4. 函数、作用域、闭包
-// JavaScript 函数由function关键字定义
+// JavaScript 函数由`function`关键字定义
function myFunction(thing){
- return thing.toUpperCase()
+ return thing.toUpperCase();
}
-myFunction("foo") // = "FOO"
-
-// 函数也可以是匿名的:
-function(thing){
- return thing.toLowerCase()
+myFunction("foo"); // = "FOO"
+
+// 注意被返回的值必须开始于`return`关键字的那一行,
+// 否则由于自动的分号补齐,你将返回`undefined`。
+// 在使用Allman风格的时候要注意.
+function myFunction()
+{
+ return // <- 分号自动插在这里
+ {
+ thisIsAn: 'object literal'
+ }
}
-// (我们无法调用此函数,因为我们不知道这个函数的名字)
+myFunction(); // = undefined
-// javascript中的函数也是对象,所以函数也能够赋给一个变量,并且被传递
-// 比如一个事件处理函数:
+// javascript中函数是一等对象,所以函数也能够赋给一个变量,
+// 并且被作为参数传递 —— 比如一个事件处理函数:
function myFunction(){
- // this code will be called in 5 seconds' time
+ // 这段代码将在5秒钟后被调用
}
-setTimeout(myFunction, 5000)
-
-// 你甚至可以直接把一个函数写到另一个函数的参数中
+setTimeout(myFunction, 5000);
+// 注意:setTimeout不是js语言的一部分,而是由浏览器和Node.js提供的。
-setTimeout(function myFunction(){
- // 5秒之后会执行这里的代码
-}, 5000)
+// 函数对象甚至不需要声明名称 —— 你可以直接把一个函数定义写到另一个函数的参数中
+setTimeout(function(){
+ // 这段代码将在5秒钟后被调用
+}, 5000);
-// JavaScript 仅有函数作用于,而其他的语句则没有作用域
+// JavaScript 有函数作用域;函数有其自己的作用域而其他的代码块则没有。
if (true){
- var i = 5
+ var i = 5;
}
-i // = 5 - 并非我们在其他语言中所得到的undefined
-
-// 这就导致了人们经常用一种叫做“即使执行匿名函数”的模式
-// 这样可以避免一些临时变量扩散到外边去
-function(){
- var temporary = 5
- // 我们可以访问一个全局对象来访问全局作用域
- // 在浏览器中是 'window' 这个对象。
- // 在Node.js中这个对象的名字可能会不同。
- window.permanent = 10
- // 或者,我们也可以把var去掉就行了
- permanent2 = 15
-}()
-temporary // 抛出引用异常
-permanent // = 10
-permanent2 // = 15
-
-// javascript最强大的功能之一就是闭包
-// 如果一个函数在另一个函数中定义,那么这个函数就拥有外部函数的所有访问权
+i; // = 5 - 并非我们在其他语言中所期望得到的undefined
+
+// 这就导致了人们经常使用的“立即执行匿名函数”的模式,
+// 这样可以避免一些临时变量扩散到全局作用域去。
+(function(){
+ var temporary = 5;
+ // 我们可以访问修改全局对象("global object")来访问全局作用域,
+ // 在web浏览器中是`window`这个对象。
+ // 在其他环境如Node.js中这个对象的名字可能会不同。
+ window.permanent = 10;
+})();
+temporary; // 抛出引用异常ReferenceError
+permanent; // = 10
+
+// javascript最强大的功能之一就是闭包。
+// 如果一个函数在另一个函数中定义,那么这个内部函数就拥有外部函数的所有变量的访问权,
+// 即使在外部函数结束之后。
function sayHelloInFiveSeconds(name){
- var prompt = "Hello, " + name + "!"
+ var prompt = "Hello, " + name + "!";
+ // 内部函数默认是放在局部作用域的,
+ // 就像是用`var`声明的。
function inner(){
- alert(prompt)
+ alert(prompt);
}
- setTimeout(inner, 5000)
- // setTimeout 是异步的,所以这个函数会马上终止不会等待。
- // 然而,在5秒结束后,inner函数仍然会弹出prompt信息。
+ setTimeout(inner, 5000);
+ // setTimeout是异步的,所以 sayHelloInFiveSeconds 函数会立即退出,
+ // 而 setTimeout 会在后面调用inner
+ // 然而,由于inner是由sayHelloInFiveSeconds“闭合包含”的,
+ // 所以inner在其最终被调用时仍然能够访问`prompt`变量。
}
-sayHelloInFiveSeconds("Adam") // 会在5秒后弹出 "Hello, Adam!"
+sayHelloInFiveSeconds("Adam"); // 会在5秒后弹出 "Hello, Adam!"
+
///////////////////////////////////
// 5. 对象、构造函数与原型
-// 对象包含方法
+// 对象可以包含方法。
var myObj = {
myFunc: function(){
- return "Hello world!"
+ return "Hello world!";
}
-}
-myObj.myFunc() // = "Hello world!"
+};
+myObj.myFunc(); // = "Hello world!"
-// 当对象中的函数被调用时,这个函数就可以通过this关键字访问这个对象
+// 当对象中的函数被调用时,这个函数可以通过`this`关键字访问其依附的这个对象。
myObj = {
myString: "Hello world!",
myFunc: function(){
- return this.myString
+ return this.myString;
}
-}
-myObj.myFunc() // = "Hello world!"
+};
+myObj.myFunc(); // = "Hello world!"
-// 但这个函数访问的其实是其运行时环境,而非定义时环境
-// 所以如果函数所在的环境不在当前对象的环境中运行时,就运行不成功了
-var myFunc = myObj.myFunc
-myFunc() // = undefined
+// 但这个函数访问的其实是其运行时环境,而非定义时环境,即取决于函数是如何调用的。
+// 所以如果函数被调用时不在这个对象的上下文中,就不会运行成功了。
+var myFunc = myObj.myFunc;
+myFunc(); // = undefined
-// 相应的,一个函数也可以被指定为一个对象的方法,并且用过this可以访问
-// 这个对象的成员,即使在定义时并没有绑定任何值
+// 相应的,一个函数也可以被指定为一个对象的方法,并且可以通过`this`访问
+// 这个对象的成员,即使在行数被定义时并没有依附在对象上。
var myOtherFunc = function(){
- return this.myString.toUpperCase()
+ return this.myString.toUpperCase();
+}
+myObj.myOtherFunc = myOtherFunc;
+myObj.myOtherFunc(); // = "HELLO WORLD!"
+
+// 当我们通过`call`或者`apply`调用函数的时候,也可以为其指定一个执行上下文。
+var anotherFunc = function(s){
+ return this.myString + s;
}
-myObj.myOtherFunc = myOtherFunc
-myObj.myOtherFunc() // = "HELLO WORLD!"
+anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!"
-// 当你通过new关键字调用一个函数时,就会生成一个对象
-// 而对象的成员需要通过this来定义。
-// 这样的函数就叫做构造函数
+// `apply`函数几乎完全一样,只是要求一个array来传递参数列表。
+anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!"
+// 当一个函数接受一系列参数,而你想传入一个array时特别有用。
+Math.min(42, 6, 27); // = 6
+Math.min([42, 6, 27]); // = NaN (uh-oh!)
+Math.min.apply(Math, [42, 6, 27]); // = 6
+
+// 但是`call`和`apply`只是临时的。如果我们希望函数附着在对象上,可以使用`bind`。
+var boundFunc = anotherFunc.bind(myObj);
+boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!"
+
+// `bind` 也可以用来部分应用一个函数(柯里化)。
+var product = function(a, b){ return a * b; }
+var doubler = product.bind(this, 2);
+doubler(8); // = 16
+
+// 当你通过`new`关键字调用一个函数时,就会创建一个对象,
+// 而且可以通过this关键字访问该函数。
+// 设计为这样调用的函数就叫做构造函数。
var MyConstructor = function(){
- this.myNumber = 5
+ this.myNumber = 5;
}
-myNewObj = new MyConstructor() // = {myNumber: 5}
-myNewObj.myNumber // = 5
+myNewObj = new MyConstructor(); // = {myNumber: 5}
+myNewObj.myNumber; // = 5
-// 每一个js对象都有一个原型,当你要访问一个没有定义过的成员时,
-// 解释器就回去找这个对象的原型
+// 每一个js对象都有一个‘原型’。当你要访问一个实际对象中没有定义的一个属性时,
+// 解释器就回去找这个对象的原型。
-// 有一些JS实现会让你通过一个对象的__proto__方法访问这个原型。
-// 这虽然对理解这个对象很有用,但是这并不是标准的一部分
-// 我们之后会通过标准方式来访问原型。
+// 一些JS实现会让你通过`__proto__`属性访问一个对象的原型。
+// 这虽然对理解原型很有用,但是它并不是标准的一部分;
+// 我们后面会介绍使用原型的标准方式。
var myObj = {
- myString: "Hello world!",
-}
+ myString: "Hello world!"
+};
var myPrototype = {
meaningOfLife: 42,
myFunc: function(){
return this.myString.toLowerCase()
}
-}
-myObj.__proto__ = myPrototype
-myObj.meaningOfLife // = 42
+};
-// This works for functions, too.
+myObj.__proto__ = myPrototype;
+myObj.meaningOfLife; // = 42
+
+// 函数也可以工作。
myObj.myFunc() // = "hello world!"
-// 当然,如果你要访问的成员在原型当中也没有定义的话,解释器就会去找原型的原型。
+// 当然,如果你要访问的成员在原型当中也没有定义的话,解释器就会去找原型的原型,以此类堆。
myPrototype.__proto__ = {
myBoolean: true
-}
-myObj.myBoolean // = true
-
-// 这其中并没有对象的拷贝。每个对象的原型实际上是持有原型对象的引用
-// 这说明当我们改变对象的原型时,会影响到其他以这个原型为原型的对象
-myPrototype.meaningOfLife = 43
-myObj.meaningOfLife // = 43
-
-// 我们知道 __proto__ 并非标准规定,实际上也没有办法更改已经指定好的原型。
-// 但是,我们有两种方式可以为新的对象指定原型。
-
-// 第一种方式是 Object.create,这个方法是在最近才被添加到Js中的
-// 也因此并不是所有的JS实现都有这个放啊
-var myObj = Object.create(myPrototype)
-myObj.meaningOfLife // = 43
-
-// 第二种方式可以在任意版本中使用,不过需要通过构造函数。
-// 构造函数有一个属性prototype。但是这 *不是* 构造函数本身的函数
-// 而是通过构造函数和new关键字生成新对象时自动生成的。
-myConstructor.prototype = {
+};
+myObj.myBoolean; // = true
+
+// 这其中并没有对象的拷贝;每个对象实际上是持有原型对象的引用。
+// 这意味着当我们改变对象的原型时,会影响到其他以这个原型为原型的对象。
+myPrototype.meaningOfLife = 43;
+myObj.meaningOfLife; // = 43
+
+// 我们知道 `__proto__` 并非标准规定,实际上也没有标准办法来修改一个已存在对象的原型。
+// 然而,我们有两种方式为指定原型创建一个新的对象。
+
+// 第一种方式是 Object.create,这个方法是在最近才被添加到Js中的,
+// 因此并不是所有的JS实现都有这个方法
+var myObj = Object.create(myPrototype);
+myObj.meaningOfLife; // = 43
+
+// 第二种方式可以在任意版本中使用,不过必须通过构造函数。
+// 构造函数有一个属性prototype。但是它 *不是* 构造函数本身的原型;相反,
+// 是通过构造函数和new关键字创建的新对象的原型。
+MyConstructor.prototype = {
+ myNumber: 5,
getMyNumber: function(){
- return this.myNumber
+ return this.myNumber;
}
-}
-var myNewObj2 = new myConstructor()
-myNewObj2.getMyNumber() // = 5
+};
+var myNewObj2 = new MyConstructor();
+myNewObj2.getMyNumber(); // = 5
+myNewObj2.myNumber = 6
+myNewObj2.getMyNumber(); // = 6
// 字符串和数字等内置类型也有通过构造函数来创建的包装类型
-var myNumber = 12
-var myNumberObj = new Number(12)
-myNumber == myNumberObj // = true
+var myNumber = 12;
+var myNumberObj = new Number(12);
+myNumber == myNumberObj; // = true
// 但是它们并非严格等价
-typeof myNumber // = 'number'
-typeof myNumberObj // = 'object'
-myNumber === myNumberObj // = false
+typeof myNumber; // = 'number'
+typeof myNumberObj; // = 'object'
+myNumber === myNumberObj; // = false
if (0){
// 这段代码不会执行,因为0代表假
}
if (Number(0)){
- // 这段代码会执行,因为Number(0)代表真
+ // 这段代码*会*执行,因为Number(0)代表真
}
-// 但是,包装类型和内置类型共享一个原型
-// 这样你就可以给内置类型也增加一些功能
+// 不过,包装类型和内置类型共享一个原型,
+// 所以你实际可以给内置类型也增加一些功能,例如对string:
String.prototype.firstCharacter = function(){
- return this.charAt(0)
+ return this.charAt(0);
}
-"abc".firstCharacter() // = "a"
+"abc".firstCharacter(); // = "a"
-// 这个技巧可以用来用老版本的javascript子集来是实现新版本js的功能
+// 这个技巧经常用在“代码填充”中,来为老版本的javascript子集增加新版本js的特性,
// 这样就可以在老的浏览器中使用新功能了。
-// 比如,我们知道Object.create并没有在所有的版本中都实现
-// 但是我们仍然可以通过这个技巧来使用
+// 比如,我们知道Object.create并没有在所有的版本中都实现,
+// 但是我们仍然可以通过“代码填充”来实现兼容:
if (Object.create === undefined){ // 如果存在则不覆盖
Object.create = function(proto){
// 用正确的原型来创建一个临时构造函数
- var Constructor = function(){}
- Constructor.prototype = proto
+ var Constructor = function(){};
+ Constructor.prototype = proto;
// 之后用它来创建一个新的对象
- return new Constructor()
+ return new Constructor();
}
}
```
@@ -399,19 +477,23 @@ if (Object.create === undefined){ // 如果存在则不覆盖
## 更多阅读
[Mozilla 开发者
-网络](https://developer.mozilla.org/en-US/docs/Web/JavaScript) 提供了很好的
-Javascript文档,并且由于是wiki,所以你也可以自行编辑来分享你的知识。
+网络](https://developer.mozilla.org/en-US/docs/Web/JavaScript) 提供了优秀的介绍
+Javascript如何在浏览器中使用的文档。而且它是wiki,所以你也可以自行编辑来分享你的知识。
MDN的 [A re-introduction to
JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)
-覆盖了这里提到的绝大多数话题,大多数只是Javascript这个语言本身。
+覆盖了这里提到的绝大多数话题的细节。该导引的大多数内容被限定在只是Javascript这个语言本身;
如果你想了解Javascript是如何在网页中被应用的,那么可以查看
[Document Object
Model](https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core)
+[Learn Javascript by Example and with Challenges](http://www.learneroo.com/modules/64/nodes/350) 是本参考的另一个版本,并包含了挑战习题。
+
[Javascript Garden](http://bonsaiden.github.io/JavaScript-Garden/) 是一个深入
-讲解所有Javascript反直觉部分的一本书
+讲解所有Javascript反直觉部分的导引。
+
+[JavaScript: The Definitive Guide](http://www.amazon.com/gp/product/0596805527/) 是一个经典的指导参考书。
除了这篇文章的直接贡献者之外,这篇文章也参考了这个网站上
Louie Dinh 的 Python 教程,以及 Mozilla开发者网络上的[JS
-Tutorial](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)
+Tutorial](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)。
diff --git a/zh-cn/swift-cn.html.markdown b/zh-cn/swift-cn.html.markdown
index b9696c72..28001e3f 100644
--- a/zh-cn/swift-cn.html.markdown
+++ b/zh-cn/swift-cn.html.markdown
@@ -5,223 +5,587 @@ contributors:
- ["Grant Timmerman", "http://github.com/grant"]
translators:
- ["Xavier Yao", "http://github.com/xavieryao"]
+ - ["Joey Huang", "http://github.com/kamidox"]
lang: zh-cn
---
-Swift 是Apple 开发的用于iOS 和OS X 开发的编程语言。Swift 于2014年Apple WWDC (全球开发者大会)中被引入,用以与Objective-C 共存,同时对错误代码更具弹性。Swift 由Xcode 6 beta 中包含的LLVM编译器编译。
+Swift 是 Apple 开发的用于 iOS 和 OS X 开发的编程语言。Swift 于2014年 Apple WWDC (全球开发者大会)中被引入,用以与 Objective-C 共存,同时对错误代码更具弹性。Swift 由 Xcode 6 beta 中包含的 LLVM 编译器编译。
-参阅:Apple's [getting started guide](https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/LandingPage/index.html) ——一个完整的Swift 教程
+Swift 的官方语言教程 [Swift Programming Language](https://itunes.apple.com/us/book/swift-programming-language/id881256329) 可以从 iBooks 免费下载.
+
+亦可参阅:Apple's [getting started guide](https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/RoadMapiOS/index.html) ——一个完整的Swift 教程
```swift
-//
-// 基础
+// 导入外部模块
+import UIKit
+
+//
+// MARK: 基础
//
+// XCODE 支持给注释代码作标记,这些标记会列在 XCODE 的跳转栏里,支持的标记为
+// MARK: 普通标记
+// TODO: TODO 标记
+// FIXME: FIXME 标记
+
println("Hello, world")
+
+// 变量 (var) 的值设置后可以随意改变
+// 常量 (let) 的值设置后不能改变
var myVariable = 42
+let øπΩ = "value" // 可以支持 unicode 变量名
+let π = 3.1415926
let myConstant = 3.1415926
-let explicitDouble: Double = 70
-let label = "some text " + String(myVariable) // Casting
-let piText = "Pi = \(myConstant)" // String interpolation
-var optionalString: String? = "optional" // Can be nil
-optionalString = nil
+let explicitDouble: Double = 70 // 明确指定变量类型为 Double ,否则编译器将自动推断变量类型
+let weak = "keyword"; let override = "another keyword" // 语句之间可以用分号隔开,语句未尾不需要分号
+let intValue = 0007 // 7
+let largeIntValue = 77_000 // 77000
+let label = "some text " + String(myVariable) // 类型转换
+let piText = "Pi = \(π), Pi 2 = \(π * 2)" // 格式化字符串
+
+// 条件编译
+// 使用 -D 定义编译开关
+#if false
+ println("Not printed")
+ let buildValue = 3
+#else
+ let buildValue = 7
+#endif
+println("Build value: \(buildValue)") // Build value: 7
+
+/*
+ Optionals 是 Swift 的新特性,它允许你存储两种状态的值给 Optional 变量:有效值或 None
+
+ Swift 要求所有的 Optinal 属性都必须有明确的值,如果为空,则必须明确设定为 nil
+
+ Optional<T> 是个枚举类型
+*/
+var someOptionalString: String? = "optional" // 可以是 nil
+// 下面的语句和上面完全等价,上面的写法更推荐,因为它更简洁,问号 (?) 是 Swift 提供的语法糖
+var someOptionalString2: Optional<String> = "optional"
+
+if someOptionalString != nil {
+ // 变量不为空
+ if someOptionalString!.hasPrefix("opt") {
+ println("has the prefix")
+ }
+
+ let empty = someOptionalString?.isEmpty
+}
+someOptionalString = nil
+
+// 显式解包 optional 变量
+var unwrappedString: String! = "Value is expected."
+// 下面语句和上面完全等价,感叹号 (!) 是个后缀运算符,这也是个语法糖
+var unwrappedString2: ImplicitlyUnwrappedOptional<String> = "Value is expected."
+
+if let someOptionalStringConstant = someOptionalString {
+ // 由于变量 someOptinalString 有值,不为空,所以 if 条件为真
+ if !someOptionalStringConstant.hasPrefix("ok") {
+ // does not have the prefix
+ }
+}
+
+// Swift 支持可保存任何数据类型的变量
+// AnyObject == id
+// 和 Objective-C `id` 不一样, AnyObject 可以保存任何类型的值 (Class, Int, struct, 等)
+var anyObjectVar: AnyObject = 7
+anyObjectVar = "Changed value to a string, not good practice, but possible."
+
+/*
+ 这里是注释
+
+ /*
+ 支持嵌套的注释
+ */
+*/
//
-// 数组与字典(关联数组)
+// Mark: 数组与字典(关联数组)
//
-// 数组
+/*
+ Array 和 Dictionary 是结构体,不是类,他们作为函数参数时,是用值传递而不是指针传递。
+ 可以用 `var` 和 `let` 来定义变量和常量。
+*/
+
+// Array
var shoppingList = ["catfish", "water", "lemons"]
shoppingList[1] = "bottle of water"
-let emptyArray = String[]()
+let emptyArray = [String]() // 使用 let 定义常量,此时 emptyArray 数组不能添加或删除内容
+let emptyArray2 = Array<String>() // 与上一语句等价,上一语句更常用
+var emptyMutableArray = [String]() // 使用 var 定义变量,可以向 emptyMutableArray 添加数组元素
// 字典
var occupations = [
- "Malcolm": "Captain",
- "kaylee": "Mechanic"
+ "Malcolm": "Captain",
+ "kaylee": "Mechanic"
]
-occupations["Jayne"] = "Public Relations"
-let emptyDictionary = Dictionary<String, Float>()
+occupations["Jayne"] = "Public Relations" // 修改字典,如果 key 不存在,自动添加一个字典元素
+let emptyDictionary = [String: Float]() // 使用 let 定义字典常量,字典常量不能修改里面的值
+let emptyDictionary2 = Dictionary<String, Float>() // 与上一语句类型等价,上一语句更常用
+var emptyMutableDictionary = [String: Float]() // 使用 var 定义字典变量
//
-// 控制流
+// MARK: 控制流
//
-// 用于数组的for 循环
+// 数组的 for 循环
let myArray = [1, 1, 2, 3, 5]
for value in myArray {
- if value == 1 {
- println("One!")
- } else {
- println("Not one!")
- }
+ if value == 1 {
+ println("One!")
+ } else {
+ println("Not one!")
+ }
}
-// 用于字典的for 循环
+// 字典的 for 循环
+var dict = ["one": 1, "two": 2]
for (key, value) in dict {
- println("\(key): \(value)")
+ println("\(key): \(value)")
}
-// 用于区间的for 循环
-for i in -1...1 { // [-1, 0, 1]
- println(i)
+// 区间的 loop 循环:其中 `...` 表示闭环区间,即[-1, 3];`..<` 表示半开闭区间,即[-1,3)
+for i in -1...shoppingList.count {
+ println(i)
}
-// 使用 .. 表示的区间不包含最后一个元素 [-1,0,1)
+shoppingList[1...2] = ["steak", "peacons"]
+// 可以使用 `..<` 来去掉最后一个元素
// while 循环
var i = 1
while i < 1000 {
- i *= 2
+ i *= 2
}
// do-while 循环
do {
- println("hello")
+ println("hello")
} while 1 == 2
-// Switch
+// Switch 语句
+// Swift 里的 Switch 语句功能异常强大,结合枚举类型,可以实现非常简洁的代码,可以把 switch 语句想象成 `if` 的语法糖
+// 它支持字符串,类实例或原生数据类型 (Int, Double, etc)
let vegetable = "red pepper"
switch vegetable {
case "celery":
- let vegetableComment = "Add some raisins and make ants on a log."
+ let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
- let vegetableComment = "That would make a good tea sandwich."
-case let x where x.hasSuffix("pepper"):
- let vegetableComment = "Is it a spicy \(x)?"
-default: // 必须 (为了覆盖所有可能的输入)
- let vegetableComment = "Everything tastes good in soup."
+ let vegetableComment = "That would make a good tea sandwich."
+case let localScopeValue where localScopeValue.hasSuffix("pepper"):
+ let vegetableComment = "Is it a spicy \(localScopeValue)?"
+default: // 在 Swift 里,switch 语句的 case 必须处理所有可能的情况,如果 case 无法全部处理,则必须包含 default语句
+ let vegetableComment = "Everything tastes good in soup."
}
//
-// 函数
+// MARK: 函数
//
-// 函数是一等类型,这意味着可以在函数中构建函数
-// 并且可以被传递
+// 函数是一个 first-class 类型,他们可以嵌套,可以作为函数参数传递
-// 函数
+// 函数文档可使用 reStructedText 格式直接写在函数的头部
+/**
+ A greet operation
+
+ - A bullet in docs
+ - Another bullet in the docs
+
+ :param: name A name
+ :param: day A day
+ :returns: A string containing the name and day value.
+*/
func greet(name: String, day: String) -> String {
- return "Hello \(name), today is \(day)."
+ return "Hello \(name), today is \(day)."
}
greet("Bob", "Tuesday")
-// 使用多元数组返回多返回值的函数
-func getGasPrices() -> (Double, Double, Double) {
- return (3.59, 3.69, 3.79)
+// 函数参数前带 `#` 表示外部参数名和内部参数名使用同一个名称。
+// 第二个参数表示外部参数名使用 `externalParamName` ,内部参数名使用 `localParamName`
+func greet2(#requiredName: String, externalParamName localParamName: String) -> String {
+ return "Hello \(requiredName), the day is \(localParamName)"
}
+greet2(requiredName:"John", externalParamName: "Sunday") // 调用时,使用命名参数来指定参数的值
-// 不定参数
-func setup(numbers: Int...) {}
+// 函数可以通过元组 (tuple) 返回多个值
+func getGasPrices() -> (Double, Double, Double) {
+ return (3.59, 3.69, 3.79)
+}
+let pricesTuple = getGasPrices()
+let price = pricesTuple.2 // 3.79
+// 通过下划线 (_) 来忽略不关心的值
+let (_, price1, _) = pricesTuple // price1 == 3.69
+println(price1 == pricesTuple.1) // true
+println("Gas price: \(price)")
+
+// 可变参数
+func setup(numbers: Int...) {
+ // 可变参数是个数组
+ let number = numbers[0]
+ let argCount = numbers.count
+}
-// 传递、返回函数
+// 函数变量以及函数作为返回值返回
func makeIncrementer() -> (Int -> Int) {
- func addOne(number: Int) -> Int {
- return 1 + number
- }
- return addOne
+ func addOne(number: Int) -> Int {
+ return 1 + number
+ }
+ return addOne
}
var increment = makeIncrementer()
increment(7)
+// 强制进行指针传递 (引用传递),使用 `inout` 关键字修饰函数参数
+func swapTwoInts(inout a: Int, inout b: Int) {
+ let tempA = a
+ a = b
+ b = tempA
+}
+var someIntA = 7
+var someIntB = 3
+swapTwoInts(&someIntA, &someIntB)
+println(someIntB) // 7
+
//
-// 闭包
+// MARK: 闭包
//
+var numbers = [1, 2, 6]
-// 函数是特殊的闭包({})
+// 函数是闭包的一个特例
-// 闭包示例.
-// `->` 分隔参数和返回类型
-// `in` 分隔闭包头和闭包体
+// 闭包实例
+// `->` 分隔了闭包的参数和返回值
+// `in` 分隔了闭包头 (包括参数及返回值) 和闭包体
+// 下面例子中,`map` 的参数是一个函数类型,它的功能是把数组里的元素作为参数,逐个调用 `map` 参数传递进来的函数。
numbers.map({
- (number: Int) -> Int in
- let result = 3 * number
- return result
- })
+ (number: Int) -> Int in
+ let result = 3 * number
+ return result
+})
-// 当类型已知时,可以这样做:
-var numbers = [1, 2, 6]
+// 当闭包的参数类型和返回值都是己知的情况下,且只有一个语句作为其返回值时,我们可以简化闭包的写法
numbers = numbers.map({ number in 3 * number })
+// 我们也可以使用 $0, $1 来指代第 1 个,第 2 个参数,上面的语句最终可简写为如下形式
+// numbers = numbers.map({ $0 * 3 })
+
+print(numbers) // [3, 6, 18]
+
+// 简洁的闭包
+numbers = sorted(numbers) { $0 > $1 }
+// 函数的最后一个参数可以放在括号之外,上面的语句是这个语句的简写形式
+// numbers = sorted(numbers, { $0 > $1 })
+
+print(numbers) // [18, 6, 3]
+
+// 超级简洁的闭包,因为 `<` 是个操作符函数
+numbers = sorted(numbers, < )
+
print(numbers) // [3, 6, 18]
//
-// 类
+// MARK: 结构体
//
-// 类的全部方法和属性都是public 的
-// 如果你在一个数据结构中只需储存数据,
-// 应使用 `struct`
+// 结构体和类非常类似,可以有属性和方法
-// 集成自`Shape` 类的简单的类`Square
-class Rect: Shape {
- var sideLength: Int = 1
-
- // Custom getter and setter property
- var perimeter: Int {
- get {
- return 4 * sideLength
- }
- set {
- sideLength = newValue / 4
+struct NamesTable {
+ let names = [String]()
+
+ // 自定义下标运算符
+ subscript(index: Int) -> String {
+ return names[index]
}
- }
+}
+
+// 结构体有一个自动生成的隐含的命名构造函数
+let namesTable = NamesTable(names: ["Me", "Them"])
+let name = namesTable[1]
+println("Name is \(name)") // Name is Them
+
+//
+// MARK: 类
+//
- init(sideLength: Int) {
- super.init()
- self.sideLength = sideLength
- }
+// 类和结构体的有三个访问控制级别,他们分别是 internal (默认), public, private
+// internal: 模块内部可以访问
+// public: 其他模块可以访问
+// private: 只有定义这个类或结构体的源文件才能访问
- func shrink() {
- if sideLength > 0 {
- --sideLength
+public class Shape {
+ public func getArea() -> Int {
+ return 0;
+ }
+}
+
+// 类的所有方法和属性都是 public 的
+// 如果你只是需要把数据保存在一个结构化的实例里面,应该用结构体
+
+internal class Rect: Shape {
+ // 值属性 (Stored properties)
+ var sideLength: Int = 1
+
+ // 计算属性 (Computed properties)
+ private var perimeter: Int {
+ get {
+ return 4 * sideLength
+ }
+ set {
+ // `newValue` 是个隐含的变量,它表示将要设置进来的新值
+ sideLength = newValue / 4
+ }
+ }
+
+ // 延时加载的属性,只有这个属性第一次被引用时才进行初始化,而不是定义时就初始化
+ // subShape 值为 nil ,直到 subShape 第一次被引用时才初始化为一个 Rect 实例
+ lazy var subShape = Rect(sideLength: 4)
+
+ // 监控属性值的变化。
+ // 当我们需要在属性值改变时做一些事情,可以使用 `willSet` 和 `didSet` 来设置监控函数
+ // `willSet`: 值改变之前被调用
+ // `didSet`: 值改变之后被调用
+ var identifier: String = "defaultID" {
+ // `willSet` 的参数是即将设置的新值,参数名可以指定,如果没有指定,就是 `newValue`
+ willSet(someIdentifier) {
+ println(someIdentifier)
+ }
+ // `didSet` 的参数是已经被覆盖掉的旧的值,参数名也可以指定,如果没有指定,就是 `oldValue`
+ didSet {
+ println(oldValue)
+ }
+ }
+
+ // 命名构造函数 (designated inits),它必须初始化所有的成员变量,
+ // 然后调用父类的命名构造函数继续初始化父类的所有变量。
+ init(sideLength: Int) {
+ self.sideLength = sideLength
+ // 必须显式地在构造函数最后调用父类的构造函数 super.init
+ super.init()
+ }
+
+ func shrink() {
+ if sideLength > 0 {
+ --sideLength
+ }
}
- }
+
+ // 函数重载使用 override 关键字
+ override func getArea() -> Int {
+ return sideLength * sideLength
+ }
+}
- override func getArea() -> Int {
- return sideLength * sideLength
- }
+// 类 `Square` 从 `Rect` 继承
+class Square: Rect {
+ // 便捷构造函数 (convenience inits) 是调用自己的命名构造函数 (designated inits) 的构造函数
+ // Square 自动继承了父类的命名构造函数
+ convenience init() {
+ self.init(sideLength: 5)
+ }
+ // 关于构造函数的继承,有以下几个规则:
+ // 1. 如果你没有实现任何命名构造函数,那么你就继承了父类的所有命名构造函数
+ // 2. 如果你重载了父类的所有命名构造函数,那么你就自动继承了所有的父类快捷构造函数
+ // 3. 如果你没有实现任何构造函数,那么你继承了父类的所有构造函数,包括命名构造函数和便捷构造函数
}
-var mySquare = new Square(sideLength: 5)
-print(mySquare.getArea()) // 25
+
+var mySquare = Square()
+println(mySquare.getArea()) // 25
mySquare.shrink()
-print(mySquare.sideLength) // 4
+println(mySquare.sideLength) // 4
+
+// 类型转换
+let aShape = mySquare as Shape
+
+// 使用三个等号来比较是不是同一个实例
+if mySquare === aShape {
+ println("Yep, it's mySquare")
+}
+
+class Circle: Shape {
+ var radius: Int
+ override func getArea() -> Int {
+ return 3 * radius * radius
+ }
+
+ // optional 构造函数,可能会返回 nil
+ init?(radius: Int) {
+ self.radius = radius
+ super.init()
+
+ if radius <= 0 {
+ return nil
+ }
+ }
+}
-// 如果你不需要自定义getter 和setter,
-// 但仍希望在获取或设置一个属性之前或之后运行
-// 一些代码,你可以使用`willSet` 和 `didSet`
+// 根据 Swift 类型推断,myCircle 是 Optional<Circle> 类型的变量
+var myCircle = Circle(radius: 1)
+println(myCircle?.getArea()) // Optional(3)
+println(myCircle!.getArea()) // 3
+var myEmptyCircle = Circle(radius: -1)
+println(myEmptyCircle?.getArea()) // "nil"
+if let circle = myEmptyCircle {
+ // 此语句不会输出,因为 myEmptyCircle 变量值为 nil
+ println("circle is not nil")
+}
//
-// 枚举类型
+// MARK: 枚举
//
-// 枚举类型可以是某种指定的类型,抑或自成一种类型
-// 像类一样,枚举类型可以包含方法
+// 枚举可以像类一样,拥有方法
enum Suit {
- case Spades, Hearts, Diamonds, Clubs
- func getIcon() -> String {
- switch self {
- case .Spades: return "♤"
- case .Hearts: return "♡"
- case .Diamonds: return "♢"
- case .Clubs: return "♧"
+ case Spades, Hearts, Diamonds, Clubs
+ func getIcon() -> String {
+ switch self {
+ case .Spades: return "♤"
+ case .Hearts: return "♡"
+ case .Diamonds: return "♢"
+ case .Clubs: return "♧"
+ }
}
- }
}
+// 当变量类型明确指定为某个枚举类型时,赋值时可以省略枚举类型
+var suitValue: Suit = .Hearts
+
+// 非整型的枚举类型需要在定义时赋值
+enum BookName: String {
+ case John = "John"
+ case Luke = "Luke"
+}
+println("Name: \(BookName.John.rawValue)")
+
+// 与特定数据类型关联的枚举
+enum Furniture {
+ // 和 Int 型数据关联的枚举记录
+ case Desk(height: Int)
+ // 和 String, Int 关联的枚举记录
+ case Chair(brand: String, height: Int)
+
+ func description() -> String {
+ switch self {
+ case .Desk(let height):
+ return "Desk with \(height) cm"
+ case .Chair(let brand, let height):
+ return "Chair of \(brand) with \(height) cm"
+ }
+ }
+}
+
+var desk: Furniture = .Desk(height: 80)
+println(desk.description()) // "Desk with 80 cm"
+var chair = Furniture.Chair(brand: "Foo", height: 40)
+println(chair.description()) // "Chair of Foo with 40 cm"
+
//
-// 其它
+// MARK: 协议
+// 与 Java 的 interface 类似
//
-// `协议(protocol)`: 与Java 的接口(Interface) 类似.
-// `扩展(extension)`: 为现有类型添加额外特性
-// 泛型: 与Java 相似。使用`where` 关键字指定
-// 泛型的要求.
+// 协议可以让遵循同一协议的类型实例拥有相同的属性,方法,类方法,操作符或下标运算符等
+// 下面代码定义一个协议,这个协议包含一个名为 enabled 的计算属性且包含 buildShape 方法
+protocol ShapeGenerator {
+ var enabled: Bool { get set }
+ func buildShape() -> Shape
+}
+
+// 协议声明时可以添加 @objc 前缀,添加 @objc 前缀后,
+// 可以使用 is, as, as? 等来检查协议兼容性
+// 需要注意,添加 @objc 前缀后,协议就只能被类来实现,
+// 结构体和枚举不能实现加了 @objc 的前缀
+// 只有添加了 @objc 前缀的协议才能声明 optional 方法
+// 一个类实现一个带 optional 方法的协议时,可以实现或不实现这个方法
+// optional 方法可以使用 optional 规则来调用
+@objc protocol TransformShape {
+ optional func reshaped()
+ optional func canReshape() -> Bool
+}
+
+class MyShape: Rect {
+ var delegate: TransformShape?
+
+ func grow() {
+ sideLength += 2
+
+ // 在 optional 属性,方法或下标运算符后面加一个问号,可以优雅地忽略 nil 值,返回 nil。
+ // 这样就不会引起运行时错误 (runtime error)
+ if let allow = self.delegate?.canReshape?() {
+ // 注意语句中的问号
+ self.delegate?.reshaped?()
+ }
+ }
+}
+
+
+//
+// MARK: 其它
+//
+
+// 扩展: 给一个已经存在的数据类型添加功能
+
+// 给 Square 类添加 `Printable` 协议的实现,现在其支持 `Printable` 协议
+extension Square: Printable {
+ var description: String {
+ return "Area: \(self.getArea()) - ID: \(self.identifier)"
+ }
+}
+
+println("Square: \(mySquare)") // Area: 16 - ID: defaultID
+
+// 也可以给系统内置类型添加功能支持
+extension Int {
+ var customProperty: String {
+ return "This is \(self)"
+ }
+
+ func multiplyBy(num: Int) -> Int {
+ return num * self
+ }
+}
+
+println(7.customProperty) // "This is 7"
+println(14.multiplyBy(3)) // 42
+
+// 泛型: 和 Java 及 C# 的泛型类似,使用 `where` 关键字来限制类型。
+// 如果只有一个类型限制,可以省略 `where` 关键字
+func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? {
+ for (index, value) in enumerate(array) {
+ if value == valueToFind {
+ return index
+ }
+ }
+ return nil
+}
+let foundAtIndex = findIndex([1, 2, 3, 4], 3)
+println(foundAtIndex == 2) // true
+
+// 自定义运算符:
+// 自定义运算符可以以下面的字符打头:
+// / = - + * % < > ! & | ^ . ~
+// 甚至是 Unicode 的数学运算符等
+prefix operator !!! {}
+
+// 定义一个前缀运算符,使矩形的边长放大三倍
+prefix func !!! (inout shape: Square) -> Square {
+ shape.sideLength *= 3
+ return shape
+}
+
+// 当前值
+println(mySquare.sideLength) // 4
+
+// 使用自定义的 !!! 运算符来把矩形边长放大三倍
+!!!mySquare
+println(mySquare.sideLength) // 12
```
+