C#码农学TypeScript(3)—— 变量声明

不像C#这种强类型语言,JavaScript是一种弱类型语言,一个变量可以被赋值成各种类型的值。

我们在C#里声明一个string类型变量: string cSharpString = "a c# string"; 

在JavaScript里面直接用var,不指定类型,它自己通过值来推导类型: var javaScriptString = "a JavaScript string"; 

看了很多描述JavaScript var关键字的文章,大多都在说它有很多坑,因为它的作用于非常奇怪,所以有很多怪异行为,又要通过很多怪异的解决方案来避免这些怪异行为。

很庆幸现在可以直接使用let和const,不用被var折磨,致敬JavaScript大神们!

TypeScript是JavaScript的超集,所以它本身就支持let和const.

let :变量,值可变。

const :常量,对let的增强,阻止被再次赋值。

let声明

let hello = "Hello!";

 使用 let 声明一个变量,它使用得是块作用域。看了一下,发现就跟C#变量作用域一样。

  • 块作用域变量在包含他们的块或 for 循环之外不能访问。
  • 变量不能在声明前使用,就是使用变量的代码必须写在变量声明的后面。变量存在于它的作用域内里,作用域内、变量没声明之前的代码区域属于变量的暂时性死区,不能用它。
  • 同一作用域内,变量只能声明一次,与C#一样。
  • 嵌套作用域,内层作用域变量会屏蔽外层作用域同名变量,与C#一样。

const声明

const numLivesForCat = 9;

与 let 的唯一区别就是,被赋值后不能再改变。

所谓的不能改变,只是说引用的值不可变。

例如,const常量被赋值成一个对象,不可以给这个常量赋成新的对象,却可以改变原来对象的成员。

 1 const numLivesForCat = 9;
 2 const kitty = {
 3     name: "Aurora",
 4     numLives: numLivesForCat,
 5 }
 6 
 7 // Error
 8 kitty = {
 9     name: "Danielle",
10     numLives: numLivesForCat
11 };
12 
13 // all "okay"
14 kitty.name = "Rory";
15 kitty.name = "Kitty";
16 kitty.name = "Cat";
17 kitty.numLives--;

解构赋值

将部分值从数组中取出,或者部分属性从对象中取出,赋值给其他变量。这里简短概述。

解构数组

使用场景 应用举例
变量赋值

我们将数组的两个值取出来分别赋给两个变量。

 1 let input = [1, 2];
 2 
 3 // 旧写法,使用索引按个赋值
 4 let first = input[0];
 5 let second = input[1];
 6 
 7 // 使用数组解构赋值
 8 let [first, second] = input;
 9 
10 // 两种方式输出结果一样
11 console.log(first); // outputs 1
12 console.log(second); // outputs 2
变量值置换
// swap variables
[first, second] = [second, first];
函数参数
function f([first, second]: [number, number]) {
    console.log(first);
    console.log(second);
}
f(input);
使用展开运算符 ... 创建剩余变量

let [first, ...rest] = [1, 2, 3, 4];
console.log(first); // outputs 1
console.log(rest); // outputs [ 2, 3, 4 ]

忽略不关心的尾随元素
let [first] = [1, 2, 3, 4];
console.log(first); // outputs 1
忽略不关心的任意元素
let [, second, , fourth] = [1, 2, 3, 4];

 

对象解构

使用场景 应用举例
变量赋值

我们将对象的属性取出来分别赋值给两个变量

let o = {
    a: "foo",
    b: 12,
    c: "bar"
};

// 旧写法
let a = o.a;
let b = o.b;

// 用对象解构赋值,不用c就忽略它
let { a, b } = o;
 使用展开运算符 ...创建剩余变量  
let { a, ...passthrough } = o;
let total = passthrough.b + passthrough.c.length;
 解构赋值给与属性不同名变量  
let { a: newName1, b: newName2 } = o;

// 上面的写法等同于下面的旧写法
let newName1 = o.a;
let newName2 = o.b;

这里的语法开始变得混乱,冒号不是用来表示类型,而是指对象属性赋值给冒号后面的变量。

要想指定类型,需要在后面写上完整的模式:

let { a: newName1, b: newName2 }: { a: string, b:number} = o;
解构用于函数声明
function f({ a, b }: { a: string, b?: number } = { a: "", b: 0}): void {
    // ...
}
 解构赋值同时指定默认值

 默认值会在对应属性为undfined时被使用。

function keepWholeObject(wholeObject: { a: string, b?: number }) {
    let { a, b = 1001 } = wholeObject;
}

wholeObject.b为undefined时,b会被赋值成1001.

 

展开运算符

在函数调用、构造字面量数组时,将数组表达式或string在语法层面展开;

在构造字面量对象时,将对象表达式按key-value方式展开。

构造字面量数组,是指 let arr = ["hello", "world", "hahaha"]; 这种简洁的构造方式。

构造字面量对象,是指 let person = {name: "bala", age: 18}; 这种简洁的构造方式。

用展开运算符构造字面量数组:

let first = [1, 2];
let second = [3, 4];
let bothPlus = [0, ...first, ...second, 5];   // [0, 1, 2, 3, 4, 5]

展开操作创建了first和second的浅拷贝,它们本身不会被展开操作改变。

用展开运算符构造字面量对象:

let defaults = { food: "spicy", price: "$$", ambiance: "noisy" };
let search = { ...defaults, food: "rich" };  // { food: "rich", price: "$$", ambiance: "noisy" }

出现在后面的属性会覆盖前面的相同属性,这里后面的 food: "rich" 覆盖了前面的 food: "spicy" 。

另外,对象展开结果只会包含自己的可枚举属性,大体上是说展开对象实例会丢失其方法。

C#码农学TypeScript(3)—— 变量声明

上一篇:使用Gitblit 在Windows上部署Git Server


下一篇:.netcore 2.0 System.Drawing