typescript之三(变量声明)

我们在js下声明变量通常使用的方式var来声明变量,但偶尔也会使用const来声明常量,一般来说常量是不能被修改的,JavaScript下面,const在强制修改也是可以被修改的,但是在typescript中就不一样了,在ts中同样声明变量可以用到var,const,let(es6中)来声明一个变量,注意,在ts中通过const来声明的常量在一开始就需要给定一个值,该常量是不能被再次修改的,若强制修改,一般的编辑器都会有提示错误信息,比如

typescript之三(变量声明)
const声明的常量是不允许被修改的

我们先来说下var声明的变量,熟悉JavaScript的都知道var的使用,它可以在外部声明,也可以在函数中声明

// 典型的闭包函数
function f() {
let a = 10;
console.log(a);//10
return function g() {
let b = a + 1;
return b;
}
}
let g = f();
console.log(g());//11

function ff(val: boolean) {
if (val) {
var a = 10;
}
return a;
}
console.log(ff(false));//undefined
console.log(ff(true));//10

看上面代码ff函数,ff(false) 之所以会返回undefined;其实ff函数代码运行如下

function ff(val:boolean){
// 通过var定义了一个变量a,但并未赋值,所以当前a的值为undefined;
var a;
if(val){
// 只有当val的值为真时,才赋值a为10;
a = 10;
}
return a;
}
function f3(){
// 定义的一个变量a
var a = 32;
// 重复定义变量a并赋值为一个函数
var a = function(){
var a = 32;
return a+2;
}
// 返回a函数
return a();
}
f3();

我们可以看到,通过var定义的变量我们在下文还可以重新赋值为其他值或是函数等,下文所赋值的函数或是值会覆盖上文的变量。

function foo() {
// 以下输出3次3
for (var i = 0; i < 3; i++) { // 传给setTimeout的每一个函数表达式实际上都引用了相同作用域里的同一个i setTimeout(function () { console.log(i); }, 100 * i); } // 要想输出0,1,2。可以通过闭包的形式来解决 for (var i = 0; i < 10; i++) { (function (i) { setTimeout(function () { console.log(i); }, 100 * i); })(i); } } // foo();//输出0,1,2 function foo1() { for (let i = 0; i < 3; i++) { setTimeout(function () { console.log(i); }, 100 * i); } }

上面代码我们可以看出通过let声明的变量i就不会出现输出同一个值得情况,这就是我们要说的块级作用域,通过let来声明的变量,通常我们将{}这种用大括号包含起来的代码块,我们就叫做一个块级作用域,比如上面的foo1函数,let定义的变量i在循环中每执行一次循环,就i就重新赋值了,每次循环的时候i的作用域都是不一样的,故而不会出现i值重写的情况,之所以使用var定义的变量通过for循环之后输出的值都是一样的是因为i的值都是最后一次的值。

function f1(input: true) {
let a = 1;
if (input) {
let b = 2;
}
// return b;//此时不能被访问到,let作为块级作用域下,不能访问到if代码块中使用let定义的变量
return a;
}

typescript之三(变量声明)
通过let定义变量不能在同一作用域下不能再次被定义
typescript之三(变量声明)
typescript之三(变量声明)
在作用域外部不能跨作用域访问变量
typescript之三(变量声明)
let声明变量不存在变量的提升

//虽然说不存在变量提升,但下面这种方式编译是通过的,但是运行会抛错
function fun() {
console.log(num);
}
let num = 3;
//这就是我们常说的暂时性死区

typescript之三(变量声明)

let vs. const

现在我们有两种作用域相似的声明方式,我们自然会问到底应该使用哪个。 与大多数泛泛的问题一样,答案是:依情况而定。

使用最小特权原则,所有变量除了你计划去修改的都应该使用const。 基本原则就是如果一个变量不需要对它写入,那么其它使用这些代码的人也不能够写入它们,并且要思考为什么会需要对这些变量重新赋值。 使用 const也可以让我们更容易的推测数据的流动。

解构赋值,与es6中的解构赋值基本一致

let [fir,sub] = [1,3];
console.log(fir,sub); // 1,3 ;这种赋值方式称之为解构赋值
let {b,c} = {b:4,c:6};
console.log(b,c);//b:4 c:6
let [d,...e] = [1,2,3,4,5];
console.log(d,e);//d:1,e:[2,3,4,5]
function fun1([a,b]:[number,number]){
console.log(a,b); // a:1 b:2
}
fun1([1,2]);
//解构对象
let o = {
n: "foo",
v: 12,
};
// let { n,v } = o;
// 下面这个解构跟es6中的对象解构一致,冒号前面的是o对象中的键,冒号后面的是才是所定义的变量(理解为)
let { n: h, v: j } = o;
console.log(h, j); // h:'foo' j:12

展开

展开操作符正与解构相反。 它允许你将一个数组展开为另一个数组,或将一个对象展开为另一个对象

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

这会令bothPlus的值为[0, 1, 2, 3, 4, 5]。 展开操作创建了 firstsecond的一份浅拷贝。 它们不会被展开操作所改变。

你还可以展开对象:

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

search的值为{ food: "rich", price: "$$", ambiance: "noisy" }。 对象的展开比数组的展开要复杂的多。 像数组展开一样,它是从左至右进行处理,但结果仍为对象。 这就意味着出现在展开对象后面的属性会覆盖前面的属性。 因此,如果我们修改上面的例子,在结尾处进行展开的话:

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

那么,defaults里的food属性会重写food: "rich",在这里这并不是我们想要的结果

这里总结下所谓的展开操作,实际上与es6中的...操作符也是类似,可以算作是合并操作。

百度已收录
分享