原型与原型链

ECMAScript规定全区对象叫做global,但是浏览器把window作为全局对象(浏览器先存在)window就是一个哈希表,有很多属性,window的属性就是全局变量。
window下面的属性分为两类,第一类是ECMAScript规定必须有的函数,第二类是私有的(浏览器专有,标准不一)。

简单类型与对象的区别:

//全局函数
//1.Number
var n = new Number(1)//创建一个Number对象
1与new Number(1)的区别是什么?看内存图
//2.String
var s = new String('hello')//创建一个Number对象
'hello'与new String('hello')的区别是什么?看内存图
//3.boolean
var b = new Boolean(true)//创建一个Number对象
true与new Boolean(true)的区别是什么?看内存图
//4.Object
var o1 = {}
var o2 = new Object()
o1和o2没区别

简单数据类型和通过new 构造函数创建的数据对象(除了对象)区别在于内存地址不同,前者存放在stack中,而后者存放在heap里。

image.png

将数值通过Number包装成对象,内存里面就有许多操作该数值的方法。但简单数据也可以调用这些办法,那为什么还需要将数值包装成对象呢?
答:历史原因,在发明JS时模仿JAVA声明数据(new关键字,满足老板需求),第二种可以直接声明var a =1。 由于第二种方法无法使用toString等方法(只有对象才能使用方法,简单数据类型不可以),创始人使用了一个妙计(临时转换)当写n.toString时,隐式的声明一个temp为 new Number(n),然后再调用n.toString的值为temp,再销毁temp数据。临时的转换,用完就销毁了。所以给简单数据类型加属性读取时将会报错,这种方法受到了开发人员的欢迎。
image.png

公有的属性藏在哪?

所有的对象都有toStringvalueOf属性,那么我们是否有必要给每个对象一个toStringvalueOf呢?
明显不需要(内存不允许),JS的做法是把toStringvalueOf放在一个对象里,暂且叫做公有属性组成的对象(原型)。

对象分为普通对象和函数对象,ObjectFunction是js自带的函数对象,每个对象都有原型(null和undefined除外)可以理解为对象的默认属性和方法。

字符串对象

通过new string()方法转换成的字符串对象是一个哈希,每一个字符对应相应的索引值,使用方括号或者charAt(索引值)来获取相对应的字符,charCodeAt(索引值)获取对应索引的值的编码。继承了String对象的方法。
获取一个数字对应的进制值使用toString()方法,如(100).toString(16)//64 可以将字符的编码转化为其他进制的编码

布尔值对象

image.png

简单数据类型false和布尔对象false在被转换时是不相等的。


image.png

为什么不相等?虽然两个对象都没有名字,但存放在heap中的地址值不同,自然不会相等,请牢记5个假值,对象经过布尔转换为真值。


image.png

结论:所有新声明的对象都是不相等的。除非将一个对象的地址值赋值给另一个变量。

Number String Boolean Object通过以上几种方式创建的对象都具有toStringvalueof方法,这两个方法哪里来的呢?如果在每个新生成对象里面都定义这两个方法太占内存。实现继承的方法:原型链

要清楚原型链,首先先弄清楚对象。

普通对象,有____proto____属性(指向其原型链),没有prototype属性。
原型对象,构造函数.prototype原型对象还有constructor属性指向构造函数对象
函数对象,通过new Function()创建的都是函数对象。用有prototype____proto____属性(指向原型对象)

原型链概念

ECMAScript中描述了原型链的机制,将原型链作为实现继承的主要方式。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。

在js中,每个对象都有一个指向它的原型对象的内部链接,这个原型对象又有自己的原型,直到某个对象的原型为null为止(也就是不再有原型指向),组成这条链的最后一环。这种一级一级的链接结构就称为原型链。

JS对象有一个指向一个原型对象的链,当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象原型的原型,依此层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

所有引用类型默认都继承了Object,而这个继承也是通过原型链实现的,所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。这也正是所有自定义类型都会继承toString()valueOf()等默认方法的根本原因,所有函数的原型最顶端都有一个最终的对象原型,存储着对象本身自带方法和属性,当调用实例上的toString()等方法时,实际上是调用的是保存在Object.prototype中的那个方法。


简单回顾一下构造函数、原型和实例之间的关系:每创建一个函数都有一个prototype属性指向通过该构造函数创建实例对象的原型对象,原型对象是包含特定类型的所有实例共享的属性和方法,都包含了一个指向构造函数的指针,而实例都包含一个指向原型对象的____proto____内部指针。

iSQ05n.jpg

iSQs2V.jpg

下面是一个简单的例子:

//原型链实例
//构造函数Animal
function Animal(){
    this.type = "animal"
}
//Animal构造函数定义原型方法
Animal.prototype.getType = function(){
    return this.type
}
//Dog构造函数
function Dog(){
    this.name = 'dog'
}
//Dog构造函数定义原型方法
Dog.prototype.getName = function(){
    return this.name
}
//Dog原型等于构造函数Animal实例(实现继承)
Dog.prototype = new Animal()
//构建新实例
var xiaohuang = new Dog()

实例、构造函数、原型之间的关系。

xiaohuang.__proto__ === Dog.prototype
Dog.prototype.__proto__ === Animal.prototype
Animal.prototype === Object.prototype
Object.prototype.proto === null
//总结:xiaohuang这个Dog的实例继承了Animal,Animal继承了Object
console.log(xiaohuang.type)//'animal'
console.log(xiaohuang.name)//'dog'

iSQHKO.jpg

iSQqqe.jpg

总结:
iSQXad.md.jpg

两个构造函数,将其中一个构造函数的实例赋值给另一个构造函数的原型,这样另一个原型就有了指向前面那一个构造函数的原型的指针(创建的实例也会有同样的原型链),查找属性和方法会根据原型链来进行搜索,先搜索实例,再搜索原型,最后是原型的原型.....,注意此时实例的constructor指向了最开始的构造函数,而不是创建实例的函数(为了代码的严谨,可以设置为创建此实例的函数)。实现的本质是重写原型对象,代之以一个新类型的实例。原型链继承不仅会继承原型上面的属性和方法,还会继承实例上的方法和属性。


Object原型对象,怎么让每个对象都指向这个共有属性?
答:每个对象都有一个__proto__属性指向了共有属性。

对象和数值对象:

var o1 = new Number(1);
var o2 =new Object(1);
o1===o2   //false
o1.toString()===o2.toString() //true

两个数值对象不相等,因为stack存放的heap地址值不同,但使用的toString函数是公共属性(Number的原型的属性),因此相等(new Object(1)自动转换成了数值对象)。

iSQMEd.png

Object()函数不加new操作符会根据传入的参数生成相应的数据类型的对象,对于Object函数来说,加不加new都是一样的效果。

String()函数不加new操作符是将你给定的参数变成string常量(基本类型,非对象),而加上new会生成String对象(复杂类型,字符串对象),除了Object函数以外,其他的标准库函数都是一样的效果。

数值的toString()方法和对象的toString()方法并不相等,因为前者可以加进制参数而且会被先搜寻到。

image.png

调用方法时,会经过一层一层的查找。Number String Boolean Object都有自己的共有属性,____proto____都是先指向了自己的共有属性,共有属性的__proto____再指向了对象。
image.png

如果对象的共有属性没有被引用的话,必将会被回收,object.prototype指向(引用)这个共有属性(原型)
image.png

当你声明一个对象时,JS引擎除了在栈内存里面存放一个hash之外,还将____proto____指向了你该有的共有属性(原型)。

不写代码就有prototype

在没有代码的时候,Number.prototypeObject.prototypeString.prototypeBoolean.prototype都引用了各自的共有属性(保证不被垃圾回收机制回收),是JS定义的,不可更改的。而你的对象____proto____则指向了对应数据类型的prototype

image.png

初始化数据类型里面还有一个Function.prototype,存储了函数的原型(共有方法),Function也是一个对象,Function.__proto__指向了Function.prototype,使用函数初始化对象时(new Function()),该函数对象的____proto____就指向了Function.prototype(因为Function是Object的构造函数),而Function.prototype里面的____proto____就指向了Object.prototype

image.png

继承方式:子类构造函数.prototype= new 父类构造函数 ,简单说就是将父类的实例赋值给子类的原型,这样子类的____proto____属性
目前组合继承用的最多,构造函数模式定义实例属性(不可共享),原型模式则定义方法和共享的属性。

现在你明白什么是原型和原型链了吗?:)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容