前端面试准备--5.原型链

*原型链(面向对象的一个基础)

1.创建对象有几种方法

    1、从结果上看这两种算是一类,写法不一样
       var o1 ={name:'o1'};//字面量对象--默认这个对象原型链指向Object
       var o2 = new Object({name:'o2'});  //通过new Object声明的一个对象
    
    2、使用显式构造函数创建对象(通过构造函数)
       var M = function(name){ this.name = name;};
       var o3 = new M('o3');
    
    3、Object.create方法创建
       //创建一个具有指定原型且可选择性地包含指定属性的对象
       var P ={name:'p'};
       
       //Object.create方法是把参数中这个对象作为一个新对象的原型对象赋给o4的,
       o4本身不具备这个属性的,通过原型链来连接这个原型对象的。(所以o4对象本身没有
       name这个属性,只能通过原型链来找name属性。)
       
       var o4 = Object.create(P);
       
       --o4.__proto__指向的就是P对象
       ------->o4.__proto__ ===P; //true
       
       o4创建出来是一个空对象,空对象本身没有name这个属性,它是在它的原型对象上。
                 
    ------>console
    -->o1 Object{name:"o1"};
    -->o2 Object{name:"o2"};
    
    -->o3 M{name:"o3"};
    
    -->o4 Object{} //空对象
       但是o4.name-->"p"
    Object.create方法创建的这个对象,是用原型链来连接的;

2.原型、构造函数、对象实例、原型链

    1.实例:
        只要是对象就是一个实例;
        
    2.构造函数:
        凡是通过new来操作后边这个函数,这个函数就是构造函数;
        (任何一个函数只要被new使用了,后面这个函数就可以被叫做构造函数。)
        构造函数可以使用new运算符来生成一个实例;构造函数也是函数;
        
        任何函数都可以用来当做构造函数,只要用new操作,立马就变成构造函数;
        不用new就是普通函数。
        
    3.原型对象
        函数都有一个prototype属性,在声明一个函数js自动加上去的属性,这个prototype
        指的就是原型对象;
        在声明一个函数,开始写function xxx,js引擎给这个函数自动增加一个属性,这个属性就是
        构造函数prototype属性,这个属性会初始化一个空对象,也就是这个原型对象。
    
    3.1.原型对象怎么区分是被那个构造函数所引用呢?   
        constructor 构造器
        原型对象中会有一个构造器,这个构造器会默认你声明的那个函数。
        
        eg:var M = function(name){ this.name = name; };
            var o3 = new M('o3');
            M是构造函数  o3是实例
            
        ---->console
        o3-->M{name:"o3"}
        
        M--->function(name){this.name = name;}
        
        M.prototype(原型对象)
            --->Object{ constructor:function(name); __proto__:Object}
            (是一个空对象,(原型对象)有constructor属性,这个属性指向了一个函数,这个函数就是构造函数。)
        
        M.prototype.constructor === M;//ture
        
        
        ----1.构造函数通过new和实例关联;
            2.构造函数的原型对象通过constructor和构造函数关联;
            3.**实例和原型对象是一个什么关系?(实例对象的__proto__这个属性引用的是M的原型对象;)
             o3.__proto__ === M.prototype ; //true
        
        
    4.原型链
        从一个实例对象往上找,构造这个实例的相关联的对象,然后这个关联对象再往上找,又有创造它的上一级的
        原型对象,以此类推,一直到Object.prototype 原型对象终止,这个链条就断了,也就是说Object.prototype
        属性是整个原型链的顶端,到那里就截止了。
        
        4.1.1原型链是通过什么来实现这个往上找的过程呢?
            通过prototype这个原型和__proto__属性来完成原型链的查找的;
            
        4.1.2原型对象和原型链之间起的什么作用?
        
        eg:构造函数中增加了很多属性和方法,实例是不是就可以共用这个东西了?
            当多个实例的时候,想去共用这个方法的时候,不能每个实例都copy一份,他们有相同的方法,可以存到一个共同的东西上,
            这个共同的东西就是原型对象。
            
        eg:var M = function(name){this.name=name;};
           var o3 = new M('o3');
           
         如果在this.name下面写this.say=function(){}方法,这样每个实例把这个东西都copy一份,占内存,没必要;
        
        4.2.1:原型链的功能
            通过在M的原型链上(原型对象上)增加方法以后,通过原型链的方式使这个对象可以找到这个原型对象的方法,实例也是可以
            拥有的,这就是js引擎做的原型链的基本功能;
            
        4.2.2原型的基本原理
            任何一个实例对象通过原型链找到它上面的原型对象,上面的方法和属性都是被实例所共享的。
        
        eg:M.prototype.say = function(){
            console.log('say hi');
        };
        var o5 = new M('o5');
        
        ------->console
        o3.say()---->say hi
        o5.say()---->say hi
        
    **原型链的工作原理:通过原型链的方式,找到原型对象,原型对象的方法是被不同的实例共有的。
        
    **按照js引擎分析的方式,在访问一个实例的时候,这个实例上有什么方法,在这个实例本身没找到这个方法和属性,它会往它的原型
    对象上找,通过__proto__上一级原型对象去找,如果它上一级对象还没有找到这个属性和方法,它会在它原型对象的基础上,在通过
    原型对象的__proto__,在往上一级查找,依次类推,直到找到Object.prototype,如果还没找到,原路返回,告诉它这个属性和方法没有
    找到、没有定义;如果在中间任一环节找到了,就会停止网上查找,直接返回这个方法;
    
       
总结:
    1.构造函数(函数)才会有prototype,对象没有prototype;
    2.只有实例对象有__proto__;
     函数既是一个函数也是一个对象,所以也会有这个属性。它的属性是:
     M.__proto__ ===Function.prototype;//true
     --->M的构造函数是Function;(M这个普通函数是Function这个构造函数的一个实例;)

4.3.实例被构造函数生成的,它怎么跟这个原型对象产生关联呢?
    构造函数的prototype这个属性,你修改这个属性,也就修改了实例所在上一级的原型对象。    

3.instanceof 的原理

    实例对象上有__proto__这个属性,实例对象的这个属性引用是它构造函数的原型对象(也就是找到的这个构造函数);
    构造函数有prototype这个属性,这个属性引用的原型对象,在往下走,实例对象的__proto__这个属性,其实是引用这个原型对象。
    
虽然实例对象是一个构造函数产生的,但是这个属性(实例对象的__proto__属性)和构造函数本身没有关联,它关联的是构造函数下面的
一个属性prototype所引用的原型对象。

原理:就是来判断实例对象的__proto__这个属性和构造函数的prototype这个属性是不是同一个引用。
(实例对象的.__proto__ )instanceof (构造函数的prototype;

判断这个实例对象是不是这个构造函数的实例的时候,其实判断的是实例对象下面的属性.__proto__与构造函数下的属性prototype是不是引用的同一个地址;
如果是,instanceof成立了返回true;如果不是返回false;

o3 instanceof M;//true
o3 instanceof Object;//true
--只要是在原型链上的构造函数都会被instanceof看成o3的一个构造函数;

03.__proto__ ===M.prototype;//true
M.prototype.__proto__ === Object.prototype; //true
(原型对象的__proto__指向的是Object的prototype,Object这个构造函数也会被instanceof看做是o3的一个构造函数)

o3.__proto__.constructor ===M;//true;o3是M这个构造函数直接生成的实例对象
o3.__proto__.constructor === Object; //false
---用constructor判断比用instanceof更加严谨;

**constructor来判断一个实例对象从严谨意义上是不是构造函数直接生成的实例对象,是用原型对象的constructor来构造,实例对象和构造函数是一个
桥梁关系,但constructor是放在prototype下的constructor属性来判断的。

4.new 运算符

    一个新对象被创建,它继承自(这个构造函数的原型对象)foo.prototype
            |
            |
    构造函数foo被执行,执行的时候,相应的传参会被传入,同时上下文(this)
    会被指定为这个新实例;new foo等同于new foo(),只能用在不传递任何参数的情况
            |
            |
    如果构造函数返回了一个“对象”,那么这个对象会取代这个new出来的结果,如果构造函数
    没有返回对象,那么new出来的结果为步骤1创建的对象(一般情况下构造函数不返回任何值,
    不过用户如果想覆盖这个返回值,可以自己选择返回一个普通对象来覆盖。当然,返回数组也会覆盖,因为数组也是对象。)

eg:
var M = function(name){
    this.name=name;
};

M.prototype.say = function(){
    console.log('say hi');
};

var o5 = new M('o5');


var new2 = function(func){

    //1.创建一个空对象,这个对象要继承这个构造函数的原型对象(空对象要关联构造函数的原型对象;)
    var o = Object.create(func.prototype);
    
    //2.执行构造函数
    var k = func.call(o);//call用来转移上下文(this),把这个上下文转成o对象
    
    //3.判断构造函数的运行结果是不是对象类型
    if(typeof k ==='object'){
        return k;
    }else{
        return o;
    }
 };
 
------------->console
--o6 = new2(M);
--->M{name:undefined} __proto__:object
o6 instanceof M;  //true
o6 instanceof Object; //true
o6.__proto_-.constructor === M; //true

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

推荐阅读更多精彩内容

  • 原型链是一种机制,指的是 JavaScript 每个对象都有一个内置的 __proto__ 属性指向创建它的构造函...
    劼哥stone阅读 4,383评论 15 79
  • 博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...
    _Dot912阅读 1,391评论 3 12
  • 如果有一天。我能忘掉全部
    ing11阅读 228评论 0 0
  • 天童美语
    Miau阅读 158评论 0 0
  • 按照女朋友的说法,我这是:剧毒 其实感觉没有烟瘾,以前只有跟朋友们出去玩,在他们的煽动下跟着他们一起抽。而且也不过...
    Forri阅读 170评论 0 0