资讯专栏INFORMATION COLUMN

javascript对象不完全探索记录04:小伙子,你对象咋来的?中篇 - 现出你的原型!

trigkit4 / 2829人阅读

摘要:译者注根据定义,没有原型,并作为这个原型链中的最后一个环节。由于这个属性不标准,因此一般不提倡使用。中用函数获得一个对象的。

温馨提示:作者的爬坑记录,对你等大神完全没有价值,别在我这浪费生命

在上一篇博文javascript对象不完全探索记录03:小伙子,你对象咋来的?上篇,中大概说了说在js中,比较好理解的对象创建方式,分别是直接定义/字面量,和调用构造函数

你对象还有原型?

在一众博文及书中,有一个高级/不好看明白的方式,比上面这两种更收到推崇,那就是大名鼎鼎的原型方式,看到这个词,我表示不是我谦虚,是真懵逼,啥原型,什么原型,谁的原型?现看看别人给的例子

function Car() {
}

Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.showColor = function() {
  alert(this.color);
};

var oCar1 = new Car();
var oCar2 = new Car();

源自ECMAScript 定义类或对象 - W3school

别说,还真有那么点眼熟,这种对象名称,后面跟一个prototype的写法,一直以来是我一个重要懵逼来源,话说这词,不就是原型的意思吗?

prototype
英 [ˈprəʊtətaɪp] 美 [ˈproʊtətaɪp]
n.
原型,雏形,蓝本

哈,在这等着我呢,其实认真一看这句Car.prototype.color = "blue";的语法意思是给Carprototypecolor赋值,翻译一下就是给Car的原型中的color属性赋值,所以说是不是能理解为原型也就是prototype是对象的一个属性呢?还是从头了解吧

所以你原型是啥?

提到原型,就不能不提到javascript中的一个重要的懵逼概念 - 原型链

每个对象都有一个私有属性(称之为 [[Prototype]]),它持有一个连接到另一个称为其 prototype 对象(原型对象)的链接。该 prototype 对象又具有一个自己的原型,层层向上直到一个对象的原型为 null。(译者注:Object.getPrototypeOf(Object.prototype) === null; // true)根据定义,null 没有原型,并作为这个原型链中的最后一个环节。

源自MDN Web docs - Web技术文档/javascript/继承与原型链

这段话我注意到的有几个关键词:每个对象,私有属性,链接,层层向上

用直白的话描述一下,在javascript中任何一个对象都有一个叫做原型对象的对象,这个原型对象就是传说中的prototype,而指向原型对象的链接/指针/箭头/->/都存在对象内部的一个私有属性中[[Prototype]]中(*见注1)

也就是说对象的[[Prototype]]中并不是直接存了原型对象,而是存着一个指向原型对象的链接//这也就使得其是动态的-待研究

由此可以想到的,既然每个对象都有原型对象,每个对象也都可以作为其他对象的原型对象,那么就会形成一个由[[Prototype]]属性组成的链,这就是传说中的原型链了,而利用原型链,对象可以访问其原型对象的属性及方法

*注1
[[prototype]]是一个隐藏属性,但很多浏览器都给每一个对象提供.__proto__这一属性,这个属性就是上文反复提到的该对象的[[prototype]]。由于这个属性不标准,因此一般不提倡使用。ES5中用Object.getPrototypeOf函数获得一个对象的[[prototype]]。ES6中,使用Object.setPrototypeOf可以直接修改一个对象的[[prototype]]

源自知乎问题 - js中__proto__和prototype的区别和关系? - 知乎用户的回答

换句话说,任何一个对象,都是在另一个被叫做原型对象的基础之上被创建出来的,这也就是所谓的原型了

整这么麻烦干嘛?

就像我们知道的,在学园都市里有好多少女们/对象,她们各自有不同名字,头发颜色,以及超能力,她们可以展现自己的超能力,我们建立一个名叫GirlFriend()的构造函数,来记录记录

function GirlFriend(name,hairColor,power){
    this.name = name;
    this.hairColor = hairColor;
    this.showPower = function(){
        console.log(power)
    }
}

记录/实例化炮姐和黑子

var mikoto = new GirlFriend("Mikoto","brown","BiliBili");
var kuroko = new GirlFriend("Kuroko","black","Telesport");
mikoto.showPower();//BiliBili
kuroko.showPower();//Telesport

直到这里一切都很正常,但是却发现炮姐不是一个人!有人处于某种原因克隆了好多炮姐,如何记录炮姐的妹妹们呢,我们创建一个构造函数Sister()用于记录炮姐的妹妹们

function Sister(level,number){
    this.level = level;
    this.number = number;
    this.showLevel = function(){
        console.log(this.level);
    }
}

但是妹妹们也是由炮姐克隆而来的啊,炮姐有的属性她们也都应该有啊,怎么办,直接在Sister()里新增属性吗?太麻烦了而且这就跟炮姐没关系了,炮姐哪天要是在GrilFriend()里多录入一个新的属性,在Sister()也还得继续添加。
就没有什么更好的方式吗,答案是肯定的

于是我们就用炮姐这个实例对象作为原型对象

Sister.prototype = mikoto;

在这里Sister.prototype指的是由构造函数Sister()生成的实例对象所对应的原型对象
说白了,上面这行代码的的作用就是让所有由Sister()生成的实例对象的原型对象都是mikoto,我们来试试结果

var sister = new Sister(3,"0001");
sister.showPower();//BiliBili
sister.showLevel();//3

到此为止一个拥有3级BiliBili能力的妹妹就诞生了

而且其整个的执行过程也与我们对的理解一样,是从内到外,从这儿到那儿的

GirlFriend.prototype.age = 14;
console.log(sister);//见截图
console.log(sister.age)//14


从结果中可以看出,sister对象内部并没有age属性,在sister对象的原型对象mikoto中也没有age属性,但是在mikoto的原型对象中包含age属性并且有值,所以sister对象就顺着原型链一路找到了第一个age属性

但其实sister的因为是被克隆出来的所以只有1岁而已

sister.age = 1;
console.log(sister);//见截图
console.log(sister.age)//1


从运行结果可以看出,sister对象内部有age属性,这个是sister原型链上第一个age属性,所以sister.age的值就取1
为由GirlFriend()实例化对象的原型对象增加属性age并赋值,看看sister.age

能在说细点吗

在上文代码和截图中出现了两个和prototype相关的词,prototype和_proto_,这俩货是干啥的?
其实上文提到了,构造函数Foo()的prototype属性指的就是这个构造函数所对应的原型对象,其实就是通过Foo()创建的对象的原型对象,所以prototype是构造函数所具有的一个属性
而_proto_属性是对应对象所说的,见上文注1所说,举个例子

sister.__proto__.age = 1
console.log(mikoto.age);//1
console.log(kuroko.age);//14
sister.__proto__.__proto__.age = 1
console.log(kuroko.age);//1

正如例子中表现的,对象可以通过_proto_属性获得自己的原型对象,以及原型链上每一个对象

在截图中的原型对象中,还存在一个constructor的属性,这个属性指向的就是这个原型对象所对应的构造函数,也就是那个构造出原型对象为该对象的函数,一句话概括就是构造函数和其对应的对象互相拥有彼此,构造函数将对象放在prototype属性中,对象将构造函数放在constructor属性中我想这就是爱情吧

这里再放一张图,就能更清除解释他们之间的关系了

源自知乎问题 - js中__proto__和prototype的区别和关系? - doris的回答

话说回来

绕了这么大一圈,还没忘我们为什么要研究原型吧,通过原型的方式创建对象的属性和方法,就可以利用同种对象类型的不同实例拥有想用的原型对象这一特性,避免重复创建,并且在修改原型对象的某个属性后,也可以通过原型链影响到其他所有相关对象上。

举个例子

GirlFriend.prototype.sayHello = function(){
    console.log("Ohayo!")
}
kuroko.sayHello();//Ohayo!
sister.sayHello();//Ohayo!

并且说到底她们执行的都是同一个sayHello()

关于原型这块概念相对复杂,还设计嵌套,相互引用等等深坑,还是得先捋清楚再自己多做联系来理解和熟练运用啦
能看到这的估计都懵逼了

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

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

相关文章

  • javascript对象完全探索记录05:伙子对象来的?下篇 - 啥样的对象适合

    摘要:温馨提示作者的爬坑记录,对你等大神完全没有价值,别在我这浪费生命温馨提示续本文内容简单,发扬了潜入潜出的精神,请谨慎浪费时间温馨提示再续魔卡少女樱动画再开撒花经过前两篇文章的梳理对象不完全探索记录小伙子,你对象咋来的上篇对象不完全探索记 温馨提示:作者的爬坑记录,对你等大神完全没有价值,别在我这浪费生命温馨提示-续:本文内容简单,发扬了潜入潜出的精神,请谨慎浪费时间温馨提示-再续:《魔...

    hlcfan 评论0 收藏0
  • 从-1开始的ES6探索之旅02:伙子对象来的?续篇 - 对象班(class)里来的

    摘要:这是因为子类没有自己的对象,而是继承父类的对象,然后对其进行加工。 温馨提示:作者的爬坑记录,对你等大神完全没有价值,别在我这浪费生命温馨提示-续:你们要非得看,我也拦不住,但是至少得准备个支持ES6的Chrome浏览器吧?温馨提示-再续:ES6简直了,放着不用简直令人发指! 书接上回,即便是程序员,也还是能够通过自己的努力辛辛苦苦找到合适对象的,见前文《javascript对象不完全...

    incredible 评论0 收藏0
  • javascript对象完全探索记录03:伙子对象来的?上篇

    摘要:看着别人写的功能对,就直接拿过来用,写出来的代码臃肿到爆炸,满屏幕的的初级使用方式,运气好了能凑合跑起来,出了问题全脸懵逼,心中安慰自己一万遍我可是干设计的,但是既然打算好好整下就得从头开始看了。 温馨提示:作者的爬坑记录,对你等大神完全没有价值,别在我这浪费生命 首先,说实话,我对不起javascript,作为一个接触前端快10年的老前端(伪),一直发扬的是不求甚解的拿来就用主义。看...

    Pluser 评论0 收藏0
  • 回顾自己三次失败的面试经历

    摘要:站在这个时间点上,我对自己之前三次失败的面试经历做了一次深度回顾。关于我第三次面试失败的经历,依然是与轮播图有关。当然,这次思特奇面试之旅,最后也是以失败告终,这也是我离进大厂最近的一次。 showImg(https://segmentfault.com/img/bVYQuP?w=528&h=513); 前言 时间的齿轮已经来到了2017年的11月份,距离2018年仅仅还剩下不到两...

    DC_er 评论0 收藏0

发表评论

0条评论

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