说好的每个星期出篇文章,然鹅距离上次发文已过去3个星期有余...说好的自律呢???
好吧!下面进入正题!
在了解原型之前,先简单介绍一下构造函数。
构造函数
- 一个函数被作为构造函数还是普通函数执行的唯一区别就是是否使用
new
- 构造函数内部可以使用
this
关键字, 因为new
构造函数会生成一个实例对象
,this
会指向这个对象- 构造函数首字母建议大写, 别问为啥,行内规矩!
原型
下面定义一个Person
构造函数,这个构造函数有一个prototype
属性,这个属性指向一个原型对象Object
,这个原型对象有一个属性constructor
又指向了这个构造函数!是不是感觉有点绕,此时建议动手操作在浏览器打印一下,你就会明白了!
function Person(age){
this.age = age
console.log(this.age)
}
// 往构造函数的原型上添加一个方法
Person.prototype.dance = function() {
console.log(`小明今年${this.age}岁了`);
}
console.log(Person === Person.prototype.constructor)
上面说的和__proto__
还没有关系,它是在用构造函数生成的实例上的。当我们用构造函数生成一个实例person
时,这个实例有一个属性__proto__
指向了那个原型对象Object
。
let person = new Person(12)
// 只有new出来的实例对象的__proto__才有意义, 不然这个__proto__就是一个函数
console.log(person.__proto__ === Person.prototype)
// true 这个实例的__proto__指向构造函数Person的prototype
这个构造函数也可以直接调用,如果直接调用的话就是一个普通函数
Person(20) // undefined 因为普通函数没有this,所以this.age就是未定义的
这时我们调用person
实例上的dance
方法,也可以new
多个实例,多个实例都会继承原型上的dance
方法
person.dance() // 小明今年12岁了
let person2 = new Person(15)
person2.dance() // 小明今年15岁了
继承
通过Son.prototype
指向father
实例实现继承
function Son(){}
function Father(){}
Son.prototype = new Father();
// Son.prototype指向father实例 所以father实例的__proto__又指向他的构造函数prototype
// 从而实现继承父构造函数原型上的方法
console.log(Son.prototype.__proto__ === Father.prototype)
原型链
原型链就是一堆继承关系,我们只需要将儿子原型prototype
的__proto__
属性指向父亲的prototype
属性,构造函数的prototype
属性的constructor
属性指向其本身即可
不过需要注意的一点是,已经被实例化的对象__proto__
属性指向其构造函数的prototype
另外一个特殊的对象Object
。作为所有对象的父类,他的原型的__proto__
属性指向null
下面我们总结一下
构造函数F 原型对象O 实例对象I
<F>用prototype属性指向<O>, <I>用__proto__
属性指向<O>, 而<O>用constructor
属性指向<F>
<构造函数>的prototype = Object
,<实例>的__proto__ = Object
,因为他俩指向都是一个Object
,所以<构造函数>的prototype = <实例>的__proto__
,Obeject
的constructor
又指向他的<构造函数>,所以他们就绑在了一起
可能你看到这还是有点迷糊,其实我也是,说来惭愧,作为一个工作两年的前端前几天才弄懂闭包,今天才看懂原型,其实都是因为手懒,原型这块看了也不下好几遍了,每次都没动手跟着敲过,今天动手码了一遍,在控制台一步步打印,才算对原型有了一定的了解,所以实践是检验真理的唯一标准,coding的路上没有捷径!