前言
在JS中,只要是一个函数,那么它就有prototype
这个属性,该属性会指向一个对象,这个对象可以存放该函数定义的属性
和方法
,并且这些属性和方法都是共享的,每个实例成员都可以使用这些属性和方法,这就是原型
也被称为原型对象。
邂逅原型
既然原型如此强大,那么就让我们和它来一场美丽的邂逅。
我们创建一个构造函数,并往该函数的原型添加一些方法。
function User(name, age){
this.name = name
this.age = age
}
// 给User的原型添加方法
User.prototype.sayHi = function() {
console.log(`你好,我是${this.name},我今年${this.age}岁了`)
}
// 创建两个实例对象,并且调用原型上面的方法
const zs = new User('张三', 18)
const ls = new User('李四', 19)
// 张三调用这个方法
zs.sayHi() // 你好,我是张三,我今年18岁了
// 李四调用
ls.sayHi() // 你好,我是李四,我今年19岁了
如代码所示,张三和李四都可以调用原型的sayHi
方法,并且输出内容不一,这段代码足以体现出原型对象
上面的方法是共享
的。
为什么实例可以访问原型对象
你肯定有疑惑,为什么实例成员可以访问原型对象上面的方法,实例只是被new出来的对象,跟原型有什么关系呢?
// 打印一下上面new出来的实例对象
console.log(zs)
为了让大家方便观看,我把打印结果截图放出来。
先不要看其他代码,你就看__proto__
,它是一个属性,听清楚!它会指向prototype
原型对象,所以说,为什么实例对象可以访问原型对象了,就是有__proto__
属性的存在,你也可以把它称之为对象的原型
,总之,它的作用很强大。
用一段代码来证明我说的是否正确。
console.log(zs.__proto__ == User.prototype); // true
访问结果为true,足以证明,__proto__
确实是指向了该函数的原型对象。
原型、constructor之间的关系
既然是往原型对象上面添加的方法,那么这些方法最终是属于谁的?总得给个说法,对吧?这是一个值得的思考的问题。
我们打印一下该函数的原型,便可得出结论。
console.log(User.prototype)
贴出一张图,方便大家观看。
可以看到,有一个sayHi函数,这个便是我们刚刚添加的方法。还可以看到一个constructor
函数,它指向了一个函数,这个便是我们创建的这个User
函数。
用一段代码来验证一下。
console.log(User.prototype.constructor == User) // true
打印结果为true,得出结论:原型对面里面的constructor
函数用于指回我们最开始创建的那个构造函数,比如,你爸妈把你生下来,然后因为要工作,所以把你托养在外婆或者爷爷奶奶那,但最终你还是你爸妈的儿子和女儿,这是不可以改变的关系。