小白看过来,浅谈JS中的原型。

335 阅读3分钟

原型定义

是函数function对象的一个属性,它定义了构造函数制造的对象的公共祖先。通过构造函数产生对象,该对象可以继承原型的属性和方法。原型也是对象

为了更好地理解原型,我们抓住一些关键字;

首先它是函数对象的属性,就比如说函数的name,是一个函数本身就具有的。

定义了构造函数制造的对象的公共祖先,这怎么理解?我们来看段代码:

Person.prototype.name = '钢铁侠'
Person.prototype.say = function () {
console.log('哈哈哈哈')
}
function Person() {
}

let p = new Person()
let p2 = new Person()
console.log(p.name);
console.log(p2.name);
p.say()

此时打印出来三个结果的是'钢铁侠' '钢铁侠' '哈哈哈哈'。也就是构造对象p和p2都继承了函数原型的属性和方法。

原型也是对象,看下图:

1.png

图上显示Person.prototype是一个对象{}。

原型特点

1.可以提取公有属性

直接上代码:

Car.prototype = {  //不需要在每次创建对象时都执行,降低了代码的耦合度
    carName: 'BMW',
    height: 1400,
    lang: 4900
}
function Car(owner, color) {
    this.owner = owner
    this.color = color
}

上段代码就直接在函数Car的原型上定义了三个属性,提取了Car的公有属性,每次创建对象都能继承到,这样就降低了代码的耦合度。

2.实例对象无法对原型做 ‘增删改查’

当我们在函数原型上定义了一个属性,构造函数制造出来的对象是无法对原型进行增删改查的。举个改的例子,我们看一下下面代码:

Person.prototype.lastName = '蜘蛛侠'
function Person(name) {
    this.name = name
}

var p = new Person('songsong')
p.lastName = 'jiang' //改不动原型的属性
console.log(Person.prototype);

输出的结果是:{ lastName: '蜘蛛侠' },想要修改的话只能通过:Person.prototype.lastName = '超人'来改。

3.实例对象的隐式原型(proto)== 构造函数的显式原型 (prototype)

看到这里就有点抽象,我们直接用代码解释:

        Person.prototype.name = 'song'
        Person.prototype.age = '18'
        function Person() {

        }
        var person = new Person()
        console.log(person.name);
        //person.name 先找自己是否具有该属性,没有的话再去 __proto__ 上找
        
        console.log(person.name);

对象都是有原型的,称为隐式原型;函数的原型称为显示原型。实例对象先找自己是否具有该属性,没有的话再去自己的隐式原型上找,因为对象的隐式原型会从函数的显式原型那里继承属性

上述代码打印出的结果为‘song’,因为实例对象自己没有name属性,在自己的隐式原型那(函数的显式原型)那找到了。

原型链

定义:在原型上加一个原型,再加一个原型...把原型连成链状,这种链状的访问顺序叫做原型链。

我们来看个例子

Ground.prototype.lastName = '漫威'
function Ground() {

}
var ground = new Ground()
Father.prototype = ground
function Father() {
    this.name = '钢铁侠'
    this.fortune = {
        card: 'jia'
    }
}
var father = new Father()
Son.prototype = father
function Son() {
    this.hobit = 'reading'

}
var son = new Son()
console.log(son.name);
console.log(son.lastName);

上面代码输出结果为:‘钢铁侠’‘漫威’

可以看到函数Son,Father,Ground通过原型连接起来了,当想要访问son.name的值,会通过Son的显式原型访问Father构建对象的隐式原型找到了name的值为‘钢铁侠’;当想要访问son.lastName的值时,一样会通过Son的显式原型访问Father构建对象的隐式原型,还是没有;就又会通过Father的显式原型访问Ground构建对象的隐式原型,最终找到值输出‘漫威’。

扩展一下

我们来看张经典图

2.png

图片上展示了函数的显式原型与对象的隐式原型构成的原型链。函数的显式原型也是对象,也会有隐式原型__proto__,它会等于创造自己的函数的显式原型,一层一层最终会找到祖先。

总结

原型理解起来可能有点绕,但是它的作用是很大的,能很好地降低代码的耦合度,让代码更优雅。我们可以很好地利用原型链,避免重复写一些代码。