Skip to content
On this page

原型系统

  • 如果所有对象都有私有字段[[prototype]],就是对象的原型;
  • 读一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止 。

ES6 提供的操纵原型方法:

  • Object.create 根据指定的原型创建新对象,原型可以是 null;

  • Object.getPrototypeOf 获得一个对象的原型;

  • Object.setPrototypeOf 设置一个对象的原型。

    var cat = {
        say(){
            console.log("meow~");
        },
        jump(){
            console.log("jump");
        }
    }
    
    var tiger = Object.create(cat,  {
        say:{
            writable:true,
            configurable:true,
            enumerable:true,
            value:function(){
                console.log("roar!");
            }
        }
    })
    
    var anotherCat = Object.create(cat);
    anotherCat.say(); //moew~
    
    var anotherTiger = Object.create(tiger);
    anotherTiger.say(); //roar!
    

new

new 运算接受一个构造器和一组调用参数,

实际上做了几件事:

  • 以构造器的 prototype 属性(注意与私有字段[[prototype]]的区分)为原型,创建新对 象;
  • 将 this 和调用参数传给构造器,执行;
  • 如果构造器返回的是对象,则返回,否则返回第一步创建的对象

new 这样的行为,试图让函数对象在语法上跟类变得相似,但是,它客观上提供了两种方式 ,

添加属性

一是在构造器中添加属性,二是在构造器的 prototype 属性上添加属性。
//直接在构造器中修改 this,给 this 添加属性
function c1(){
    this.p1 = 1;
    this.p2 = function(){
        console.log(this.p1);
    }
}
var o1 = new c1;
o1.p2();

//修改构造器的 prototype 属性指向的对象,它是从这个构造器构造出来的所有对象的原型。
function c2(){
}
c2.prototype.p1 = 1;
c2.prototype.p2 = function(){
    console.log(this.p1);
}
var o2 = new c2;
o2.p2();

ES6 中的类

推荐使用 ES6 的语法来定义类,而令 function 回归原本的函数语义。ES6 中引入了 class 关键字,并且在标准中删除了所有[[class]]相关的私有属性描述,类的概念正式 从属性升级成语言的基础设施,从此,基于类的编程方式成为了 JavaScript 的官方编程 范式。

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  // Getter
  get area() {
    return this.calcArea();
  }
  // Method
  calcArea() {
    return this.height * this.width;
  }
}

继承

class Animal {
  constructor(name) {
    this.name = name;
  }
  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); //调用父类的构造函数
  }
	//覆盖父类的方法
  speak() {
    console.log(this.name + ' barks.');
  }
}

let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.

总结

在新的 ES 版本中,我们不再需要模拟类了:我们有了光明正大的新语法。而原型体系同时 作为一种编程范式和运行时机制存在。

我们可以自由选择原型或者类作为代码的抽象风格,但是无论我们选择哪种,理解运行时的 原型系统都是很有必要的一件事。