TypeScrip入門之基礎篇

那么我們開始吧,

我們從基礎語言類型開始

JavaScript 的類型分為兩種:原始數據類型(Primitive data types)和對象類型(Object types)

原始數據類型包括:布爾值、數值、字符串、null、undefined以及 ES6 中的新類型 Symbol。

本節主要介紹前五種原始數據類型在 TypeScript 中的應用。

原始數據類型

布爾值

TypeScript是用:來進行類型申請的。

let isDone: boolean = false;
// 編譯通過
// 后面約定,未強調編譯錯誤的代碼片段,默認為編譯通過

注意,使用構造函數 Boolean 創造的對象不是布爾值:

let createdByNewBoolean: boolean = new Boolean(1);

// index.ts(1,5): error TS2322: Type 'Boolean' is not assignable to type 'boolean'.
// 后面約定,注釋中標出了編譯報錯的代碼片段,表示編譯未通過

事實上 new Boolean() 返回的是一個Boolean對象:

let createdByNewBoolean: Boolean = new Boolean(1);

直接調用 Boolean也可以返回一個 boolean 類型:

let createdByBoolean: boolean = Boolean(1);

在 TypeScript 中,boolean 是 JavaScript 中的基本類型,而 Boolean 是 JavaScript 中的構造函數。其他基本類型(除了 null 和 undefined)一樣,不再贅述。

下面的類型類似:

數值

let age: number = 23;

字符串

let myName:string = 'Tom';

編譯結果為;

var isDone = false;
var age = 23;
var myName = 'Tom';

空值

JavaScript 沒有空值(Void)的概念,在 TypeScript 中,可以用 void 表示沒有任何返回值的函數:

function alertName(): void {
    alert("my name is Tom")
};

聲明一個 void 類型的變量沒有什么用,因為你只能將它賦值為 undefinednull

let unusable: void = undefined;

Null和Undefined

這兩個原始數據類型比較有意思,他們的類型變量只能賦值為他們本身,undefinedundefined,null只能為null.

let u: undefined = undefined;
let n: null = null;

不過,它和void的區別是,他們兩個是所有類型的子類型。也就是說undefinednull類型的變量,可以賦值給number類型變量:

// 這樣不會報錯
let num: number = undefined;
// 這樣也不會報錯
let u: undefined;
let num: number = u;

void 類型的變量不能賦值給 number 類型的變量:

任意值

任意值(Any)用來表示允許賦值為任意類型

那么什么是任意值類型呢?

如果是一個普通類型,在賦值過程中改變類型是不被允許的:

let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;

編譯報錯:

hello.ts:25:1 - error TS2322: Type '7' is not assignable to type 'string'.

25 myFavoriteNumber = 7;
   ~~~~~~~~~~~~~~~~

但是any類型可以,允許被賦值為任意類型。

let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 7;

任意值的屬性和方法

在任意值上訪問任何屬性都是允許的:

let anyThing: any = 'hello';
console.log(anyThing.myName);
console.log(anyThing.myName.firstName);

也允許調用任何方法:

let anyThing: any = 'Tom';
anyThing.setName('Jerry');
anyThing.setName('Jerry').sayHello();
anyThing.myName.setFirstName('Cat');

可以這樣認為,聲明一個變量為任意值后,對它的任何操作,返回的內容的類型都是任意值。

未聲明類型的變量

如果變量在聲明的時候沒有指定類型,那么它的默認類型為任意值類型:

let something;
something = 'seven';
something = 7;
something.setName('Tom');

相當于

let something: any;
something = 'seven';
something = 7;
something.setName('Tom');

類型推論

如果沒有明確的指定類型,那么TypeScript會依照類型推論Type Inference 的規則推斷出一個類型。

什么是類型推論呢?

例如:

let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.

它就相當于:


let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;
// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.

報的錯誤都一樣,就是說,在你聲明變量的時候,如果你沒有設置類型,但是你給它指定了具體的值,那么它就會推斷它的類型為你制定值的類型。

同理,如果你在聲明變量的時候沒有指定值,那么它就推斷它的類型為any任意值類型。

let myFavoriteNumber;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

聯合類型

聯合類型(Union Types)表示取值可以為多種類型中的一種。

let myFavoriteNumber: string | number = 'seven';
myFavoriteNumber = 7;

同樣是上面的代碼,你設置了字符串和數字,那么它就可以設置這兩種。

let myFavoriteNumber: string | number ;
myFavoriteNumber = false;
// index.ts(2,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.
//   Type 'boolean' is not assignable to type 'number'.

聯合類型是用豎線 |來分割每個類型。

這里的含義是,你可以是字符串或者數字,但是不可以是其他的類型。

訪問聯合類型的屬性或方法

TypeScript不確定一個聯合類型的變量到底是哪個類型的時候,我們只能訪問此聯合類型的所有類型里共有的屬性或方法:

function getLength(something: string | number): number {
    return something.length;
}

hello.ts:39:22 - error TS2339: Property 'length' does not exist on type 'string 

上例中,length不是stringnumber的共有屬性,所以會報錯。

訪問stringnumber的共有屬性是沒有問題的:

function getString(something: string | number): string {
    return something.toString();
}

聯合類型的變量在賦值的時候,會根據類型推論的規則推斷出一個類型:

let myFavoriteNumber: string|number;
myFavoriteNumber = 'seven';
console.log(myFavoriteNumber.length);

myFavoriteNumber = 7;
console.log(myFavoriteNumber.lenght);
// index.ts(5,30): error TS2339: Property 'length' does not exist on type 'number'.

上面的第二行,類型推斷字符串,所以length不報錯,
而第四行,類型推斷為數字,所以length為不報錯。

對象的類型——接口

這個在java語言中非常重要的概念,有一個說法是面向接口編程。在TypeScript中,我們使用接口interface來定義對象的類型。

什么是接口

在面向對象語言中,它是對行為的抽象,而具體如何行動需要由類classes去實現implements.

TypeScript中的接口是一個非常靈活的概念,除了可用于一部分行為進行抽象外,也常用于對象的形狀Shape進行概括。

例如:

interface Person {
    name:string;
    age:number;
}

let tom:Person = {
    name:"Tom",
    age:23
};

這個有點想抽象類,我們看到上面代碼中,我們創建了一個對象tom,然后把它的類型設置為接口Person。這樣的話,我們就約束了tom的形狀必須和接口Person一直。接口一般首字母大寫。有的編程語言中會建議接口的名稱加上I為前綴。

因為你設定了對象的類型是接口Person,所以必須完全一致,少一些屬性和多一些屬性,通通不允許:

interface Person {
    name:string;
    age:number;
}

let tom:Person = {
    name:"Tom",
};

//hello.ts:59:5 - error TS2322: Type '{ name: string; }' is //not assignable to type 'Person'.
//  Property 'age' is missing in type '{ name: string; }'.

interface Person {
    name:string;
    age:number;
}

let tom:Person = {
    name:"Tom",
    age:23,
    gender:'male'
};

//hello.ts:62:5 - error TS2322: Type '{ name: string; age: //number; gender: string; }' is not assignable to type //'Person'.
//  Object literal may only specify known properties, and //'gender' does not exist in type 'Person'.

所以,賦值的時候,變量的形狀必須和接口的形狀保持一致。

可是我不想保持一致怎么辦呢?可選屬性出場

可選屬性

可選屬性是通過變量后面加一個?問號來實現的,它的意思是你可以選擇這個屬性不存在。但是不可以添加未定義的屬性。

interface Person {
    name:string;
    age?:number;
}

let tom:Person = {
    name:"Tom",
};

可選屬性,你可以存在或者不存在

interface Person {
    name:string;
    age?:number;
}

let tom:Person = {
    name:"Tom",
    age:23,
    gender:'male'
};

//hello.ts:62:5 - error TS2322: Type '{ name: string; age: //number; gender: string; }' is not assignable to type //'Person'.
//  Object literal may only specify known properties, and //'gender' does not exist in type 'Person'.

不可以添加不存在的屬性。

對象的類型 接口的意義就是為了約束對象的創建。

任意類型

有時候我們希望一個借口允許有任意的屬性,可以使用下面的方式:


interface Person {
    name:string;
    age?:number;
    [propName: string]:any;
}

let tom:Person = {
    name:"Tom",
    age:23,
    gender:'male'
};

我們通過[propName: string]定義了任意屬性取string的值,而我們需要注意的是,一旦定義了任意屬性,那么確定屬性和可選屬性都必須是它的子屬性。


interface Person {
    name:string;
    age?:number;
    [propName: string]:string;
}

let tom:Person = {
    name:"Tom",
    age:23,
    gender:'male'
};

我們把上面的any改為string,那么不確定屬性agenumber,不屬于string,就報錯了。
編譯的結果:

hello.ts:56:5 - error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.

56     age?:number;
       ~~~

hello.ts:60:5 - error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
Property 'age' is incompatible with index signature.
Type 'number' is not assignable to type 'string'.

60 let tom:Person = {

只讀屬性

我們還可以設置只讀類型,只有在創建的時候賦值,其他的時候不可以賦值,那么就可以使用readonly定義只讀屬性了。

interface Person {
    readonly id:number;
    name:string;
    age?:number;
    [propName: string]:any;
}

let tom:Person = {
    id:12345,
    name:"Tom",
    age:23,
    gender:'male'
};

tom.id = 2222;

//hello.ts:68:5 - error TS2540: Cannot assign to 'id' because //it is a constant or a read-only property.

//68 tom.id = 2222;

類似于上面的代碼,我們把readonly放在屬性名稱的前面,在上面的tom對象中,我們創建的時候就已經直接賦值了,所以在后面再次賦值的時候,就報錯。

注意:只讀的約束存在于第一次給對象賦值的時候,而不是第一次給只讀屬性賦值的時候。

interface Person {
    readonly id:number;
    name:string;
    age?:number;
    [propName: string]:any;
}

let tom:Person = {
    
    name:"Tom",
    age:23,
    gender:'male'
};

tom.id = 2222;

hello.ts:61:5 - error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
  Property 'id' is missing in type '{ name: string; age: number; gender: string; }'.

61 let tom:Person = {
       ~~~

hello.ts:68:5 - error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.

68 tom.id = 2222;

上面報錯有兩次,一是在創建對象的時候,沒有給只讀屬性id賦值,二是它是只讀屬性,不可以在此賦值。

關于接口行為的約束,我們在后面會有詳細的章節。

數組的類型

TypeScript中,數組類型有多重定義方式,比較靈活。

「類型 + 方括號」表示法

java的類似

let array:number[] = [1,2,3,4,5,6];
let sty_arr:string[] = ['1','2'];

數組中不可以出現其他的數據類型:

let array:number[] = [1,2,3,4,5,6,"1"];

hello.ts:70:35 - error TS2322: Type 'string' is not assignable to type 'number'.

70 let array:number[] = [1,2,3,4,5,6,"1"];

我們試一下是否可以聲明聯合類型的數組,既包含字符串又包含數字

let com_arr: string | number [] = ["1",1];

hello.ts:73:5 - error TS2322: Type '(string | number)[]' is not assignable to type 'string | number[]'.
  Type '(string | number)[]' is not assignable to type 'number[]'.
    Type 'string | number' is not assignable to type 'number'.
      Type 'string' is not assignable to type 'number'.

73 let com_arr: string | number [] = ["1",1];

看上面錯誤,這樣聲明的數組是不行的。需要改成下面這樣。

let com_arr: (string | number) [] = ["1",1];

果然可以。666,不過我們還是不要這樣用了,你用TypeScript就是為了約束,你這樣玩還不如直接寫:

let com_arr = ["1", 1];

數組的泛型

我們也可以用數組的泛型來展示數組。Array<elemType>

let array: Array<number> = [1,2,3,4,5];
let array1: Array<string> = ["1","2"];
let array3: Array<string|number> = ["1","2",1];
let array4:Array<any> = [1,"2",{"a":1}];

同樣我們可以用any來定義數組。

關于泛型,可以參考泛型一章.

用接口表示數組

interface NumberArray {
    [index:number]:number;
}

// let array:NumberArray = [1,2,3,4];
let array :NumberArray = ["a"];

hello.ts:86:27 - error TS2322: Type 'string' is not assignable to type 'number'.

86 let array :NumberArray = ["a"];

  hello.ts:82:5
    82     [index:number]:number;
           ~~~~~~~~~~~~~~~~~~~~~~
    The expected type comes from this index signature.

NumberArray表示:只要index的類型是number,那么值必須是number

如果我們設置的數組是字符串的話,那么它會報錯。

類數組

類數組不是數組類型,比如內置對象arguments:

function sum() {
    let args:number [] = arguments;
}

hello.ts:89:9 - error TS2322: Type 'IArguments' is not assignable to type 'number[]'.
  Property 'pop' is missing in type 'IArguments'.

89     let args:number [] = arguments;

我們可以看到上面的錯誤說的是IArguments類型無法匹配為nujber []類型。所以我們可以這樣寫:

function sum() {
    let args:IArguments = arguments;
}

沒有報錯,妥妥的。

函數的類型

大家要記得,函數是JavaScript的一等公民

函數聲明

JavaScript中,有兩種常見的定義函數的方式--函數聲明和函數表達式:

//函數聲明 (Function Declaration)
function sum(x,y){
    return x+y;
}

//函數表達式 (Function Expression)
let mySum = function(x,y){
    return x + y;
}

一個函數有輸入和輸出,要在 TypeScript 中對其進行約束,需要把輸入和輸出都考慮到,其中函數聲明的類型定義較簡單:

function sum(x:number,y:number):number {
    return x + y;
}

注意:輸入多余的或者少輸入都會報錯。我就不在這里試了。

函數表達式

感覺這里是個坑。

聲明一個函數表達式,會寫成這樣:

let mySum = function (x: number, y: number):number {
    return x + y;
}

沒有報錯,可以編譯,實際上上面的代碼只對燈油右側的匿名函數進行了類型定義,而等號左邊的mySum,是對賦值操作進行類型推論出來的。如果我們需要手動為它添加類型,則應該寫成這樣。

let mySum:(x:number,y:number)=>number = function (x: number, y: number):number {
    return x + y;
}

這里不要把TypeScript=>ES6=>混淆了。

怎么可能不混淆嗎?

TypeScript的類型定義中,=>用來表示函數的定義,左邊是輸入的參數的類型,右邊是返回的類型。

ES6中,=>表示箭頭函數。不在介紹。

用接口定義函數的形狀

那么我們現在用接口來定義個函數所需要的形狀:

interface SearchFunc {
    (source:string,subString:string):boolean;
}

let mySearch:SearchFunc = function (source:string,subString:string) {
    return source.search(subString) !== -1; 
}

我們用接口定義了函數的形狀,左邊是輸入的類型,右邊是輸出的類型。

可選參數

前面我們說道輸入多余或者少輸入都會報錯,那么如何定義和選擇的參數呢?與接口中的可選屬性類型,我們用?表示可選的參數:

function buildName(firstName: string, lastName?: string) {
    if (lastName) {
        return firstName + ' ' + lastName;
    } else {
        return firstName;
    }
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');

需要注意的是,可選參數必須接在必需參數后面。換句話說,可選參數后面不允許再出現必須參數了:

function buildName(firstName?: string, lastName: string) {
    if (firstName) {
        return firstName + ' ' + lastName;
    } else {
        return lastName;
    }
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName(undefined, 'Tom');

// index.ts(1,40): error TS1016: A required parameter cannot follow an optional parameter.

參數默認值

TypeScript中參數的默認值和ES6一樣的寫法,TypeScript會將添加了默認值的參數識別為可選參數:

function buildName(firstName:string,lastName:string = "Cat") {
    return firstName +" " +lastName;
}

let tomcat = buildName('Tom','Cat');
let tom = buildName('Tom');

此時就不受可選參數必須接在必須參數后面的限制了:

function buildName(firstName:string,lastName:string = "Cat") {
    return firstName +" " +lastName;
}

let tomcat = buildName('Tom','Cat');
let tom = buildName(undefined,'Tom');

剩余參數

ES6 中,可以使用 ...rest 的方式獲取函數中的剩余參數(rest 參數):

function push(array,...items) {
    items.forEach(function (item) {
        array.push(item);
    });
}

let a  = [];
push(a,2,3,4);

我們可以看到,實際上items是一個數組,所以我們可以用數組的方式來定義它。

function push(array:any [],...items:any []) {
    items.forEach(function (item) {
        array.push(item);
    });
}

let a  = [];
push(a,2,3,4);

需要注意的是,rest參數只能是最后一個參數。

重載

重載允許一個函數接受不同數量或者不同類型的參數時,做出不同的處理。

比如我們實現下面的函數。利用聯合類型,我們可以這樣實現。

function reverse(x:number|string):number|string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

不過這樣有一個缺點,就是不能夠精確的表達,輸入為數字的時候,輸出也應該是數字,輸入字符串的時候,輸出也應該是字符串。

我們可以使用多個reverse的函數類型:

function reverse(x:number):number;
function reverse(x:string):string;
function reverse(x:number|string):number|string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

上例中,我們重復定義了多次函數reverse,幾次都是函數定義,最后一次是函數實現,在編輯的代碼提示中,可以正確的看到前兩個提示。

需要注意的是,TypeScript會優先從最前面的函數定義開始匹配,所以多個函數定義如果有包含關系,需要優先把精確的電影以寫在前面。

類型斷言

類型斷言(Type Assertion) 可以用來手動指定一個值的類型。但是它并不是類型轉換。

語法

<類型>值

值 as 類型

tsx語法中必須用后一種。

例如:將一個聯合類型的變量指定為更加具體的的類型。

之前提到過,當 TypeScript 不確定一個聯合類型的變量到底是哪個類型的時候,我們只能訪問此聯合類型的所有類型里共有的屬性或方法:

function getLength(something:string|number):number {
    return something.length;
}
hello.ts:154:22 - error TS2339: Property 'length' does not exist on type 'string | number'.
  Property 'length' does not exist on type 'number'.

154     return something.length;

我們有時候需要在還不確定類型的時候就訪問其中的一個類型的屬性或方法,比如:

function getLength(something:string|number):number {
   if(something.length){
       return something.length;
   }else{
       return something.toString.length;
   }
}
hello.ts:154:17 - error TS2339: Property 'length' does not exist on type 'string | number'.
  Property 'length' does not exist on type 'number'.

154    if(something.length){
                    ~~~~~~

hello.ts:155:25 - error TS2339: Property 'length' does not exist on type 'string | number'.
  Property 'length' does not exist on type 'number'.

155        return something.length;

可以看到上面的報錯,這個時候我們就可以使用類型斷言,將something斷言成string:

function getLength(something:string|number):number {
   if((<string>something).length){
       return (<string>something).length;
   }else{
       return something.toString.length;
   }
}

類型斷言的用法如上,在需要斷言的變量前加上<Type>就可以。

類型斷言不是類型轉換,斷言成一個聯合類型中不存在的類型是不允許的。

function boBoolean(something:string|number):boolean {
    return <boolean>something;
}

hello.ts:162:12 - error TS2352: Conversion of type 'string | number' to type 'boolean' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  Type 'number' is not comparable to type 'boolean'.

162     return <boolean>something;

類型斷言不是類型轉換,因為你不能把它強制轉換為不存在的類型。

聲明文件

聲明文件官方連接

內置對象

JavaScript 中有很多內置對象,它們可以直接在 TypeScript 中當做定義好了的類型。

內置對象是指根據標準在全局作用域(Global)上存在的對象。這里的標準是指 ECMAScript 和其他環境(比如 DOM)的標準。

ECMAScript 的內置對象

ECMAScript標準提供的內置對象有:
Boolean,String,Error,Date,RegExp
我們都可以在TypeScript中將變量定義為這些類型。

let b:Boolean = new Boolean(1);
let e:Error = new Error("error occurred");
let d:Date = new Date();
let r:RegExp = /[a-z]/;
let s:String = new String("a");
let n:Number = new Number(1);

更多的內置對象,可以查看MDN的文檔
而他們的定義文件,則在 TypeScript 核心庫的定義文件中。

DOM 和 BOM 的內置對象

DOM和BOM提供的內置對象:
Document、HTMLElement、Event、NodeList等。

TypeScript中經常用到這些類型:

let body:HTMLElement = document.body;
let allDiv:NodeList = document.querySelectorAll('div');
document.addEventListener('click',function (e:MouseEvent) {
    //DO something
})

它們同樣定義在 TypeScript 核心庫的定義文件中。

這里是我學習的網址教程

大家加油。。。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,695評論 2 370

推薦閱讀更多精彩內容

  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學習記錄文檔,今天18年5月份再次想寫文章,發現簡書還為我保存起的...
    Jenaral閱讀 2,802評論 2 9
  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執行單位為行(line),也就是一...
    悟名先生閱讀 4,182評論 0 13
  • 看到男神李健和嬌妻孟小蓓的生活片段,一下子陷入艷羨的情緒,能在煙火人間活出仙氣,享受二人的愜意時光,是一種怎...
    天明懶畫眉閱讀 433評論 0 2
  • 最近在讀杜子建的書,他在書中是這么說經歷和閱歷的。 經歷,是指你走過了多少路、遇到過多少事;閱歷,是指你觀察過多少...
    西蘭花開8528閱讀 237評論 0 1
  • 2018―10―09 姓名:葉彩霞 【日精進打卡第182天】2018.10.09 第367期(無錫市) 樂觀三組 ...
    透明的水泡閱讀 134評論 0 0