都知道JavaScript原型,但原型模式你会用吗?

写在前面

前端同学都知道原型是JavaScript原生就支持的,可以通过prototypeproto 访问原型。在项目中,通常要创建包含继承关系的对象,现在通常大家都是通过es6的class关键词来创建。大家也或许听过JavaScript的继承是通过原型链的方式实现的,那今天就来深入探究下这种原型模式

function Dog() {}
//or
class Dog{}
// 访问原型
Dog.prototype

const dog = new Dog();
// 访问原型
dog.__proto__ 

第一种方式是构造函数访问原型的方式;第二种方式是实例对象访问原型的方式。

极简释义

在某一类对象中共享属性或方法

class关键词

下面我们来看一下class的常见用法:

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类的constructor里为啥会有一个name属性(this.name)呢?这个类本身还有一个bark属性。其实当使用es6的class,所有的属性都定义在这个类的原型上,比如上面的bark方法自动被添加到原型上。

我们可以在某个类的构造方法和它的实例对象里直接发现prototype的存在:

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(); 

在dog1/2/3实例被初始化之后,给Dog原型上添加play方法,依然可以被dog1/2/3直接调用。

给Dog类的prototype直接添加属性的效果,有点类似JS中的继承的效果。下面我们来新建个SuperDog类,它继承自Dog类,当然它继承了Dog类的所有属性和方法(name/bark),同时给它新加个fly方法,代码如下:

class SuperDog extends Dog {constructor(name) {super(name);}fly() {return "Flying!";}
}

const dog1 = new SuperDog("Daisy");
dog1.bark();
dog1.fly(); 

大家或许都听说过,JS的继承是通过prototype原型链来实现的。具体怎么实现的呢?其实SuperDog类的原型prototype指向父类Dog的原型prototype,并且dog1实例对象的原型prototype指向SuperDog类的原型prototype,这样就形成了原型链

这就是为什么取名叫原型链的原因 ——— 会依次递归查找某个属性,直到找到为止。

Object.create 指定原型

Object.create方法用来给某个对象指定原型prototype对象:

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"] 

从上述代码中我们不难看出:给pet1指定原型对象时,pet1本身是没有任何属性,但是pet1的原型被指定成dog对象;同时Object.create方法可以快速实现从其他对象继承属性和方法 ———— 通过原型链的方式添加新属性和方法。

总结

原型模式可以很方便的让某个对象拥有或者继承其他对象的属性或方法;同时原型链的存在允许调用自己本身没有的属性或方法,这样可以避免重复定义属性和方法,也可以减少内存使用,从而可以优化性能。

最后

为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值