让你的JavaScript成为真正的Java Script

1,768 阅读5分钟
原文链接: mp.weixin.qq.com

先问一个问题:

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值。具体代码如下:

// Java
class 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中的类即是对象,用关键字privatepublic即可达到封装的效果。

  • 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!!!'
  }
}

Dog.prototype = 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的全栈开发者来说,都是意义重大的。

本文可被转发或分享,但必须保留完整图文信息和出处,作者保留追究一切法律责任的权利和手段~

欢迎搜索关注公众号“web学习社”~