js原型链的一些发现----来自一道笔试题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js原型链的一些发现----来自一道笔试题相关的知识,希望对你有一定的参考价值。

1.开篇

1.1本文目标

这是我真正意义上的博客,一是想记录下自己学到的东西,二是想写博客也是对自己的一种历练,自己的一次新的尝试。

废话不多说,说下这次写这篇东东的原因。js的原型链是让我很头疼的事情,每次碰到一些相关的题目和代码都让我有点不知所措。最近的一次笔试碰到了一道相关的题目,不出所料,没有答出来。回来对此钻研一通,不断地查资料测试代码,终于有了点收获,正好最近开始玩博客,所以写了这篇记录。

PS:我基础并不好,所以这篇文章可能不会是那种大牛级的专业博客。如果有幸让大神们看到这篇文章,并且让你看了心情不悦,还望见谅。如果还能得到大神的指导,那真的是谢天谢地。

2.正文

2.1代码

下面就是我这次笔试遇到的代码:

 1 function Fun(){
 2     var getName = function(){
 3         console.log(1);
 4     }
 5     return this;
 6 }
 7 Fun.getName = function(){
 8     console.log(2);
 9 }
10 Fun.prototype.getName = function(){
11     console.log(3);
12 }
13 var getName = function(){
14     console.log(4);
15 }
16 function getName(){
17     console.log(5);
18 }
19         
20 Fun().getName();
21 getName();
22 Fun();
23 getName();
24 new Fun().getName();
25 new new Fun().getName();

2.2我的理解

我先把结果贴出来:4 4 4 3 3

第一条执行语句:Fun().getName();

这里结果是4,语句先执行Fun()函数,得到返回值this,这时的this就代表全局对象Global,然后调用getName()函数,输出结果。

上面这个步骤相信大家都是知道的,但是为什么输出的是4而不是5,调用的是var getName而不是function getName(),这个我想应该要记录一下。

js有个机制叫声明提前,也就是函数里的所有变量都被“提前”至函数体的顶部。结合题目看一下:

1 var getName = function(){
2     console.log(4);
3 }
4 function getName(){
5     console.log(5);
6 }
7 Fun().getName();

好的,按照声明提前,我们应该是把var getName提到最前面:

var getName;//被提前了
getName = function(){
    console.log(4);
}
function getName(){
    console.log(5);
}

看到这里,我想了很久,这不是应该被function getName()覆盖了吗,输出不应该是5吗?想得我头都大,最后才明白了,这function getName()也应该要提前啊,因为它叫函数声明,也是声明......

所以正确的应该是这样的:

var getName;
function getName(){//这个也是要提前的
    console.log(5);
}
getName = function(){
    console.log(4);
}

其实到这里我还担心一种可能,就是funciton getName()和var getName其实不是一个玩意儿,也就不存在覆盖不覆盖的事情了,那我前面说的不就是白费了?我验证了一下,把整个var getName都删了,再运行一下,发现结果为4的地方都变成了5,我才稍稍放心了点。如果我这么想是错的,还望大牛们纠正我,别让我误人误己,谢了。

第二条语句getName(),第三条语句Fun(),第四条语句getName():

这里的getName()就不用多说了,和第一条的解释是一样的。至于这第三条Fun(),我也不知道我是不是记错了,那次笔试不能用通讯设备,偷偷的也不行,以至于我想把题目拍下来的机会都没有,题目还是我用脑子记的,第三条语句的出题意义我也没想明白,跳过吧。对了,Fun()这条语句是没有输出的,所以最后是只有5个输出结果。

第五条语句new Fun().getName(),第六条语句new new Fun().getName():

好了,重头戏来了。在我做笔试的时候,当我一看到这里,心里默念了无数次,我我我去。真的,这是我第一次看到两个new放在了一起......好吧,毕竟基础差,下面是我测试得出来的分析:

在此之前我觉得应该提一些知识点,有一句话是万事万物皆为对象,而js这里分为了两种,一种是普通对象,另一种是函数对象。对的,函数就是牛逼一点,记着这个。再来一个知识点,只要是对象,就会有_proto_这个属性,而prototype这个属性,是只有函数对象才有。这里开始会涉及原型链的东西,我会说一些我看到的东西,但未必是全部,有兴趣的可以自己去查一下。

先来看个例子:

function Fun(){
    var getName = function(){
        console.log(1);
    }
    return this;
}
var a = new Fun();//创建Fun函数的实例
console.log(typeof Fun);
console.log(typeof a);

下面是浏览器工具的截图:

技术分享技术分享技术分享

好的,这里我们先看到一个点,第三张图里能看到,Fun是function类型,a是object类型。再来看前两张图,Fun函数是有prototype而a变量没有,而_proto_属性是两个都有,也就证明了上面那个知识点的正确性。

再来看最重要的一点,有没有发现,a的_proto_和Fun的prototype是一模一样的。这就是我测试找到的最重要的一点:通过new得到的实例,它只会继承函数的prototype属性,也就是a._proto_==Fun.prototype。

再来看下面这个例子:

1 function Fun(){
2     var c = 1;//增加一个内部变量c
3     var getName = function(){
4         console.log(1);
5     }
6     return this;
7 }
8 var a = new Fun();
9 console.log(a.c);

聪明的大家应该已经知道了,这个例子的结果应该是undefined,因为a只继承(应该可以用继承这个词吧)了Fun这个函数的prototype,而c变量是Fun函数的内部变量,并不是它的原型prototype的属性,所以a里面并没有定义这个c变量。这也能引申出另一个知识点,就是js的闭包,有兴趣可以去查一哈。那问题来了,我就是要用这个变量c怎么办,聪明的大家应该早就知道了,return啊老哥,这样变量c不就出来了嘛。

终于可以说回我们的笔试题了:

第五句执行new Fun().getName();结果是3。我们知道,new出来的Fun实例只继承了prototype,而正好题目有一句Fun.prototype.getName = function(){console.log(3);},把prototype的getName进行了替换,所以这就是为什么输出3了。再看第六句执行new new Fun().getName();执行顺序应该是这样的,先new出来Fun函数的一个实例,再new一个Fun函数实例中的getName函数,这里我们知道getName函数已经被替换成了结果3,new的时候执行代码getName函数里面的代码console.log(3);输出结果,至于new new Fun().getName()返回的就是getName函数的实例了。其实和第五句一个意思,就是返回的结果不同了。

最最最后一个例子:

 1 function Fun(){
 2     var getName = function(){
 3         console.log(1);
 4     }
 5     return this;
 6 }
 7 var a = new Fun();
 8 Fun.prototype.getName = function(){//修改Fun()函数prototype里面的getName
 9     console.log(6);
10 }

结果如下:

未执行Fun.prototype.getName = function(){console.log(6);}技术分享

执行后Fun.prototype.getName = function(){console.log(6);}技术分享

好了,意思都知道了,我就不多说了。

3.总结

3.1认真的总结

这总结我也不知道有什么好写的,这是我第一次写博客,连续三个小时全部写了出来,也还算满意吧。如果有幸被大牛看到,或者对看到的人有一丝帮助,那我就很开心了。


转载请注明出处,快转快转,哈哈哈。http://www.cnblogs.com/ChenYongHao/p/7716828.html



以上是关于js原型链的一些发现----来自一道笔试题的主要内容,如果未能解决你的问题,请参考以下文章

从零开始的全栈工程师——js篇(作用域 this 原型笔试题练习)

一道头条笔试题:求区间的个数

一道动态规划的笔试题

nice公司的一道笔试题讲解

js笔试题系列之三——函数

一道简单的 Java 笔试题,但值得很多人反思