javascript:原型、原型链学习总结

原型、原型链的学习总结

一、 写在前面

学习JavaScript有一段时间了,从基础开始,第一次写学习总结,一定坚持写完,相信自己能够将关于原型、原型链的学习总结写好。

二、原型、原型链的概念

  • 原型:原型分为显示原型属性和隐式原型属性
    ① 显示原型属性(prototype): 函数定义时自动添加的空Object对象,通过prototype可以向原型中添加方法;
    ②隐式原型属性(__ proto __ ):实例对象创建时自动添加,值为构造函数的prototype值,ES6之前通过__ proto __只能查看原型中的方法。
  • 原型、原型链的作用:
    ①同一个构造函数创建的实例对象共享方法;
    ②原型链是js实现继承的主要方法。
function Person(name){  //创建Person构造函数
                this.name=name;
            }
            Person.prototype.sayName=function(){
                console.log(this.name);
            };
            var p=new Person("Tom");//创建Person的实例对象
            //实例对象的隐式原型属性等于构造函数的显示原型属性
            console.log(Person.prototype===p.__proto__);    //true       

  • 原型链:构造函数 → prototype属性 → 原型对象 ← __ proto __ 属性 ← 实例对象形成一个原型链 ,通过构造函数中的prototype属性向原型中添加方法,通过实例中的 __ proto __ 属性查看原型中的方法。

三、用案例理解原型、原型链

  • 案例一
function Person(name,age){//创建Person构造函数,并添加name和age两个属性
                this.name=name;
                this.age=age;
            }
            Person.prototype.sayName=function(){//通过prototype向Person的原型中添加sayName方法
                console.log(this.name);
            };
            Person.prototype.sayAge=function(){//通过prototype向Person的原型中添加sayAge方法
                console.log(this.age);
            };
            var p=new Person("Tom",20);//创建Person的实例对象
            var p0=new Person("Jone",18);
            p.sayName();//通过实例对象p分别调用sayName和sayAge方法
            p.sayAge();
            p0.sayName();
            p0.sayAge();

画图分析代码

案例一

①2、4号箭头表示创建构造函数,并通过prototype向构造函数的原型中添加sayName、sayAge方法;
②1、3号箭头和5、6号箭头分别表示通过构造函数Person创建的实例对象p和p0,p和p0的__ proto __ 属性默认指向构造函数Person的原型对象,此时p和p0共享sayName方法和sayAge方法;
③由上述实例对象的隐式原型值等于构造函数的显示原型值

  • 案例二
 function Person(name){
                this.name=name;
            };
            var p1=new Person("Tom");
            Person.prototype={//修改Person原型的指向
                sayName:function(){
                    console.log(this.name);
                }
            };
            var p2=new Person("Jone");
            p2.sayName();//Jone
            p1.sayName();//Uncaught TypeError: p1.sayName is not a function

画图分析代码

案例二
①3、4号箭头表示创建Person构造函数,Person的原型指向一个空的Object对象;
②1、2号箭头表示通过Person创建一个实例对象p1,p1的__ proto __指向构造函数的原型对象;
③6号箭头表示修改了Person原型的指向切断了与原对象的引用关系(擦除4号箭头),并在新的对象中添加了sayName方法;
④5、7号箭头表示通过Person创建一个实例对象p2,p2的 __ proto __ 指向含有sayName方法的原型;
⑤代码11行通过p2访问sayName方法是可以执行的,代码12 行通过p1访问sayName方法是会报错的。
⑥由上述尽管我们可以通过prototype修改原型的指向,尽量避免这样做,可能会产生错误。

  • 案例三

function Father(name,age){//创建Father函数,添加name、age属性
                this.name=name;
                this.age=age;
            }
            Father.prototype.sayHello=function(){//向Father函数的原型中添加sayHello方法
                console.log("Hello");
            };
            function Son(name,age){//创建Son函数
                Father.call(this,name,age);//利用call方法做假继承
            }
            Son.prototype=new Father();//将Son的prototype值设为Father对象的一个实例,实现继承
            Son.prototype.constructor=Son;//修正Son的构造函数指向Son
            var s=new Son("Tom",20);//创建Son的实例对象
            s.sayHello();//Hello   实例s可以调用sayHello方法,说明Son继承了Father中的属性
            console.log(s);

①这是利用原型实现对象继承的案例;
②代码第10行利用call方法在Son的作用域内执行Father中的代码,这里是一个假继承,同时简化了代码;
③代码第12行将Father的一个实例对象赋值给Son的原型,这一步真正的实现了对象的继承;
④代码第13行修正了Son构造函数的constructor的指向为Son;
⑤代码第15行通过实例s调用sayHello方法正常执行,验证了继承关系的存在。

  • 案例四
    先上图祭祖


    原型链
function Foo(){}
            var f1=new Foo();
            var o1=new Object();
            console.log(f1.__proto__===Foo.prototype);//true
            console.log(Foo.prototype.__proto__===Object.prototype);//true
            console.log(Foo.__proto__==Function.prototype);//true
            console.log(Object.__proto__===Function.prototype);//true
            console.log(Function.__proto__===Function.prototype);//true
            console.log(Function.prototype.__proto__===Object.prototype);//true
            console.log(o1.__proto__===Object.prototype);//true
            console.log(Object.prototype.__proto__===null);//true
            console.log(Function.__proto__===Function.prototype);//true

①代码第8行Function. __ proto __ =Function.prototype,由此可知Function是构造函数也是实例;
②代码第11行Object.prototype.__ proto __=null,由此可知Object显示原型的隐式原型为空;
牢记这张祭祖的图

四、总结

①原型让同一个构造函数创建的实例共享方法;
②通过构造函数中prototype属性向原型中添加方法;
③通过实例的 __ proto __ 属性查看原型中的方法;
④实例对象的隐式原型值等于构造函数的显示原型值;
⑤尽量避免修改prototype属性的指向,这样可能会产生错误;
⑥原型是实现对象继承的主要方法,详看案例三,特别注意需要修正被继承对象的constructor的指向;
⑦Function既是构造函数,也是实例。

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

推荐阅读更多精彩内容