JavaScript為什么叫“JavaScript”?
要回答這個問題還得從JavaScript的歷史說起。
1995年5月,Netscape創建了稱為Mocha(摩卡)的瀏覽器端的腳本語言。
可是沒過多久,同年9月就改名為“LiveScript”。
又過了沒多久,同年12月,Netscape與sun公司合作,將其改名成“JavaScript”了,意為像Java一樣的Script(腳本語言)。
為什么最終確定了“JavaScript”這個名字?
“JavaScript”和“Java”到底有多少相似度呢?
我們通過幾段代碼來簡單地比較一下~
既然是“像Java一樣”,那么就以Java為准進行對比。而Java作為一門純正的面向對象的語言(一切皆為對象類),我們就從Java面向對象的3個特性出發進行對比。
封裝
封裝作為首要特性,指的是能將對象的屬性或函數隱藏或暴露出來。
我們創建一個 Animal 對象,讓其有個私有屬性 name ,同時只能通過對象上的 set/get 方法修改/獲取 name 值。
具體代碼如下:
// Javaclass Animal { private String name; public void set(String name) { this.name=name;
} public String get() { return this.name;
}
}public class Test { public static void main(String[] args) {
Animal animal=new Animal();
animal.set("dog");
System.out.println(animal.get()); // "dog"
}
}// JavaScript(ECMAScript5) function Animal() { var name=''
this.set=function(a) {
name=a
} this.get=function() { return name
}
}var animal=new Animal()
animal.set('dog')console.log(animal.get()) // 'dog'
對於“封裝”特性,兩者都能實現,但實現方式還是有些區別。
Java中的類即是對象,用關鍵字 private 和 public 即可達到封裝的效果。
JavaScript中的作用域為函數,所以需要函數來實現。
繼承
Java中的繼承特性可以讓子類獲得父類中定義的屬性和方法。
class Dog extends Animal {
public String bark() { return "wang wang wang!!!";
}
}
public class Test {
public static void main(String[] args) { Dog dog=new Dog();
dog.set("dog"); System.out.println(dog.get()); // "dog"
System.out.println(dog.bark()); // "wang wang wang!!!"
}
}
JavaScript中實現繼承得依賴函數中的prototype屬性,將prototype屬性指向父類的實例。
function Dog() { this.bark=function() { return 'wang wang wang!!!'
}
}
Dogtotype=new Animal()var dog=new Dog()
dog.set('dog')
dog.get() // 'dog'dog.bark() // 'wang wang wang!!!'
在繼承上,JavaScript和Java相比,出現了一些差異:需要在函數聲明之后,讓其prototype屬性指向父類實例以實現繼承的效果,繼承多個父類時還需要將多個實例進行合並。代碼的可維護性和可讀性方面,顯然不Java如在類的聲明時進行定義。
多態
多態我們以函數為例,當一個函數需要對不同的輸入結果進行不同的操作時,一般會使用函數重載。下面的例子我們編寫一個 bark 的方法,來針對不同的輸入進行顯示。
class Cat { // 當輸入字符串時,直接顯示
public String bark(String sound) { return sound;
} // 當為輸入時,輸出默認值
public String bark() { return "...";
}
}public class Test { public static void main(String[] args) {
Cat cat=new Cat();
System.out.println(cat.bark()); // "..."
System.out.println(cat.bark("miao~")); // "miao~"
}
}
而JavaScript則比較“悲催”,語言本身不支持重載函數,如果多次定義函數則會被覆蓋,所以只能通過判斷入參來實現多態。
function Cat() { this.bark=function(sound) { if(undefined !==sound && null !==sound) { return sound
} else { return '...'
}
}
}var cat=new Cat()console.log(cat.bark()) //'...'console.logcat.bark('miao')) // 'miao'
在多態這個特性上,JavaScript和Java的區別進一步被放大,因為JavaScript既沒有變量類型聲明,函數也不支持重載。
更多
JavaScript和Java的語言差異當然可以列出更多,比如最受人詬病之一的便是JavaScript是弱類型語言,這使得代碼的健壯性下降:函數可能傳入任何可能引起錯誤的值,但是卻只能在執行時發現。當然更高級的接口功能JavaScript原生也是不支持的。
從上面的代碼分析可以看出,JavaScript和Java還存在着不小的差異,令人欣慰的時ES6版本對JavaScript有不小的提升,讓其更高效和健壯。更令人贊嘆的是Typescript這種膠水語言的出現,讓代碼成為更接近Java的Script。
我們用Typescript把上面3個類重寫一下:
// 封裝class Animal { private name:string; public set(name:string):void { this.name=name
} public get():string { return this.name
}
}// 繼承class Dog extends Animal { public bark():string { return 'wang wang wang!!!'
}
}// 多態class Cat { public call():string
public call(sound:string):string
public call(sound?:string):string { if(undefined !==sound && null !==sound) { return sound
} else { return '...'
}
}
}
和Java語言相比,在 封裝 和 繼承 特性上寫法非常相似,有一些小小的差異比如大小寫,類型申明的前后位置,而在 多態 特性上,Typescript增加了類型聲明,但是受限於JavaScript語言限制,只能有一個函數實現,仍然避免不了參數判斷。
總結
如果說ES6讓JavaScript更像python,那么Typescript作為ES6的超集,讓JavaScript實至名歸——變得更像Java。
這樣的好處一方面是讓開發者能寫出健壯、高效的代碼,另一方面是使得JavaSript越來越有可能變成運行在Node.js上的后端語言。對於前端開發者,還是對於JavaScript的全棧開發者來說,都是意義重大的。