白天写了一篇 【JS中建立对象的方法】,写完之后感受意犹未尽(实际状况是感受原型那块内容没有交
代清楚),因此开这一篇继续聊聊关于JavaScript中的原型对象
相信用过vue的童鞋,都常常这样作,用Vue.prototype.xxx = xxx 把一个方法或者属性添加到Vue对象的原型上,
这样,咱们在vue实例的任何地方,均可以用这个方法或属性了,我最喜欢用的,就是把异步请求库
(我比较喜欢用axios)挂载到vue原型上:javascript
// 通常是./src/mian.js // 这里为了方便理解就直接引入axios,实际使用,咱们能够先用axios封装一个异步请求模块 // 在模块里作一些拦截或者处理,而后再导入这个模块。具体作法看 import axios from 'axios' import Vue from 'vue' import App from './App' // 为全部Vue实例添加一个post模块,能够在vue实例中直接使用this.post Vue.prototype.post = axios new Vue({ el: '#app', components: { App }, template: '<App/>' })
这了是prototype就是咱们所说的原型,那什么是原型呢? 咱们看看MDN给的解释vue
当谈到继承时,JavaScript 只有一种结构:对象。每一个对象都有一个私有属性(称之为 [[Prototype]]),
它指向它的原型对象(prototype)。该 prototype 对象又具备一个本身的 prototype ,
层层向上直到一个对象的原型为 null。根据定义,null 没有原型,并做为这个原型链中的最后一个环节。
视乎看起好有点拗口,不要紧,我用本身的话总结了一下java
1.prototype其实就是存在于对象中的一个特殊的对象,你能够把它理解为对象的一个属性或方法,
如 a.prototype,看起来是否是很像对象a的一个属性呢?2.每一个对象都有一个prototype,除了nullios
那这个prototype是干吗的呢? 其实回头看看上面关于vue的代码就知道了,
prototype最主要的做用就是该原型所属对象的全部实例,都能共享prototype里的属性和方法
上面的代码中,经过向Vue.prototype中添加一个post方法,而后就能够在全部vue实例中使用该方法,就是个简单的实践。git
咱们回头看看 【JS中建立对象的方法】里面的原型模式github
function Student(){} // 声明一个空函数 Student.prototype.name = 'xiaohong' Student.prototype.age = 17 Student.prototype.gender = 'f' Student.prototype.study = fucntion() { console.log('我在学习...')}
咱们先定义了一个空函数,注意:这个时候,咱们并无认为的给函数添加一个prototype属性/方法,
而Student却自动有了prototype,而后咱们往prototype里面添加了name,age,gender属性和study方法,
而后咱们用new实例化2个Student对象出来chrome
var studentA = new Student() console.log(studentA.name) // xiaohong console.log(studentA.age) // 17 console.log(studentA.gender) // f studentA.study() // 我在学习... var studentB = new Student() console.log(studentB.age) // xiaohong console.log(studentB.name) // 17 console.log(studentB.gender) // f studentB.study() // 我在学习...
上面的例子能够看出,对象的prototype里面的属性和方法,在该对象的全部实例里面,都是共享的
那若是咱们想要让实例对象有本身的属性/方法,该怎么办呢? 好比,我想让studentB的名字是'lili',
很简单,直接在实例对象上添加该属性/方法:axios
studentA.name = 'lili' studentA.study = function () { console.log('我在偷懒') } console.log(studentA.name) // lili console.log(studentB.name) // xiaohong studentA.study() // 我在偷懒 studentB.study() // 我在学习...
能够看出,studentA的属性/方法被改变的时候,studentB没有对应的跟着改变,这是为何呢?
不是说好的全全部prototype里的属性/方法都是共享的吗?事实上,prototype里的属性/方法,确实是共享的,
问题出在咱们是在实例对象上赋值,因此这个属性/方法,是属于实例的,而不是属于prototype的,prototype的属性,
也没法在实例对象上写入,也就是说,实例对象和prototype上,同时存在了 name属性和study方法,那么,
为何 studentA 和 studentB 访问到的属性/方法 会不同呢? 其实每次访问一个属性/方法的时候,
都会先从实例对象开始查找,若是实例上有,就直接返回,若是实例上没有,就继续往prototype上查找,有就返回,
若是prototype上还有 prototype,那么还会继续网上查找,直到原型链的最顶层。若是都没有查到,则会返回undefined。浏览器
那么新的问题来了,咱们该如何判断一个属性,是属于实例自己的,仍是属于prototype的? 答案是hasOwnProperty方法,
hasOwnProperty方法能够检测到实例对象里面有没有给定的属性,该方法只能检测到实例里面的属性,检测不到prototype上的app
studentA.hasOwnProperty('name') // true studentB.hasOwnProperty('name') // false
那若是想同时查找实例对象和原型对象prototype呢?咱们能够用 in 操做符
'name' in studentA // true 'name' in studentB // true
有了这2个方法,咱们就能够组合起来判断属性是属于实例仍是原型了。
这里总是说到实例,不得不提一下, 实例对象虽然是构造函数“构造”出来的,可是其实跟构造函数没有直接联系,
实例对象内部指向的是构造函数的prototype(原型)。 实例跟构造函数的一个间接关系是
实例.prototype.constructor --> 构造函数
关于原型的介绍就到这里,有须要更深刻的童鞋,建议去读一下javascript权威指南。里面关于原型的介绍比我这详细。
下面列几个javascript权威指南里面介绍的关于原型的方法
Object.getPrototypeOf(studentA) // Student.prototype
部分浏览器(chrome,safari,firefox)也支持一个属性 __proto__
studentA.__proto__ == Student.prototype
指定实例对象
的原型Student.prototype.isPrototypeOf(studentA) // true