JavaScript 原型对象

JavaScript是一种基于对象的语言,可以说万物皆对象。
  特别说明:基于对象也好,面向对象也好实际上都是以对象的概念来编写程序,从本质上并无区别。
  JavaScript没有类这个概念,它继承机制是基于原型,产生原型链的模式,而不是其他语言的类。因此要理解JavaScript的继承机制,需要更深入了解原型对象的概念。

对象
  JavaScript中,对象是有区别的,分为普通对象和函数对象,Object、Function是JS自带的函数对象,function定义方式本质上还是new Function方式。(函数对象都是通过Function来实例化的)

        <script type="text/javascript">
            function f1(){};
            var f2 = function(){};
            var f3 = new Function('str', 'console.log(str)');
            var o3 = new f1();
            var o1 = {};
            var o2 = new Object();
            
            console.log(typeof Object);//function
            console.log(typeof Function);//function
            console.log(typeof o1);//object
            console.log(typeof o2);//object
            console.log(typeof o3);//object
            console.log(typeof f1);//function
            console.log(typeof f2);//function
            console.log(typeof f3);//function
        </script>

在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object 也都是通过 new Function()创建的。

对象继承
  Brendan Eich参考C++和Java,做了简化设计,将new命令引入到JavaScript中,new后面跟对象的构造函数,用来创建对象,缺点:无法共享方法和属性。

比如,在DOG对象的构造函数中,设置一个实例对象的共有属性species。(函数也是一个对象)
function DOG(name) {
  this.name = name;
  this.species = '犬科';
};
用上面**函数对象**生成两个实例对象
var dogA = new DOG('大毛');
var dogB = new DOG('二毛');

这两个对象species属性是独立的,修改其中一个,不会影响到另一个。
dogA.species = '猫科';
alert(dogB.species);//犬科
每个实例对象都有自己的属性和方法的副本,这不仅无法做到资源共享,也极大的资源浪费。

Brendan Eich决定为构造函数设置一个prototype属性。这个属性包含一个对象,所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就在构造函数里面。实例对象一旦创建,将自动引用prototype对象的属性和方法(也就是__proto__)。也就是说,实例对象的属性和方法,分成两种,一种是本地的,另一种是引用的。

species属性放在prototype对象里,是两个实例对象共享的。只要修改了prototype对象,就会同时影响两个实例对象。
DOG.prototype.species = '猫科';
alert(dogA.species);//猫科 (dogA的__proto__指向DOG.prototype)
alert(dogB.species);//猫科

由于所有实例对象共享一个prototype对象,那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像"继承"了prototype对象一样。

原型prototype
  在JavaScript中,每当定义一个对象(函数)时候,对象都会包含一些预定的属性。其中函数对象的一个属性就是原型对象prototype(原型对象还有constructor属性(指向构造函数对象))。普通对象没有prototype,但是有__proto__属性。(比如实例化、字面量的对象)(指向其原型链)

原型对象其实就是普通对象(Function.prototype除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性))。
function f1(){};
console.log(f1.prototype);//f1{}  (f1{}表示普通对象)
console.log(typeof f1.prototype);//object
console.log(typeof Function.prototype);//function,这个特殊
console.log(typeof Object.prototype);//object
console.log(typeof Function.prototype.prototype);//undefined
打印关于f1函数对象的相关信息

原型链
  JS在创建对象(不论普通对象还是函数对象)的时候,都有一个叫做__proto__([[ prototype ]] )的内置属性,用于指向创建它 的 函数对象的原型对象prototype。
  (ps:函数对象来自Function对象,字面量对象来自Object对象,实例对象来自创建它的函数对象-->等等类似)

var person = function(name) {
    this.name = name;
};
person.prototype.getName = function() {
    return this.name;
}
var gz = new person('gongzi');
gz.getName();//gongzi

以上面的例子为例:

console.log(gz.__proto__ === person.prototype) //true

同样,person.prototype对象也有__proto__属性,它指向创建它的函数对象(Object)的prototype
console.log(person.prototype.__proto__ === Object.prototype) //true

继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null
console.log(Object.prototype.__proto__) //null

我们把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。
如图.png
function Fruits(name) {
    this.name = name;
}
Fruits.prototype.colour = 'red';
Object.prototype.taste = '甜';
var fruits = new Fruits('苹果');
console.log(fruits);//打印实例对象(普通对象)

var Game = {
    name:'王者荣耀'
};
Object.prototype.type = '竞技';
console.log(Game);//打印字面量对象(普通对象)

console.log(Fruits.__proto__);//打印 创建它 的 函数对象 的原型对象,结果function () {}
console.log(Fruits.constructor);//可以打印出构造函数对象Function//Fruits.__proto__.constructor一样
Function对象作为一个函数,就会有prototype属性,该属性将对应”function () {}”对象。
alert(Fruits.__proto__ === Function.prototype);//true

前面有提到,原型对象属于普通对象。Function.prototype是个例外,它是原型对象,却又是函数对象,作为一个函数对象,它又没有prototype属性。
打印实例对象.png
打印字面量对象.png

constructor属性
  constructor 属性返回对创建此对象的函数的引用
  prototype对象有一个construction属性,默认指向prototype对象所在的构造函数。
  由于construction属性定义在prototype对象上面,意味着可以被所有实例对象继承。
  constructor属性的作用,是分辨原型对象到底属于哪个构造函数。

总结
1.原型和原型链是js实现继承的一种模式。
2.原型链的形成真正的是靠proto而非prototype。

访问原型对象的方法
获取实例对象的原型对象,有三种方法:
1.obj.construction.prototype或者C.prototype用于引用new C()创建的对象的原型对象
2.Object.getPrototypeOf(obj):是获取obj对象的原型对象的标准方法。
3.obj.proto:是获取obj对象的原型对象的非标准方法,每个对象都有的属性,可以在不支持Object.getPrototypeOf方法时作为权宜之计,proto是非安全的。
  上面三种方法第一种和第三种都不是很可靠。最新的ES6标准规定,proto属性只有浏览器才需要部署,其他环境可以不部署,obj.construction.prototype在手动改变原型对象时,可能会失效。

扩展

1.Object.__proto__ === Function.prototype//true
2.Function.__proto__ === Function.prototype//true
3. Function.prototype.__proto__ === Object.prototype//true
1.Object是函数对象,是通过new Funciton()创建,所以Object.__proto__指向Function.prototype。

2.Function也是对象函数,也是通过new Function()创建,所以Function.__proto__指向Function.prototype。

3.Function.prototype是个函数对象,理论上其__proto__应该指向Functuin.prototype,就是它自己,自己指向自己,没有意义。函数对象也是对象,给它设定根指向Object.prototype,Object.prototype.__proto__ === null,保证原型链能够正常结束。

Object.create()
  创建一个具有指定原型且可选择性地包含指定属性的对象。
Object.create(prototype, descriptors)
  这种创建对象的方式与上面所说略有差异,如果要查找原型链,按照原型对象的类型分析就可以。
  是使用第一个参数作为它们的原型。
prototype
  必需。要用作原型的对象。可以为 null,不继承任何对象。
descriptors
  可选。包含一个或多个属性描述符的 JavaScript 对象。
  “数据属性”是可获取且可设置值的属性。 数据属性描述符包含 value 特性,以及 writable、enumerable 和 configurable 特性。
使用方法可以参考网络上的这两篇,或自己百度,没时间细说了。
javascript一种新的对象创建方式-Object.create()
前端开发者进阶之ECMAScript新特性【一】--Object.create

参考文献:
Javascript继承机制的设计思想
JavaScript原型及原型链详解
JS原型、原型链深入理解

实在不懂就就就.............这样记住吧
  JS中所有函数的原型都是Function.prototype,所有对象原型链的终点指向Object.prototype

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

推荐阅读更多精彩内容