资讯专栏INFORMATION COLUMN

JS中的原型对象

whlong / 3045人阅读

摘要:下面列几个权威指南里面介绍的关于原型的方法获取一个实例对象的原型才支持部分浏览器也支持一个属性判断一个构造函数是否是指定实例对象的原型

JS中的原型对象
白天写了一篇【JS中创建对象的方法】,写完以后感觉意犹未尽(实际情况是感觉原型那块内容没有交
代清楚),所以开这一篇继续聊聊关于JavaScript中的原型对象

相信用过vue的童鞋,都经常这样做,用Vue.prototype.xxx = xxx 把一个方法或者属性添加到Vue对象的原型上,
这样,我们在vue实例的任何地方,都可以用这个方法或属性了,我最喜欢用的,就是把异步请求库
(我比较喜欢用axios)挂载到vue原型上:

// 一般是./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: ""
})

这了是prototype就是我们所说的原型,那什么是原型呢? 我们看看MDN给的解释

当谈到继承时,JavaScript 只有一种结构:对象。每个对象都有一个私有属性(称之为 [[Prototype]]),
它指向它的原型对象(prototype)。该 prototype 对象又具有一个自己的 prototype ,
层层向上直到一个对象的原型为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。

视乎看起好有点拗口,没关系,我用自己的话总结了一下

1.prototype其实就是存在于对象中的一个特殊的对象,你可以把它理解为对象的一个属性或方法,
如 a.prototype,看起来是不是很像对象a的一个属性呢?

2.每个对象都有一个prototype,除了null

那这个prototype是干嘛的呢? 其实回头看看上面关于vue的代码就知道了,
prototype最主要的作用就是该原型所属对象的所有实例,都能共享prototype里的属性和方法
上面的代码中,通过向Vue.prototype中添加一个post方法,然后就可以在所有vue实例中使用该方法,就是个简单的实践。

我们回头看看 【JS中创建对象的方法】里面的原型模式

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对象出来

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",
很简单,直接在实例对象上添加该属性/方法:

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上的

studentA.hasOwnProperty("name")  // true
studentB.hasOwnProperty("name")  // false

那如果想同时查找实例对象和原型对象prototype呢?我们可以用 in 操作符

"name" in studentA    // true
"name" in studentB    // true

有了这2个方法,我们就可以组合起来判断属性是属于实例还是原型了。

这里老是说到实例,不得不提一下,实例对象虽然是构造函数“构造”出来的,但是其实跟构造函数没有直接联系,
实例对象内部指向的是构造函数的prototype(原型)。 实例跟构造函数的一个间接关系是
实例.prototype.constructor --> 构造函数

关于原型的介绍就到这里,有需要更深入的童鞋,建议去读一下javascript权威指南。里面关于原型的介绍比我这详细。

下面列几个javascript权威指南里面介绍的关于原型的方法

获取一个实例对象的原型 (ES5才支持)

Object.getPrototypeOf(studentA) // Student.prototype

部分浏览器(chrome,safari,firefox)也支持一个属性 __proto__

studentA.__proto__ == Student.prototype

判断一个构造函数是否是指定实例对象的原型

Student.prototype.isPrototypeOf(studentA) // true

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94160.html

相关文章

  • JS对象继承与原型

    摘要:此用来定义通过构造器构造出来的对象的原型,构造器内部的代码用来给对象初始化。 对象继承 VS 类继承 在 class-based 的面向对象的世界里,要出现对象,必须先有类。类之间可以继承,类再使用 new 操作创建出实体,父子对象之间的继承体现在父类和子类上。你不能说 对象 a 继承了对象 b,只能说 class A 继承了 class B,然后他们各自有一个实例a、b。 JS中实现...

    QLQ 评论0 收藏0
  • 你是否理解js的Object与Function与原型

    摘要:原型对象是由创建的,因此原型对象的构造函数是构造函数也可以是称为对象,原型对象也就继承了其生父构造函数中的数据,也同时继承了原型对象的数据。当然这条原型链中的数据,会被还是还是这类构造函数继承,但是不会被这些继承,他们不处于同一个链条上。 js中,Function的本质是什么?Object的本质又是什么?js中有几条原型链? showImg(https://segmentfault.c...

    itvincent 评论0 收藏0
  • 一次性搞懂js中的原型原型

    摘要:每个原型都有一个属性指向关联的构造函数由于实例对象可以继承原型对象的属性,所以实例对象也拥有属性,同样指向原型对象对应的构造函数。 showImg(https://segmentfault.com/img/remote/1460000017183104?w=1300&h=834); 构造函数:function Foo ( ) { }; 实例对象:let f1=new Foo; 谈到...

    Freeman 评论0 收藏0
  • JS对象(1)重新认识面向对象

    摘要:对象重新认识面向对象面向对象从设计模式上看,对象是计算机抽象现实世界的一种方式。除了字面式声明方式之外,允许通过构造器创建对象。每个构造器实际上是一个函数对象该函数对象含有一个属性用于实现基于原型的继承和共享属性。 title: JS对象(1)重新认识面向对象 date: 2016-10-05 tags: JavaScript 0x00 面向对象 从设计模式上看,对象是...

    superw 评论0 收藏0
  • JS对象随笔

    摘要:原型对象对象的原型对象实质上是对象的构造函数的原型对象。构造函数所有的对象都是通过构造函数实例化出来的。即一个对象,如果沿着原型链找下去,最终都会找到构造函数原型对象相互之间纠缠不休,你中有我,我中有你。 JS中的对象 JS中对象(若无特殊说明,本文中的对象都为对象实例,即使是空对象实例)可谓是一个核心的概念,纵观整个JS的数据结构如String、Number、Array、Boolea...

    Lin_YT 评论0 收藏0

发表评论

0条评论

whlong

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<