通过面试题去认识原型

            昨天又重新看了一下自己写的插件方面的文章再加上看了叶小钗博客中关于面试题的文章,找到了一个关于原型方面的题目,个人感觉很好,然后分析一下。


题目是:

var F = function(){};
Object.prototype.a = function(){};
Function.prototype.b = function(){};
var f = new F();


问:调用f.a( )和f.b( ) 能成功么?


答案:能调用f.a( )但是不能调用f.b( ); // 反正我一开始是没答出来的~ -。- 哈哈所以才会有这一篇文章,如果有高手可以不用往下看了,不过也可以看看我的理解可取么~


然后就请跟着我的思路,Follow me!

"预习":一般来说我们需要有一定的知识储备,这样有利于我们对于问题的理解,先提一下,大概有一个印象,然后我们带着这些往下看,忘记了的话可以再上来温习一下。

1.JS中,函数本身也是一个包含了方法和属性的对象。

2.prototype是每个函数中都有的一个属性,叫做原型,它是一个对象。

3.__proto__是每个对象都具有的一个属性,这个指向了它的构造函数的原型(prototype),是它的引用(我们称这个属性为链接,而且每个prototype都有__proto__属性,因此本身也包含了指向其原型的链接,由此形成了一条链,我们称为原型链。

4.Object是JS所有对象的父级对象,Object()为构造函数。

5.Function是所有函数对象的构造对象,Function()为构造函数,所以Object和Function都有prototype属性。

6.我们可以通过constructor来查看对象的构造函数,isPrototypeOf来确定某个对象是不是我的原型,hasOwnProperty 方法判断属性是否存在。


好了,有了上面的只是储备,现在开始我们的代码分析之旅。

提示!!:在分析代码的过程中其实会发现一些很神奇的事,这个代码的逻辑分析就好比我们机器人要变身了,身体的一个个零件开始组合,放在这里来说就是一条条原型链(__proto__)要开始悄悄连接了(回顾一下我们前面的知识点)。

1.创建一个函数F(恩,没毛病,匿名函数的形式传给F)

   var F = function(){};


//F.__proto__ ---> Function.prototype    (__proto__ 指向了它的构造函数的原型)

//F.prototype.__proto__ --->Object.prototype  (每个prototype都有__proto__属性)


2.给Object的原型定义一个方法a

Object.prototype.a = function( ){ };


3.给Function的原型定义一个方法b

Function.prototype.b = function( ){ };


4.用F当做构造函数去构造一个对象f

var f = new F( );

这里是我们需要拆分一下才能看懂(不然鬼知道经历了什么!):

var f={ };

f.__proto__=F.prototype;


F.prototype.__proto__= Object.prototype

//f.__proto__ --->F.prototype

//F.prototype.__proto__--->Object.prototype

//f.__proto__.__proto__ ---> Object.prototype

F.call(f);


new的过程:创建了一个新对象,新对象中有一个__proto__属性(这个前面说过),把它指向了它构造函数的原型对象(F.prototype),然后将此新对象返回;

/*不如我们自己写一个new方法*/

var new2=function(func){
  var o=Object.create(func.prototype);
  var res=func.call(o);
  if(typeof res ==='object'){
    return  res;
  }else{
    return o;
  }
}

var f=new2(F)

"奇迹”发送了,一条条链子(原型链)开始已经自己连上了。不知道大家有没有发现,把线全部连起来后,其实可以得到

f.__proto__ --->F.prototype     F.prototype.__proto__ ---> Object.prototype


所以我们最终可以得到 f.__proto__.__proto__ ---> Object.prototype

这就是原型链,它会一层层往上找,直到最终的对象,这样我们就可以调用a方法了。

这个时候大家就会有疑问了,那b方法呢?

我们这边逆推一下:

Function.prototype --->F.__proto__    而我们的F.prototype !=F.__proto__  所以我们不能使用b方法。

哇,分析了这么久,大家不知道糊涂了没有,不过这里我个人感觉__proto__和prototype就是一个承上启下的作用,__proto__就是引用了它构造函数的prototype,只不过__proto__在下面(被构造出来的对象的属性),prototype在上面(构造函数对象的属性)。环环相扣。


Tips:如果这里我们希望有b方法的话,只需要改成这样:F.prototype.b = function(){};



最后说一下原型中存在的小陷阱:

function f( ) { }


var people={

name:"lzj",

say:function(){

return this.name;

  }

};

f.prototype=people;

f.prototype.constructor=f;//当我们把原型对象完全替换的时候需要重置相对应的constructor属性,否则会使我们原有对象不能访问原型的新增属性。

/*如果这里我们没有这一步的话,我们来查看一下f的原型对象的构造对象是谁

f.prototype.constructor  // function Object() { [native code] }

它的构造对象就成了object,而不是f,这样你再去f里面新增属性的时候,f实例出来的对象是不能继承的

*/




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值