原型及原型扩展
prototype翻译为“原型”,js中所有function的对象都有一个prototype属性,这个属性本身是一个object对象,我们可以在上面添加属性和方法。同时,prototype上定义的方法和属性统一原型链上的对象皆可调用。
修改我的上一篇如下
function Animal(name) {
this.name = name;
// 将say函数挂载到原型链上
//this.say = function() {
// console.log('I\'m ' + this.name || '');
// return this;
//}
}
//
Animal.prototype.say = function() {
console.log('I\'m ' + this.name || '');
return this;
}
let ani = new Animal('牛');
ani.say();
function Fish(name, food) {
//Animal.call(this, name);
this.food = food;
this.eat = function() {
console.log('I eat ' + this.food || '');
}
}
// 将Fish指向Animal原型,获得say方法和name属性
Fish.prototype = new Animal('鲤鱼');
let carp = new Fish('水草');
carp.say().eat();
// Fish的say方法和Animal的say方法是同一个
console.log(carp.say == ani.say); // true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
按照上面的写法,在animal的原型上挂载了say方法,同理我们将aniaml整体挂载到Fish原型上,那么Fish的原型上就会有name和say两个。正常情况下我们是不想要name属性到原型上的,所有我做出如下修改:
function Fish(name, food) {
// 获取Animal的name属性
Animal.call(this, name);
this.food = food;
this.eat = function() {
console.log('I eat ' + this.food || '');
}
}
// Fish原型链指向Animal原型链,只获取say方法
Fish.prototype = Animal.prototype;
2
3
4
5
6
7
8
9
10
因为function本身就是object所以所有的prototype最终会指向Object.prototype,从而形成一条条原型链。原型链上的属性或方法会从上到下继承,你可以使用原型对象的方法或属性也可以自定义覆盖原型属性,玩法非常灵活。
在js中很多方法都是通过原型来实现的,比如说常用数组和字符串类型的内置方法其实都是挂载到原型上的,查看MDN文档可以清楚看到。

通过原型我们能进行自定义扩展,拿我使用的Vue框架来说使用亦是很频繁。在main.js中我们可以使用Vue.prototype挂载自定义属性,通常我们会将全局的api请求、国际化、Vuex等挂载到Vue的原型上,那么在Vue环境中通过this即可调用
import Vue from 'vue'
import App from './App'
import api from './api'
Vue.prototype.$api = api
Vue.prototype.$store = store
const app = new Vue({
...App
})
app.$mount()
2
3
4
5
6
7
8
9
10
*注意:*实例对象没有prototyp属性,所有对Vue new出来的实例app不能设置prototype
Vue我们使用的$on、$emit、$set、$destroy等方法都是通过原型挂载的,在Vue源码vue/src/core/instance/state.js、vue/src/core/instance/lifecycle.js、vue/src/core/instance/events.js中都可以看到挂载记录
除开prototype我们还有一种隐式原型__proto__,不同于prototype只在函数中,__proto__存在于所有的对象中。使用它来访问已经实例化对象的prototype属性,两者使用有不少的区别。
- 实例对象没有
prototyp属性 - 实例对象的
__proto__指向对象Person的prototype - 实例对象
__proto__等同于Object.getPrototypeOf(实例对象)、对象的__proto__等同于Object.getPrototypeOf(对象)
function Person(name) {
this.name = name
}
let person1 = new Person('张三')
console.log(person1.prototype) // undefined
console.log(person1.__proto__) // {}
console.log(person1.__proto__ === Person.prototype) // true
console.log(person1.__proto__ === Object.getPrototypeOf(person1)) // true
console.log(Person.__proto__ === Object.getPrototypeOf(Person)) // true
2
3
4
5
6
7
8
9
10