重学前端
如果我们抛开 JavaScript 用于模拟 Java 类的复杂语法设施(如 new、Function Object、函数的 prototype 属性等),原型系统可以说相当简单,我可以用两条概括:
- 如果所有对象都有私有字段[[prototype]],就是对象的原型;
- 读一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止。
这个模型在 ES 的各个历史版本中并没有很大改变,但从 ES6 以来,JavaScript 提供了一系列内置函数,以便更为直
- 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();var anotherTiger = Object.create(tiger);anotherTiger.say();
这段代码创建了一个“猫”对象,又根据猫做了一些修改创建了虎,之后我们完全可以用 Object.create 来创建另外的猫和虎对象,我们可以通过“原始猫对象”和“原始虎对象”来控制所有猫和虎的行为。
new运算
new 运算接受一个构造器和一组调用参数,实际上做了几件事:
- 以构造器的 prototype 属性(注意与私有字段[[prototype]]的区分)为原型,创建新对象;
- 将 this 和调用参数传给构造器,执行;
- 如果构造器返回的是对象,则返回,否则返回第一步创建的对象。
下面代码展示了用构造器模拟类的两种方法:
function c1(){this.p1 = 1;this.p2 = function(){console.log(this.p1);}
}
var o1 = new c1;
o1.p2();function c2(){
}
c2.prototype.p1 = 1;
c2.prototype.p2 = function(){console.log(this.p1);
}var o2 = new c2;
o2.p2();
第一种方法是直接在构造器中修改 this,给 this 添加属性。
第二种方法是修改构造器的 prototype 属性指向的对象,它是从这个构造器构造出来的所有对象的原型。
ES6 中的类
基本写法:
class Rectangle {constructor(height, width) {this.height = height;this.width = width;}// Getterget area() {return this.calcArea();}// MethodcalcArea() {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.
更多推荐
重学前端
发布评论