变量声明

TypeScrpt中变量声明主要有三种方式:var,let和const。

var声明

讲讲var的特点

1.变量提升
2.可重复声明,后声明覆盖前声明
3.var的作用域,来看下面的例子:

function f(flag:boolean) {
 if(flag) {
 var x = 10;
 }
}
f(true); // returns "10"
f(false); // returns "undefined"

可以看到,我们将变量X定义在if语句内,但是却可以在if语句外面访问它。这是因为var声明可以在包含他的函数,模块命名空间或全局作用域内部的任何位置被访问。此为var作用域或函数作用域,函数参数也使用函数作用域。

let声明

let与var的写法一致

let hello = "Hello!";

主要区别在语义上。

块作用域

当用let声明一个变量,它使用的是词法作用域或块作用域。var声明的变量可以在包含他们的函数外访问,与var不同的是,块作用域变量在包含他们的块或for循环之外是不能访问的。
来看下面的例子:

function f(flag:boolean) {
 let a = 100;
 if(flag) {
 let b = a + 1;
 return b;
 }
 return b; // 报错
}

我们在函数内部用let定义了a,b两个变量。a的作用域是f函数体内,而b的作用域是if语句内,if语句内可以访问a,但是if语句外无法访问到b,因此在if语句外访问b会报错。

块级作用域的特点之一是没有变量提升,也就是不能在被声明之前读写,这也是与var不同的地方。

const声明

const也是声明变量的一种方式。

const Π = 3.14

const拥有与let相同的作用域规则,但是不能对他们重新赋值。

const age = 18;
const Tom = {
 name: "Tom",
 age: age 
};
//报错
Tom = {
 name: "Jerry",
 age: age
};
//ok
Tom.name = "tom";
Tom.age--;

通过以上例子不难看出,在给Tom重新赋值对象时报错,但是修改Tom的属性值时正常运行。这是因为const定义的变量的不能修改的含义是不能修改变量的引用。
如果const定义的变量为简单数据类型:字符串、数字等类型,不能修改;如果const定义的变量为复杂数据类型:对象、数组等,不能修改其引用,但可以修改其属性的值。

解构

解构赋值语法是一种 Javascript 表达式。可以将数组中的值或对象的属性取出,赋值给其他变量。

结构数组

let array = [1, 2];
let [first, second] = array;
console.log(first); // 1
console.log(second); // 2

这里通过解构创建了first和second两个变量。
作用域函数参数:

function f([first, second]: [number, nnumber]) {
 console.log(first);
 console.log(second);
}
 f([1,2])

也可以在数组里使用...展开操作符创建剩余变量:

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

也可以忽略不关心的尾随元素或其他元素:

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

解构对象

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

这里通过o.a和o.b创建了a和b,可以忽略不需要的属性,例如这里的c。
在前面我们讲到,可以对没有声明的数组解构,对象同样也可以。

({ a, b } = { a:"bar", b:10 });

这里要注意,在javascript中通常会以 { 起始的语句解析为一个块,因此我们在这里用括号将其括起来。
也可以用...展开操作符创建剩余变量:

let { a, ...restProperty } = o;
let rest = restProperty.b + restO=Property.c.length;

属性重命名

可以给属性以不同的名字:

let { a: newName1, b: newName2 } = o;

这里我们将a重命名为newName1,b重命名为newName2,可以将a作为newName1,b作为newName2。
需要注意的是,这里的:是重命名的作用,并不是指示类型,如果要同时指定类型,仍然需要在气候写上完整的模式。

let { a:newName1, b: newName2 }: { a:string, b: number } = o;

默认值

在函数调用时,有时我们并不会传所有参数,此时,可以为函数参数给默认值。

function f(args: {a: string, b?: number}) {
 let { a, b = 18 } = args;
}

这里,我们给函数参数b给定了默认值为18。

展开

展开操作符与解构相反,它可以将一个数组展开为另一个数组,或将一个对象展开为另一个对象。例如:

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

这里,bothPlus的值为[0, 1 ,2, 3, 4, 5],展开操作创建了first和second的一份浅拷贝,他们不会被展开操作所改变。
同解构一样,也可以展开对象:

let cat = { name: "Tom", age: 18 };
let Tom = { ...cat, gender: male };

Tom的值为{ name: "Tom", age: 18, gender: male },对象的展开较于数组的展开更为复杂。同数组的展开一样,它从左至右进行,但结果仍为对象。这意味着,展开对象后面的属性会覆盖前面的属性。

let cat = { name: "Tom", age: 18, gender: female };
let Tom = { ...cat, gender: male };

这里,Tom的值为{ name: "Tom", age: 18, gender: male }。
另外,展开对象,仅包含对象自己的可枚举属性。因此,当展开对象是,会丢失对象本身的方法:

class Cat {
 name: "Tom";
 hunt() {
 console.log("抓老鼠~");
 }
}
let Tom = new Cat();
let smallTom = { ...Tom };
console.log(smallTom.name); // Tom
smallTom.hunt; //报错

其次,Typescript编译器不允许展开泛型函数上的类型参数。

作者:风起缘灭原文地址:https://segmentfault.com/a/1190000043317892

%s 个评论

要回复文章请先登录注册