JS 中原型和原型链深入理解

首先要搞明白几个概念:

函数(function)

函数对象(function object)

本地对象(native object)

内置对象(build-in object)

宿主对象(host object)

函数

function foo(){

}

var foo = function(){

}

前者为函数声明,后者为函数表达式。typeof foo

的结果都是function。

函数对象

函数就是对象,代表函数的对象就是函数对象

官方定义, 在Javascript中,每一个函数实际上都是一个函数对象.JavaScript代码中定义函数,或者调用Function创建函数时,最终都会以类似这样的形式调用Function函数:var newFun = new Function(funArgs, funBody)

其实也就是说,我们定义的函数,语法上,都称为函数对象,看我们如何去使用。如果我们单纯的把它当成一个函数使用,那么它就是函数,如果我们通过他来实例化出对象来使用,那么它就可以当成一个函数对象来使用,在面向对象的范畴里面,函数对象类似于类的概念。

var foo = new function(){

}

typeof foo // object

或者

function Foo (){

}

var foo = new Foo();

typeof foo // object

上面,我们所建立的对象

本地对象

ECMA-262 把本地对象(native object)定义为“独立于宿主环境的 ECMAScript 实现提供的对象”。简单来说,本地对象就是 ECMA-262 定义的类(引用类型)。它们包括:

Object,Function,Array,String,Boolean,Number

Date,RegExp,Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError.

我们不能被他们起的名字是本地对象,就把他们理解成对象(虽然是事实上,它就是一个对象,因为JS中万物皆为对象),通过

typeof(Object)

typeof(Array)

typeof(Date)

typeof(RegExp)

typeof(Math)

返回的结果都是function

也就是说其实这些本地对象(类)是通过function建立起来的,

function Object(){

}

function Array(){

}

...

可以看出Object原本就是一个函数,通过new Object()之后实例化后,创建对象。类似于JAVA中的类。

内置对象

ECMA-262 把内置对象(built-in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者不必明确实例化内置对象,它已被实例化了。ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。

理清楚了这几个概念,有助于理解我们下面要讲述的原型和原型链。

prototype

prototype属性是每一个函数都具有的属性,但是不是一个对象都具有的属性。比如

function Foo(){

}

var foo = new Foo();

其中Foo中有prototype属性,而foo没有。但是foo中的隐含的__proto__属性指向Foo.prototype。

1foo.__proto__ === Foo.prototype

为什么会存在prototype属性?

Javascript里面所有的数据类型都是对象,为了使JavaScript实现面向对象的思想,就必须要能够实现‘继承’使所有的对象连接起来。而如何实现继承呢?JavaScript采用了类似C++,java的方式,通过new的方式来实现实例。

举个例子,child1,child2都是Mother的孩子,且是双胞胎。(虽然不是很好,但是还是很能说明问题的)

function Mother(name){

    this.name = name;

    this.father = 'baba';

}

var child1 = new Mother('huahua');

var child2 = new Mother('huihui');

如果有一天,发现孩子的父亲其实是Baba,那么就要对孩子每一个孩子的father属性。

child1.father ='Baba';

console.log(child2.father) // baba

也就是说修改了其中一个孩子的father属性不会影响到下一个,属性的值无法共享。

正是这个原因才提出来prototype属性,把需要共享的属性放到构造函数也就是父类的实例中去。

__proto__

__proto__属性是每一个对象以及函数都隐含的一个属性。对于每一个含有__proto__属性,他所指向的是创建他的构造函数的prototype。原型链就是通过这个属性构件的。

想像一下,如果一个函数对象(也成为构造函数)a的prototype是另一个函数对象b构件出的实例,a的实例就可以通过__proto__与b的原型链起来。而b的原型其实就是Object的实例,所以a的实例对象,就可以通过原型链和object的prototype链接起来。

function a(){

}

function b(){

}

var b1 = new b();

a.prototype = b1;

var a1 = new a();

console.log(a1.__proto__===b1);//true

console.log(a1.__proto__.__proto__===b.prototype) //true

console.log(a1.__proto__.__proto__.__proto__===Object.prototype) //true

如果要理清原型和原型链的关系,首先要明确一下几个概念:

1.JS中的所有东西都是对象,函数也是对象, 而且是一种特殊的对象

2.JS中所有的东西都由Object衍生而来, 即所有东西原型链的终点指向Object.prototype

3.JS对象都有一个隐藏的__proto__属性,他指向创建它的构造函数的原型,但是有一个例外,Object.prototype.__proto__指向的是null。

4.JS中构造函数和实例(对象)之间的微妙关系

构造函数通过定义prototype来约定其实例的规格, 再通过 new 来构造出实例,他们的作用就是生产对象.

function Foo(){

}

var foo = new Foo();

foo其实是通过Foo.prototype来生成实例的。

构造函数本身又是方法(Function)的实例, 因此也可以查到它的__proto__(原型链)

function Foo(){

}

等价于

var Foo= new Function();

而Function实际上是

function Function(){

    Native Code

}

也就是等价于

var Function= new Function();

所以说Function是通过自己创建出来的。正常情况下对象的__proto__是指向创建它的构造函数的prototype的.所以Function的__proto__指向的Function.prototype

Object 实际上也是通过Function创建出来的

typeof(Object)//function

所以,

function Object(){

    Native Code

}

等价于

var Object = new Function();

那么Object的__proto__指向的是Function.prototype,也即是

1Object.__proto__ === Function.prototype //true

下面再来看Function.prototype的__proto__指向哪里

因为JS中所有的东西都是对象,那么,Function.prototype 也是对象,既然是对象,那么Function.prototype肯定是通过Object创建出来的,所以,

1 Function.prototype.__proto__ === Object.prototype //true

综上所述,Function和Object的原型以及原型链的关系可以归纳为下图。

对于单个的对象实例,如果通过Object创建,

1var obj = new Object();

那么它的原型和原型链的关系如下图。

如果通过函数对象来创建,

function Foo(){

}

var foo = new Foo();

那么它的原型和原型链的关系如下图

那JavaScript的整体的原型和原型链中的关系就很清晰了,如下图所示

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

推荐阅读更多精彩内容