highlight: atom-one-dark theme: smartblue
本文正在参加「金石计划 . 瓜分6万现金大奖」,欢迎大家来交流。写在前面
大家都知道原型是JavaScript原生就支持的,可以通过Object访问原型链。在项目中,通常要创建很多同类的对象,现在通常大家都是通过es6的class来创建。极简释义
在同类的对象中共享属性。class
请注意,Dog类的constructor里为啥会有一个name属性呢,并且这个类本身还有一个bark属性。当实用es6的class,所有的属性都定义在这个类本身上,在上面的实例中bark方法自动被添加到原型上。 我们可以在某个类的构造方法和它的实力对象里直接发现prototype的存在:class Dog {constructor(name) {this.name = name;}bark() {return `Woof!`;}}const dog1 = new Dog("Daisy");const dog2 = new Dog("Max");const dog3 = new Dog("Spot");class Dog { constructor(name) { this.name = name; } bark() { return `Woof!`; } } const dog1 = new Dog("Daisy"); const dog2 = new Dog("Max"); const dog3 = new Dog("Spot");class Dog { constructor(name) { this.name = name; } bark() { return `Woof!`; } } const dog1 = new Dog("Daisy"); const dog2 = new Dog("Max"); const dog3 = new Dog("Spot");
console.log(Dog.prototype);// constructor: ƒ Dog(name, breed) bark: ƒ bark()console.log(dog1.__proto__);// constructor: ƒ Dog(name, breed) bark: ƒ bark()console.log(Dog.prototype); // constructor: ƒ Dog(name, breed) bark: ƒ bark() console.log(dog1.__proto__); // constructor: ƒ Dog(name, breed) bark: ƒ bark()console.log(Dog.prototype); // constructor: ƒ Dog(name, breed) bark: ƒ bark() console.log(dog1.__proto__); // constructor: ƒ Dog(name, breed) bark: ƒ bark()
其中,某个实例的原型prototype直接指向对应的构造方法的prototype!当我们访问一个对象上不直接存在的属性时,JS会接着在原型链上检索看是否存在该属性。 原型模式对于使用公共属性是非常有用的。我们可以直接把公共属性添加在原型对象上,这样所有的实例都能访问到,而不需要每次都复制相同的属性;并且即便是在实例对象被创建之后,在原型上添加属性也十分简单。
class Dog {constructor(name) {this.name = name;}bark() {return `Woof!`;}}const dog1 = new Dog("Daisy");const dog2 = new Dog("Max");const dog3 = new Dog("Spot");Dog.prototype.play = () => console.log("Playing now!");dog1.play();class Dog { constructor(name) { this.name = name; } bark() { return `Woof!`; } } const dog1 = new Dog("Daisy"); const dog2 = new Dog("Max"); const dog3 = new Dog("Spot"); Dog.prototype.play = () => console.log("Playing now!"); dog1.play();class Dog { constructor(name) { this.name = name; } bark() { return `Woof!`; } } const dog1 = new Dog("Daisy"); const dog2 = new Dog("Max"); const dog3 = new Dog("Spot"); Dog.prototype.play = () => console.log("Playing now!"); dog1.play();
在dog1/2/3实例被初始化之后,给Dog原型上添加play方法,依然可以被dog1/2/3直接调用。给Dog类的prototype直接添加属性的效果,有点类似JS中的继承的效果。下面我们来新建个SuperDog类,它继承自Dog类,当然它继承了Dog类的所有属性和方法(name/bark),同时给它新加个fly方法,代码如下:
大家或许听说过,JS的继承是通过prototype原型链来实现的。具体怎么实现的呢?其实SuperDog类的原型prototype指向父类Dog的原型prototype,并且dog1实例对象的原型prototype指向SuperDog类的原型prototype。这样就形成了原型链。class SuperDog extends Dog {constructor(name) {super(name);}fly() {return "Flying!";}}const dog1 = new SuperDog("Daisy");dog1.bark();dog1.fly();class SuperDog extends Dog { constructor(name) { super(name); } fly() { return "Flying!"; } } const dog1 = new SuperDog("Daisy"); dog1.bark(); dog1.fly();class SuperDog extends Dog { constructor(name) { super(name); } fly() { return "Flying!"; } } const dog1 = new SuperDog("Daisy"); dog1.bark(); dog1.fly();

这就是为什么取名叫原型链的原因 ——— 会依次递归查找某个属性,直到找到为止。
Object.create 指定原型
Object.create方法用来给某个对象制定原型prototype:从上述代码中我们不难看出:给pet1指定原型对象时,pet1本身是没有任务属性,但是pet1的原型对象上则被指定成dog对象; 同时也不难发现Object.create方法可以快速实现从其他对象继承属性和方法 —— 通过原型链的方式添加新属性和方法。const dog = {bark() {return `Woof!`;}};const pet1 = Object.create(dog);pet1.bark(); // Woof!console.log(Object.keys(pet1)); // []console.log(Object.keys(pet1.__proto__)); // ["bark"]const dog = { bark() { return `Woof!`; } }; const pet1 = Object.create(dog); pet1.bark(); // Woof! console.log(Object.keys(pet1)); // [] console.log(Object.keys(pet1.__proto__)); // ["bark"]const dog = { bark() { return `Woof!`; } }; const pet1 = Object.create(dog); pet1.bark(); // Woof! console.log(Object.keys(pet1)); // [] console.log(Object.keys(pet1.__proto__)); // ["bark"]
总结
原型模式可以很方便的让某个对象拥有或者继承其他对象的属性或方法。同时原型链允许调用自己本身没有的属性或方法,这样可以避免重复定义属性和方法,也可以减少内存使用。感谢您的来访,获取更多精彩文章请收藏本站。

© 版权声明
THE END
暂无评论内容