javascript中的原型

javascript 中的原型

javascript 中,每个函数都可以有属性,prototype 就是每个函数都有的一个特殊属性,我们定义一个函数,然后查看其 prototype 属性:

> function dosomething() {}
> console.log(dosomething.prototype)

我们得到这样一个 prototype 对象:

{constructor: ƒ}

将这个查看这个对象详细内容:

[图片上传失败...(image-4985bb-1544192076037)]

其中,这两个成员又都可以详细展开:

[图片上传失败...(image-e996a7-1544192076037)]

现在,向 dosomething 添加一些属性和方法:

> dosomething.prototype.foo = "bar"
> dosomething.prototype.log = function() {console.log("this is a logging.")}

此时 dosomethingprototype 属性已与原先有所不同:

[图片上传失败...(image-d98f12-1544192076037)]

至此,我们大概了解的函数的 prototype 属性。

首先,会显示其包含的所有属性和方法;

其次是 constructor,是构造函数的原始定义,

最后是 __proto__ ,这个 __proto__ 到底是什么呢?请往下看

使用 new 创建对象实例:

var dosomeInstancing = new dosomething()

然后往上面添加一些属性,

dosomeInstancing.prop = "some value"

再看这个对象实例:

[图片上传失败...(image-80ce55-1544192076037)]

是否发现了一些端倪,这个对象实例有两个属性,其中一个是我们刚刚添加进去的 prop,另一个是其自带的 __proto__,而且这个 __proto__ 竟然就是 dosomething.prototype

到这里,我们可以基本说一下所谓原型链是什么东西了:

正如我们上面看到的,当我们访问 dosomeInstancing 这个对象实例的某个属性 prop
首先,浏览器会在这个对象本身查找是否有这个属性(比如我们刚刚添加的 prop),如果有,返回属性值

如果没有(即假如我们没有给 dosomeInstacing 添加 prop 属性),浏览器会在 dosomeInstancing__proto__ 属性(也就是 dosomething.prototype)中查找有没有这个 prop 属性,如果有,返回属性值

如果没有,浏览器则会继续在 dosomeInstancing 的属性 __proto____proto__ 属性(dosomeInstancing.__proto__.__proto__,即 dosomething.prototype.__proto__),看看它有没有这个属性,默认情况下,所有函数的 prototype__proto__ 就是 windows.Object.prototype。如果有,返回属性值。

如果没有,则继续在 dosomeInstancing.__proto__.__proto__.__proto__ 寻找有没有这个属性,然而这里有一个问题,dosomeInstancing.__proto__.__proto__ 就是 Object.prototype ,而其并没有 __proto__ 属性,代表原型链上所有 __proto__ 已找完,没有这个属性,会返回 undefined

[图片上传失败...(image-cc356f-1544192076037)]

prototype属性 继承成员被定义的地方

之前我们已看到,对象 dosomeInstancing 继承的属性和方法都是在 dosomething.prototype 中定义的,如果在实例本身没有属性和方法的情况下,访问是要从 dosomething.prototype 中寻找的。由此,我们可以说, prototype 属性是继承成员被定义的地方。

假如我给 dosomething (注意不是 dosomething.prototype)添加一个属性或方法,那么这个方法能否被通过 dosomething 实例化的对象所访问呢?

dosomething.outprop = "test"

[图片上传失败...(image-c70ae6-1544192076037)]

其实根据之前所述,我们已经能够想到问题的答案了,不能。

因为其不是定义在 dosomethingprototype中的,而prototype 属性是继承成员被定义的地方。

这些定义在 prototype 之外的属性和方法只能被构造函数本身所访问。

constructor

prototype 里有一个属性 constructor,是构造函数的原始定义:

[图片上传失败...(image-e579cc-1544192076037)]

既然其包含在构造函数的 prototype 属性内,那么通过构造函数实例化的对象也能继承这个属性,用以指向构造此实例的构造函数。

[图片上传失败...(image-985761-1544192076037)]

那么,就存在“另一种”创建对象实例的方法:

var person3 = new person1.constructor()

应用场景:当我们忘记或丢失了对象的原始构造函数的引用时,可以直接通过此种方式构建新的对象,或者通过:

[图片上传失败...(image-9d7ee-1544192076037)]

获得构造函数名

属性和方法定义的最佳位置

属性和方法可以定义在三个地方:

//FIXME:下面这句话有待商榷,outprop 也会出现在 dosomething.prototype.constructor 内

1 构造函数的定义中,这会直接包含在构造函数的 prototypeconstructor 内,如:

function Person(first, last) {
    this.name = [first, last],
    this.country = "China"
}

2 构造函数的 prototype 内,如之前前文定义的 foo 属性:

[图片上传失败...(image-1e9feb-1544192076037)]

3 构造函数 prototype 外

//TODO: 把三种方法定义之后属性出现的位置截图放上

[图片上传失败...(image-734832-1544192076037)]

由于前两者皆是定义在 prototype 上的,所以由此实例化的对象均能够继承这些属性和方法,而最后一种定义方法不是定义在 prototype 上,不能够被继承,只能由构造函数本身访问。

那么,如何选择属性和方法的定义位置呢?

常见的做法是:

在构造器中定义属性,在 prototype 中定义方法。

理由:# javascript 中的原型

javascript 中,每个函数都可以有属性,prototype 就是每个函数都有的一个特殊属性,我们定义一个函数,然后查看其 prototype 属性:

> function dosomething() {}
> console.log(dosomething.prototype)

我们得到这样一个 prototype 对象:

{constructor: ƒ}

将这个查看这个对象详细内容:

[图片上传失败...(image-acd5fe-1544192076037)]

其中,这两个成员又都可以详细展开:

[图片上传失败...(image-277dc7-1544192076037)]

现在,向 dosomething 添加一些属性和方法:

> dosomething.prototype.foo = "bar"
> dosomething.prototype.log = function() {console.log("this is a logging.")}

此时 dosomethingprototype 属性已与原先有所不同:

[图片上传失败...(image-1ecacf-1544192076037)]

至此,我们大概了解的函数的 prototype 属性。

首先,会显示其包含的所有属性和方法;

其次是 constructor,是构造函数的原始定义,

最后是 __proto__ ,这个 __proto__ 到底是什么呢?请往下看

使用 new 创建对象实例:

var dosomeInstancing = new dosomething()

然后往上面添加一些属性,

dosomeInstancing.prop = "some value"

再看这个对象实例:

[图片上传失败...(image-bfde0-1544192076037)]

是否发现了一些端倪,这个对象实例有两个属性,其中一个是我们刚刚添加进去的 prop,另一个是其自带的 __proto__,而且这个 __proto__ 竟然就是 dosomething.prototype

到这里,我们可以基本说一下所谓原型链是什么东西了:

正如我们上面看到的,当我们访问 dosomeInstancing 这个对象实例的某个属性 prop
首先,浏览器会在这个对象本身查找是否有这个属性(比如我们刚刚添加的 prop),如果有,返回属性值

如果没有(即假如我们没有给 dosomeInstacing 添加 prop 属性),浏览器会在 dosomeInstancing__proto__ 属性(也就是 dosomething.prototype)中查找有没有这个 prop 属性,如果有,返回属性值

如果没有,浏览器则会继续在 dosomeInstancing 的属性 __proto____proto__ 属性(dosomeInstancing.__proto__.__proto__,即 dosomething.prototype.__proto__),看看它有没有这个属性,默认情况下,所有函数的 prototype__proto__ 就是 windows.Object.prototype。如果有,返回属性值。

如果没有,则继续在 dosomeInstancing.__proto__.__proto__.__proto__ 寻找有没有这个属性,然而这里有一个问题,dosomeInstancing.__proto__.__proto__ 就是 Object.prototype ,而其并没有 __proto__ 属性,代表原型链上所有 __proto__ 已找完,没有这个属性,会返回 undefined

[图片上传失败...(image-a7a845-1544192076037)]

prototype属性 继承成员被定义的地方

之前我们已看到,对象 dosomeInstancing 继承的属性和方法都是在 dosomething.prototype 中定义的,如果在实例本身没有属性和方法的情况下,访问是要从 dosomething.prototype 中寻找的。由此,我们可以说, prototype 属性是继承成员被定义的地方。

假如我给 dosomething (注意不是 dosomething.prototype)添加一个属性或方法,那么这个方法能否被通过 dosomething 实例化的对象所访问呢?

dosomething.outprop = "test"

[图片上传失败...(image-ef4755-1544192076037)]

其实根据之前所述,我们已经能够想到问题的答案了,不能。

因为其不是定义在 dosomethingprototype中的,而prototype 属性是继承成员被定义的地方。

这些定义在 prototype 之外的属性和方法只能被构造函数本身所访问。

constructor

prototype 里有一个属性 constructor,是构造函数的原始定义:

[图片上传失败...(image-5de1cd-1544192076037)]

既然其包含在构造函数的 prototype 属性内,那么通过构造函数实例化的对象也能继承这个属性,用以指向构造此实例的构造函数。

[图片上传失败...(image-1793f8-1544192076037)]

那么,就存在“另一种”创建对象实例的方法:

var person3 = new person1.constructor()

应用场景:当我们忘记或丢失了对象的原始构造函数的引用时,可以直接通过此种方式构建新的对象,或者通过:

[图片上传失败...(image-d2d82a-1544192076037)]

获得构造函数名

属性和方法定义的最佳位置

属性和方法可以定义在三个地方:

//FIXME:下面这句话有待商榷,outprop 也会出现在 dosomething.prototype.constructor 内

1 构造函数的定义中,这会直接包含在构造函数的 prototypeconstructor 内,如:

function Person(first, last) {
    this.name = [first, last],
    this.country = "China"
}

2 构造函数的 prototype 内,如之前前文定义的 foo 属性:

[图片上传失败...(image-d31e37-1544192076037)]

3 构造函数 prototype 外

//TODO: 把三种方法定义之后属性出现的位置截图放上

[图片上传失败...(image-3494bb-1544192076037)]

由于前两者皆是定义在 prototype 上的,所以由此实例化的对象均能够继承这些属性和方法,而最后一种定义方法不是定义在 prototype 上,不能够被继承,只能由构造函数本身访问。

那么,如何选择属性和方法的定义位置呢?

常见的做法是:

在构造器中定义属性,在 prototype 中定义方法。

理由:

在构造器中定义属性,可以方便使用 this 关键字,因为在函数域内,如 this.name = this.first + this.last,如果放在 prototype 很难做到

prototype 中定义方法,之后可以方便地进行更新,添加,一致性更好,同时不同方法定义在不同代码块,可读性也更高。

两点说明

一、Object.create()

上一篇文章Javascript对象中提到过 Object.create()

var person2 = Object.create(person1);

create() 实际做的是从指定原型对象创建一个新的对象。这里以 person1 为原型对象创建了 person2 对象。在控制台输入:

person2.__proto__

返回对象 person1

二、构造函数的 proto

dosomething.proto 与 dosomething.prototype.proto 是不一样的,

当我们访问 dosomething.__proto__ 时:

[图片上传失败...(image-a80a88-1544192076037)]

发现也有内容返回,而根据前文所述,__proto__ 应该是对象实例所拥有的,或者是构造函数的 prototype 属性所拥有的属性。

那这里返回的究竟是什么呢?

说实话,在这块内容之前,我觉得自己整的挺明白的,但在这想了半天,我有点懵,我看看其他资料研究下。

__proto__ 是 Object 构造函数的自有属性,不会被继承,在 Object.prototype.constructor 中显示的都是自有属性,__proto__

Object.__proto__ 属性指向的是 Function.prototype,即 FunctionObject 的原型

Object.prototype__proto__ 属性

Object__proto__ 属性

参考链接

在构造器中定义属性,可以方便使用 this 关键字,因为在函数域内,如 this.name = this.first + this.last,如果放在 prototype 很难做到

prototype 中定义方法,之后可以方便地进行更新,添加,一致性更好,同时不同方法定义在不同代码块,可读性也更高。

两点说明

一、Object.create()

上一篇文章Javascript对象中提到过 Object.create()

var person2 = Object.create(person1);

create() 实际做的是从指定原型对象创建一个新的对象。这里以 person1 为原型对象创建了 person2 对象。在控制台输入:

person2.__proto__

返回对象 person1

二、构造函数的 proto

dosomething.proto 与 dosomething.prototype.proto 是不一样的,

当我们访问 dosomething.__proto__ 时:

[图片上传失败...(image-2a936-1544192076037)]

发现也有内容返回,而根据前文所述,__proto__ 应该是对象实例所拥有的,或者是构造函数的 prototype 属性所拥有的属性。

那这里返回的究竟是什么呢?

说实话,在这块内容之前,我觉得自己整的挺明白的,但在这想了半天,我有点懵,我看看其他资料研究下。

__proto__ 是 Object 构造函数的自有属性,不会被继承,在 Object.prototype.constructor 中显示的都是自有属性,__proto__

Object.__proto__ 属性指向的是 Function.prototype,即 FunctionObject 的原型

Object.prototype__proto__ 属性

Object__proto__ 属性

参考链接

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

推荐阅读更多精彩内容