今天,一个技术群里小朋友提出一个问题:

  1. Object.prototype.a = function () {
  2. console.log('a')
  3. }
  4.  
  5. Function.prototype.b = function () {
  6. console.log('b')
  7. }
  8.  
  9. function F(){}
  10. var f = new F();
  11.  
  12. f.a();
  13. f.b();
  14. F.a();
  15. F.b();

我默念心中的万能公式,答案一下就出来了:

a;

报错(f.b is not a function);

a;

b;

这下子出题人产生了疑惑,你是控制台敲出来的吧!

但其实,原型链真的很简单。话不多说,开始表演!

首先,我们简单介绍一下,实例化一个对象(new)到底做了什么?

  1. function Base() {
  2. this.a = function () {
  3. console.log('我是Base中的a')
  4. }
  5. }
  6.  
  7. Base.prototype.b = function () {
  8. console.log('我是Base prototype上的b')
  9. }
  10.  
  11. var obj = new Base();
  12. // 实际上做了以下几件事
  13. // var obj = {};
  14. // obj.__proto__ = Base.prototype;
  15. // Base.call(obj);
  16. // 第一行,我们创建了一个空对象obj
  17. // 第二行,我们将这个空对象的__proto__成员指向了Base函数对象prototype成员对象
  18. // 第三行,我们将Base函数中this上的成员赋值给obj

这就去控制台检验一下:

好,可以开始解题,回顾一下小朋友提出的问题:

  1. Object.prototype.a = function () { console.log('a') }
  2. Function.prototype.b = function () { console.log('b') }
  3. function F(){}
  4. var f = new F();
  5. f.a();f.b();F.a();F.b();

我们展开f的原型链:

  1. f.__proto__ === F.prototype;
  2.  
  3. // 因为prototype本质也是对象,继承自Object,所以F.prototype.__proto__ === Object.prototype
  4. f.__proto__.__proto__ === Object.prototype;
  5.  
  6. // 按上一条,会得出Object.prototype.__proto__ = Object.prototype,那样会永无止境,因此js中把Object.prototype.__proto_直接赋值成null
  7. f.__proto__.__proto__.__proto__ === null;

我们会发现,f的原型链中,根本没有Function.prototype什么事,所以答案出来了,f.a()输出a,f.b会报错;

我们再展开F的原型链:

  1. F.__proto__ === Function.prototype;
  2.  
  3. // 因为prototype本质也是对象,继承自Object,所以Function.prototype.__proto__ === Object.prototype
  4. F.__proto__.__proto__ === Object.prototype;
  5.  
  6. f.__proto__.__proto__.__proto__ === null;

OK,Function.prototype和Object.prototype都在原型链上,都会有输出,答案揭晓,F.a()输出a,F.b()输出b;

前文我提到了万能公式,吃瓜群众表示,难道公式就是这个?当然不是,请听我细细道来;

刚才的故事还没结束,我心血来潮回问了小朋友一个问题,就刚才你的条件Object.a();Object.b();Function.a();Function.b();会输出什么?

小朋友答曰:a; b; a; b;

不错不错,但他接了一句(他的1和4其实答错了,后续会告诉原因):

1. Object.a();  直接prototype取值;

2. Object是Function.prototype的实例,可以继承b;

3. Function.__proto__ === Function.prototype;

4. Function.b();直接prototype取值;

???Object.a第一步就直接到Object.prototype上找?这可能也是大家弄不清原型链的一大问题,话不多说,请摊开Object的原型链:

  1. // Object是函数,继承自Function
  2. Object.__proto__ === Function.prototype;
  3.  
  4. Object.__proto__.__proto__ === Object.prototype;
  5.  
  6. Object.__proto__.__proto__.__proto__ === null;

因此,细心的朋友已经发现他的错误了,Object.a其实是访问到Object.__proto__.__proto__时才从Object.prototype上找到相应的a();

同样展开Function的原型链,就不再赘述了:

  1. // Function自身也是个函数,因此继承自己
  2. Function.__proto__ === Function.prototype;
  3.  
  4. Function.__proto__.__proto__ === Object.prototype;
  5.  
  6. Function.__proto__.__proto__.__proto__ === null;

为了引导出万能公式,我再次发出了灵魂拷问:

  1. // 在刚才的前提下
  2. var c = 1;
  3. console.a();// a
  4. console.b();// console.b is not a function
  5. c.a();// a
  6. c.b();// c.b is not a function
  7. console.log.a();// a
  8. console.log.b();// b

这时,学会展开原型链的同学已经明白答案了,我就直接说出我的万能公式:

在js中,万物皆对象,只要在Object.prototype上写的方法,万物都能访问到;而Function.prototype上的方法,只有能通过()方式调用的函数,才能访问到;

因此我只需要查看这个对象可不可以通过函数()的形式调用,就能确定他是否能访问Function.prototype。再次回顾出题人的问题,f仅仅是个对象,f()是会报not is a function错误的,而F()是可以调用的函数,一下子得出 a 报错 a b的答案,学到了是不是感觉自己也棒棒哒~~~

最终Cober老师还是给出了自己的杀手锏面试题,毕竟原型链还有另一层面试方法:

  1. Object.prototype.a = function () {
  2. console.log('我是Object中的a')
  3. }
  4. Object.prototype.b = function(){
  5. console.log('我是Object中的b')
  6. }
  7. Function.prototype.a = function () {
  8. console.log('我是Function中的a')
  9. }
  10. Function.prototype.b = function () {
  11. console.log('我是Function中的b')
  12. }
  13. function F(){
  14. this.a = function () {
  15. console.log('我是F中的a')
  16. }
  17. }
  18. F.prototype.a = function () {
  19. console.log('我是F的prototype中的a')
  20. }
  21. var f = new F();
  22. f.a();f.b();F.a();F.b();Object.a();Object.b();Function.a();Function.b();

(提示:原型链调用顺序是f.a -> f.__proto__.a -> f.__proto__.__proto__.a,直到访问到null)

关于原型链,原来这么简单?—————终结__proto__和prototype的那些事的更多相关文章

  1. 对于js原型和原型链继承的简单理解(第二种,对象冒充)

    关键代码    this.parent = Cat;    this.parent.apply(this); function Cat(){ this.climb = function(){ aler ...

  2. 对于js原型和原型链继承的简单理解(第三种,复制继承)

    复制继承:简单理解,就是把父对象上的所有属性复制到自身对象上: function Cat(){ this.climb = function(){ alert("我会爬树"); } ...

  3. 对于js原型和原型链继承的简单理解(第一种,原型链继承)

    原型是js中的难点加重点,也是前端面试官最爱问的问题之一,因为面试官可以通过被面试者对原型的理解.来判断被面试者对js的熟悉程度. 原型的定义 Js所有的函数都有一个prototype属性,这个属性引 ...

  4. js 原型链的介绍

    对象的原型链:一个对象所拥有的属性不仅仅是它本身拥有的属性,他还会从其他对象中继承一些属性.当js在一个对象中找不到需要的属性时,它会到这个对象的父对象上去找,以此类催,这就构成了对象的原型链. 下面 ...

  5. js关于原型,原型链的面试题

    之前面试的时候遇到过原型和原型链方面的题目,具体的已经忘了,只记得当时回答的稀里糊涂,今天查了一些资料,把自己所理解的写出来,加深记忆. 1,前提 在js中,对象都有__proto__属性,一般这个是 ...

  6. Object.prototype 原型和原型链

    Object.prototype 原型和原型链 原型 Javascript中所有的对象都是Object的实例,并继承Object.prototype的属性和方法,有些属性是隐藏的.换句话说,在对象创建 ...

  7. JS原型链简单图解

    JS中原型链,说简单也简单. 首先明确: 函数(Function)才有prototype属性,对象(除Object)拥有__proto__. 首先,我画了一张图. 所谓原型链,指的就是图中的proto ...

  8. 彻底理解什么是原型链,prototype和__proto__的区别以及es5中的继承

    再讲一遍好了( 参考https://blog.csdn.net/cc18868876837/article/details/81211729 https://blog.csdn.net/lc23742 ...

  9. js 原型链 prototype __proto__

    1.说明 函数(Function)才有prototype属性,对象(除Object)拥有__proto__. 2.prototype与__proto__区别 示例: <!DOCTYPE html ...

随机推荐

  1. sh_06_女友的节日

    sh_06_女友的节日 # 定义 holiday_name 字符串变量记录节日名称 holiday_name = "生日" # 如果是 情人节 应该 买玫瑰/看电影 if holi ...

  2. 【转载】mysqld_safe Directory ‘/var/run/mysqld’ for UNIX socket file don’t exists.

    This is about resetting the MySQL 5.7 root password in Ubuntu 16.04 LTS You probably tried something ...

  3. Spring Boot教程(九)异步方法

    创建工程 在pom文件引入相关依赖: <dependency> <groupId>org.springframework.boot</groupId> <ar ...

  4. Spring Cloud架构教程 (二)Hystrix监控数据聚合

    上一篇我们介绍了使用Hystrix Dashboard来展示Hystrix用于熔断的各项度量指标.通过Hystrix Dashboard,我们可以方便的查看服务实例的综合情况,比如:服务调用次数.服务 ...

  5. jvisualvm性能监控

    一.配置JMX 1.进入tomcat bin目录 vim catalina.sh #!/bin/sh下面加入: #!/bin/sh JAVA_OPTS="-Dcom.sun.manageme ...

  6. nowcoder---常州大学新生寒假训练会试----F 大佬的生日礼包(二分)

    链接:https://www.nowcoder.net/acm/contest/78/F 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K 64bit ...

  7. Mybatis 中在xxx.mapper书写模糊查询

    1.在mybatis中,书写sql,有时候会有一些不细心,如: <!-- 首页商品 关键字搜索--> <select id="getGoodsByLikeTitle&quo ...

  8. android和网络连接相关的类URL,URLConnection,HttpURLConnection,HttpClient

    这几个类都是用于和服务器端的连接,有些功能都能够实现,关系是: 一.URL URL标识着网络上的一个资源:该类包含一些URL自身的方法,如获取URL对应的主机名称,端口号,协议,查询字符串外,还有些方 ...

  9. Vue v-if以及 v-else 的使用

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  10. @WebService这个标签的作用是什么

    当实现 Web Service 时,@WebService 注释标记 Java 类:实现 Web Service 接口时,标记服务端点接口(SEI). (声明webservice服务) 要点: • 实 ...