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

舒适提示:做者的爬坑记录,对你等大神彻底没有价值,别在我这浪费生命javascript

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

你对象还有原型?

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

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是对象的一个属性呢?仍是从头了解吧this

因此你原型是啥?

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

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

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

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

用直白的话描述一下,在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属性中我想这就是爱情吧

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

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

话说回来

绕了这么大一圈,还没忘咱们为何要研究原型吧,经过原型的方式建立对象的属性和方法,就能够利用同种对象类型的不一样实例拥有想用的原型对象这一特性,避免重复建立,而且在修改原型对象的某个属性后,也能够经过原型链影响到其余全部相关对象上。

举个例子

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

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

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

相关文章
相关标签/搜索