原型与原型链

MDN解释:

JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。

方方解释:

所有对象都有 toString 和 valueOf 属性,那么我们是否有必要给每个对象一个 toString 和 valueOf 呢?
明显不需要。
JS 的做法是把 toString 和 valueOf 放在一个对象里(暂且叫做公用属性组成的对象)
然后让每一个对象的 __ proto __ 存储这个「公用属性组成的对象」的地址。
原型就是共有属性

公用属性(原型)

用String赋值的变量s1,她的__ proto __ 指向了String共有属性(原型),String的原型里面还有 __ proto __的原型指向Object共有属性,Object共有属性最后指向了null,结构图如下:


  • Numer的共有属性:Number.prototype
  • Object的共有属性:Object.prototype
  • String的共有属性:String.prototype
  • Boolean的共有属性:Boolean.prototype

上面的代码Object.prototype就是上边结构图的Object的共有属性(原型),
o1的__ proto __指向Object里的原型,所以是true

n1的下划线原型指向的是Number的原型,然后Number原型里面的下划线原型指向Object的原型,所以就可以写成

n1.__proto__.__proto__ === Object.prototype
或者:Number.prototype.__proto__ === Object.prototype


注意:prototype是浏览器自动生成的,你就算不写代码也有

上面的图当你什么代码也不写的时候,打开浏览器也会有一个window对象,而window对象里有Number、Object、String、Boolean这几个全局函数,又因为函数也是对象,所以他们再次将内容存放到一个堆里,又因为是函数所以有prototype的原型,分别指向自己对应的类型,而最后prototype也是一个对象,只要是对象就有__ proto __这个下划线的原型,通过他指向了Object公用属性。就拿Number这个全局函数来举例

上面没有执行任何操作,直接打印了Number这个函数,它里面的prototype就指向了Number的公用属性,而她的prototype下面还有一个下划线的原型指向了Object的公用属性。

上面的代码,var 后面的肯定是对象,new后面的是函数对象

对象的下划线原型指向该实例对象的构造函数的原型也就是说:

var n = new Object();
n.__proto__ === Object.prototype
//new后面的就是构造函数名,以new方法生成的函数就是构造函数

Object.prototype.proto ===null

对象由构造函数创建的

数组、函数、正则都是对象

对象的proto等于创建者的prototype

prototype上有个属性constructor 指向创建者(构造函数)

数组的构造函数是 Array

函数的构造函数是 Function(当构造函数作为对象时,这个构造函数的构造函数就是Function)

正则的构造函数是 RegExp

而String,Number,Boolean,Object,Function这几个是全局函数,所以它的构造函数就是Function,故指向Function.prototype:


这里最需要注意的是Function的构造函数就是Function,只有它的proto是指向自己的:


另外自己写的构造函数也是一样的,当构造函数作为对象时.__ proto __===Function.prototype

如:

function Person(name){
  this.name = name;
}
var person = new Person('wang')
Person.__proto__===Function.prototype  //true
//因为Person是一个函数,函数也是一个对象所以有__proto__的属性,而函数的构造函数是Function

另外判断一个对象的构造函数可以用
1.console.log(xxx.constructor),但是注意xxx只能是单独的对象就是xxx里面不可以接prototype或者__ proto __


第一个Function.constructor是可以正确判断的,但Function.prototype.constructor就不能,它显示的也是Function可实际上它的构造函数是Object。另外判断一个构造函数是什么其实上述方法并不可取,因为不排除有人为改变构造函数的可能,所以暂且只需记住就行,另外只要是(对象.prototype)或者(对象.__ proto __)作为对象的时候他们的构造函数都是Object(这里排除特例)
2.实例对象.constructor(构造器里的prototype始终指向构造函数本身)

实例对象的proto和构造函数中的prototype相等--->true
因为实例对象是通过构造函数来创建的,构造函数中有原型对象prototype
实例对象的proto指向了构造函数的原型对象prototype
只要是对象就有proto原型
又因为prototype也是对象,所以,prototype也有proto

原型(对象)、构造函数、实例、原型链

关系图如下:


1.构造函数:就是函数,名字首字母应该大写
function Foo(name,age){
  this.name = name
  this.age = age
  this.class = 'class-1'
  // return this // 默认有这行
}
2.实例对象:new 函数() => 实例
// 创建多个实例对象
var f1 = new Foo('zhangsan',21)// new 就是实例化的过程
var f2 = new Foo('lisi',22)
var f3 = new Foo('wangwu',23)
实例对象.__proto__ === 构造函数.prototype

实例对象.proto === 构造函数.prototype

描述 new 一个对象的过程
  • 创建一个新对象,它继承自构造函数Foo.prototype
  • 执行构造函数Foo。执行时,相应的参数会被传入,同时上下文 this,指向这个新实例。在不传递参数时,new Foo等同于new Foo()
  • 执行代码,即对 this 赋值(this.key = value)
  • 构造函数 Foo,return一个对象,那么这个对象会取代整个 new 出来的结果。如果构造函数没有return对象,那么 new 出来的结果,就是步骤1创建的新对象
3.原型对象:prototype,每个函数都有这个属性,也是用于扩展构造函数的
Foo.prototype.alertName = function(){
  alert(this.name)
}

f1.printName = function(){
  console.log(this.name)
}

f1.printName()
f1.alertName()

构造器:constructor

在原型对象(prototype)下有个constructor属性,它的作用是指向声明的那个函数(就是构造函数)

Foo.prototype.constructor === Foo返回true
原型5条规则:
  1. 所有的引用类型(对象、函数、数组),都具有对象特性,即可自由扩展属性(除null以外)
  2. 所有的引用类型(对象、函数、数组),都有一个__ proto __属性,属性值是一个普通对象(除null以外)—— 隐式原型
  3. 所有的函数都有一个prototype属性,属性值是一个普通对象 —— 显示原型
  4. 所有的引用类型(对象、函数、数组),__ proto __属性值指向(全等)它的构造函数的prototype属性值
  5. 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__ proto __中寻找,(也就是去它的构造函数的 prototype)
4.原型链
var obj = { name: 'obj' } 

在我们没对obj进行任何操作之前,obj就已经有toString()方法,那么toString()方法是怎么来的哪?


答:这跟 proto 有关。

当我们「读取」 obj.toString 时,JS 引擎会做下面的事情:

  1. 看看 obj 对象本身有没有 toString 属性。没有就走到下一步。
  2. 看看 obj.__ proto __ 对象有没有 toString 属性,发现 obj.__ proto __ 有 toString 属性,于是找到了,就会退出
    所以 obj.toString 实际上就是第 2 步中找到的 obj.__ proto __.toString。
    可以想象,
  3. 如果 obj.__ proto __ 没有,那么浏览器会继续查看 obj.__ proto . proto __
  4. 如果 obj.__ proto . proto __ 也没有,那么浏览器会继续查看 obj.__ proto . proto . proto __
  5. 直到找到 toString 或者 __ proto __ 为 null。
    上面的过程,就是「读」属性的「搜索过程」。

而这个「搜索过程」,是连着由 __ proto __ 组成的链子一直走的。

这个链子就叫原型链。

通过下图我们可以更好的理解:

典型例题:
function Fn(){
    this.a = function(){
        console.log(1)
    }
}
Fn.prototype.a = function(){
    console.log(2)
}
new Fn().a()  //1

上面的代码先从实例对象本身开始搜索有没有a这个方法,因为本身就有所以直接退出搜索
参考文章:什么是 JS 原型链?

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

推荐阅读更多精彩内容