Typescript的學習筆記_溫故javascript一些令人詬病的問題_typescript型別跟執行方式還有物件
Typescript 是由微軟的C#之父Anders Hejlsberg設計出來的一套語言
javascript 本身以前由Netscape推出而當時是為了蹭Java的熱度才取名叫Javascript的
Javascript本身語言有一個缺點那就是沒有強型別的觀念
Typescript則是補足這塊觀念的增強版程式語言
在此以es5大部分瀏覽器都還能支援的標準來做javascript的比較
Typescript (.ts)本身編譯完最終產物仍是javascript (.js)
=======================================
變數作用域的觀念(var,let)
javascript 變數 區域性跟全域性觀念
通常若你用var宣告在特定一個function中就會視為區域性變數
外層無法存取的到
var num1 = 1;
function test_func(){
var num2 = 2;
console.log(num1);
console.log(num2);
}
console.log(num1);
console.log(num2);
num2 is not defined
當你在function中用var宣告並定義變數的時候
只能夠過functino呼叫存取該區域變數的值此時是有局部範圍限制的!!
再來怪異的一個點到底時常看到人家寫的javascript
宣告變數有時有寫var有時又不寫??? 到底有沒有差別?
這裡在function中若去除var
直接只寫一個變數名稱num2
跟直接指派值給num2
都會發現屬於 not defined
所以看起來感覺有var的宣告跟無var的宣告沒有差異
而not defined 跟 undefined是不同的涵義
undefined不是錯誤 not defined才是!!
not defined 代表根本不存在沒被宣告跟定義
undefined 則代表有被宣告但沒有被定義值
javascript在尚未初始化前不會知道該型別是捨麼
var num1;
function test_func(){
num2=2;
console.log(num1);
console.log(num2);
}
console.log(num1);
test_func();
console.log(num2);
這邊會發現原先在functino中定義的num2不管有無var宣告原本都會報錯的
但此時由於上一句呼叫過function再console打印num2就會有資料
所以事實上區域跟全域跟var有無的宣告也是有差異的
區域跟全域在陣列中的撰寫細節
var arr = [];
for(var i=0;i<10;i++){
arr[i] = function(){
console.log(i);
}
}
arr[1]();
arr[2]();
arr[3]();
這裡針對array元素值給function
當中打印對應i的索引
結果怎麼印都是10....
並非預期印出指定的index
因為最外層的for已經跑到最後一圈到10了
到這邊後開始很頭暈.... javascript怎麼變數宣告這麼凌亂
要加var跟不加沒有一致性
很容易寫出BUG
因此之後出現let
var arr = [];
for(let i=0;i<10;i++){
arr[i] = function(){
console.log(i);
}
}
arr[1]();
arr[2]();
arr[3]();
然後開始會看到很多文章跟人分享var跟let就是一個區域一個全域的說法
其實有點不完全正確
但var其實從剛剛一開始實驗也有區域全域的問題!!
常數的觀念
在javascript中 常數const (大部分程式語言都通用的觀念,但通常IDE都會提示錯誤)
則還單純一點也就是一個數不可以改變
初始化多少之後就只能永遠是多少
const PI=3.1415;
console.log(PI);
PI=314;
只是會有一點不太善解人意
不會在寫的過程被提醒不能指派常數的錯誤叮嚀
在到執行階段才會發現問題!
函數的參數多載(同名異式)設計觀念
js中函數 overload 定義
以前傳統作法會採用邏輯運算來做預設值的optional操作設計
function add(a,b){
a=a || 4 , b = b || 6;
console.log(a+b);
}
add(4,8);
add(4);
add();
當然在之後推出來新版的ES6則可支援到function預設參數值
function add(a=4,b=6){
console.log(a+b);
}
add(4,8);
add(4);
add();
物件的觀念
let student = {
name:"Jack",
age:25,
scores:{
math:76,
english:88,
computer:90
},
getTotalScore:function(){
return this.scores.math + this.scores.english + this.scores.computer;
}
}
console.log(student.age);
console.log(student['name']);
console.log(student.scores.math);
console.log(student.scores['english']);
console.log(student.getTotalScore());
箭頭函數的觀念
一個陣列我們想去打印每個元素的平方結果
傳統作法可以用map
let a = [1,2,3];
let b = a.map(function(i){
return i*i;
})
console.log(b);
箭頭函數(Lambda)風格
可以省去每次都要寫 function再來一個括號包參數
當function只有一個參數時候可以省去括號直接寫參數搭配箭頭
那主要設計用法除了簡潔寫法還可以解決物件中this使用上指向錯誤的一些存取問題
let a = [1,2,3];
let b = a.map(function(i){
return i*i;
})
console.log(b);
let c=a.map( i => i*i)
console.log(c);
物件中this使用上的一些問題
架設我們有一個物件obj裡面定義打印something屬性的資料
我們在該方法中又去包一層setTimeout的方法時候
let obj = {
something : "banana",
showSomething(){
//console.log(this.something);
setTimeout(function(){
console.log(this.something);
},500);
}
}
obj.showSomething();
會發現存取不到something 變成 undefined
主要是因為在setTimeout 方法中this指向已經不再是當前物件了
所以就要改成用 箭頭函式來改寫解決這問題
let obj = {
something : "banana",
showSomething(){
//console.log(this.something);
//setTimeout(function(){
// console.log(this.something);
//},500);
setTimeout(()=>{
console.log(this.something);
},500);
}
}
obj.showSomething();
for...in跟for...of迴圈的觀念
在javascript中也很常出錯的就是它的foreach
預設是去抓其index(key)而非值
跟其他一般程式語言不太一樣
let arr = [1,2,3,4,5,6,7,8];
for(var item in arr){
console.log(item);
}
若是要遍歷值要用arr[key]
那通常for...in 比較少用在陣列 因為陣列的key也就是index
直接for i=0....去做就好沒有捨麼好取的
通常是在針對物件取屬性key時候會比較常用
let obj = {
thing:"banana",
price:45
}
for(var item in obj){
console.log(item);
}
而for...of其實寫法跟for...in差不多
但for...of 是直接印值出來 跟一般其他程式語言foreach觀念叫像
let arr = [1,2,3,4,5,6,7,8];
for(var item of arr){
console.log("for...of的值:"+item);
}
class的觀念
以前ES5的classes舊式風格
定義一個function同時代表該class的建構子
let Point = function(x,y){
this.x = x;
this.y = y;
this.printAll = function(){
console.log(this.x + ", " + this.y);
}
}
到了ES6之後就出現class了
class Point{
//建構子
constructor(x,y){
this.x=x;
this.y=y;
}
printAll(){
console.log(this.x + ", " + this.y);
}
}
在javascript中 建構子是直接寫constructor而非class名稱!!!
那在ES6也可以做繼承
用 extends
class Label extends Point{
constructor(x,y,name){
super(x,y);//必要 用來初始化指向Base Class
this.name = name;
}
printAll(){
super.printAll();
console.log(this.name);
}
}
let lbl = new Label(1,2,"Label_1");
lbl.printAll();
再來 簡單認識到 TypeScript
初次要先安裝typescript
npm i typescript -g
typescript非編譯器而是做轉譯(translate)
轉譯(translate): A程式語言翻譯成B程式語言
會負責幫你把寫好的typescript轉成javascript
因為瀏覽器只認得javascript
有無裝成功可透過
tsc --version來做確認
首先附檔名是.ts
預設要宣告變數名稱後頭需補上冒號加上資料型別
而function則一樣需補上冒號加上資料型別
參數也一樣
其餘則跟ES6一樣有預設值直接寫
執行方式則是下
tsc {xxx.ts}
會發現多跑出一個.js的檔案
最終要運行的就是已經被轉譯出來的.js檔案
tsc ex10_typescript.ts & node ex10_typescript.js
var num = 1;
function fun1(a, b) {
if (a === void 0) { a = 4; }
if (b === void 0) { b = 8; }
return a + b;
}
console.log(fun1());
let num:number=1;
function fun1(a:number=4,b:number=8):number{
return a+b;
}
console.log(fun1());
let tup:[string,number]=["1",5];
let arr:number[] = [1,2,3,4];
若function無返回值則可以用void
常用的型別有
string
number
boolean
any --> 跟C#的var有點像 (某種特定情況在typescript不能用)
tuple -->元組(跟元祖雪餅沒有關係...)
就跟python有點類似可以混和多種不同資料型別
array
typescript 的 class 屬性
在建構子中會發現套用typescript規範寫
仍然會有錯誤
是因為有缺少修飾詞 private (DI寫法)
class Person{
constructor(private Name:string){
this.Name=Name;
}
getName(){
console.log(this.Name);
}
}
之後就跟一般ES6物件一樣操作
輸出屬性值tsc ex11_Person.ts & node ex11_Person.js
經由typescript翻譯出來javascript
我們可在當前有定義的Person Class在做存取使用
但如果要在外面去引用則要用import 語法
class定義的所在檔案裏頭的class必須要記得export(輸出)才能給外部他人使用!
export class Person{
constructor(private Name:string){
this.Name=Name;
}
getName(){
console.log(this.Name);
}
}
let person = new Person("Jack");
person.getName();
外部在存取的程式
import {class1名 , class2名....} from 'class定義的所在檔案名稱(不含附檔名)'
import {Person} from './ex11_Person'
let person = new Person("Jack");
person.getName();
留言
張貼留言