JavaScript不区分类和实例的概念,而是通过原型(prototype)来实现面向对象编程。
JavaScript的原型链和Java的Class区别就在,它没有“Class”的概念,所有对象都是实例,所谓继承关系不过是把一个对象的原型指向另一个对象而已。
// 原型对象: var Student = { name: 'Robot', height: 1.2, run: function () { console.log(this.name + ' is running...'); } }; function createStudent(name) { // 基于Student原型创建一个新对象: var s = Object.create(Student); // 初始化新对象: s.name = name; return s; } var xiaoming = createStudent('小明'); xiaoming.run(); // 小明 is running... xiaoming.__proto__ === Student; // true
JavaScript对每个创建的对象都会设置一个原型,指向它的原型对象。
当我们用 obj.xxx 访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到 Object.prototype 对象,最后,如果还没有找到,就只能返回 undefined 。
var arr = [1, 2, 3]; 其原型链是: arr ----> Array.prototype ----> Object.prototype ----> null
function foo() { return 0; } 函数也是一个对象,它的原型链是: foo ----> Function.prototype ----> Object.prototype ----> null
Array.prototype 定义了 indexOf() 、 shift() 等方法,因此可以在所有的 Array 对象上直接调用这些方法。
由于 Function.prototype 定义了 apply() 等方法,因此,所有函数都可以调用apply()
方法。
构造函数
function Student(name) { this.name = name; this.hello = function () { console.log('Hello,' + this.name + '!'); } } var xiaoming = new Student('小明'); xiaoming.name; xiaoming.hello();
在Java中,继承的本质是扩展一个已有的Class,并生成新的Subclass。
但是JavaScript由于采用原型继承,无法直接扩展一个Class,因为根本不存在Class这种类型。
class继承
//class继承 class Student{ constructor(name) { this.name=name; } hello(){ console.log('hello,'+this.name); } } var xiaoming = new Student('小明'); xiaoming.hello(); class PrimaryStudent extends Student{ constructor(name,grade){ super(name); this.grade = grade; } myGrade(){ console.log('I am at grade' + this.grade); console.log(this.name); } } var xiaohong = new PrimaryStudent('小红',12); xiaohong.myGrade();
注意: PrimaryStudent 的定义也是Class关键字实现的,而 extends 则表示原型链对象来自 Student 。子类的构造函数可能会与父类不太相同,例如 PrimaryStudent 已经自动获得了父类 Student 的 hello 方法,又在子类中定义了新的 myGrade 方法。
class
的好处就是极大地简化了原型链代码。要注意浏览器是否支持ES6的class。