关于原型链,原来这么简单?—————终结__proto__和prototype的那些事
今天,一个技术群里小朋友提出一个问题:
Object.prototype.a = function () {
console.log('a')
}
Function.prototype.b = function () {
console.log('b')
}
function F(){}
var f = new F();
f.a();
f.b();
F.a();
F.b();
我默念心中的万能公式,答案一下就出来了:
a;
报错(f.b is not a function);
a;
b;
这下子出题人产生了疑惑,你是控制台敲出来的吧!
但其实,原型链真的很简单。话不多说,开始表演!
首先,我们简单介绍一下,实例化一个对象(new)到底做了什么?
function Base() {
this.a = function () {
console.log('我是Base中的a')
}
}
Base.prototype.b = function () {
console.log('我是Base prototype上的b')
}
var obj = new Base();
// 实际上做了以下几件事
// var obj = {};
// obj.__proto__ = Base.prototype;
// Base.call(obj);
// 第一行,我们创建了一个空对象obj
// 第二行,我们将这个空对象的__proto__成员指向了Base函数对象prototype成员对象
// 第三行,我们将Base函数中this上的成员赋值给obj
这就去控制台检验一下:

好,可以开始解题,回顾一下小朋友提出的问题:
Object.prototype.a = function () { console.log('a') }
Function.prototype.b = function () { console.log('b') }
function F(){}
var f = new F();
f.a();f.b();F.a();F.b();
我们展开f的原型链:
f.__proto__ === F.prototype; // 因为prototype本质也是对象,继承自Object,所以F.prototype.__proto__ === Object.prototype
f.__proto__.__proto__ === Object.prototype; // 按上一条,会得出Object.prototype.__proto__ = Object.prototype,那样会永无止境,因此js中把Object.prototype.__proto_直接赋值成null
f.__proto__.__proto__.__proto__ === null;
我们会发现,f的原型链中,根本没有Function.prototype什么事,所以答案出来了,f.a()输出a,f.b会报错;
我们再展开F的原型链:
F.__proto__ === Function.prototype; // 因为prototype本质也是对象,继承自Object,所以Function.prototype.__proto__ === Object.prototype
F.__proto__.__proto__ === Object.prototype; 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的原型链:
// Object是函数,继承自Function
Object.__proto__ === Function.prototype; Object.__proto__.__proto__ === Object.prototype; Object.__proto__.__proto__.__proto__ === null;
因此,细心的朋友已经发现他的错误了,Object.a其实是访问到Object.__proto__.__proto__时才从Object.prototype上找到相应的a();
同样展开Function的原型链,就不再赘述了:
// Function自身也是个函数,因此继承自己
Function.__proto__ === Function.prototype; Function.__proto__.__proto__ === Object.prototype; Function.__proto__.__proto__.__proto__ === null;
为了引导出万能公式,我再次发出了灵魂拷问:
// 在刚才的前提下
var c = 1;
console.a();// a
console.b();// console.b is not a function
c.a();// a
c.b();// c.b is not a function
console.log.a();// a
console.log.b();// b
这时,学会展开原型链的同学已经明白答案了,我就直接说出我的万能公式:
在js中,万物皆对象,只要在Object.prototype上写的方法,万物都能访问到;而Function.prototype上的方法,只有能通过()方式调用的函数,才能访问到;
因此我只需要查看这个对象可不可以通过函数()的形式调用,就能确定他是否能访问Function.prototype。再次回顾出题人的问题,f仅仅是个对象,f()是会报not is a function错误的,而F()是可以调用的函数,一下子得出 a 报错 a b的答案,学到了是不是感觉自己也棒棒哒~~~
最终Cober老师还是给出了自己的杀手锏面试题,毕竟原型链还有另一层面试方法:
Object.prototype.a = function () {
console.log('我是Object中的a')
}
Object.prototype.b = function(){
console.log('我是Object中的b')
}
Function.prototype.a = function () {
console.log('我是Function中的a')
}
Function.prototype.b = function () {
console.log('我是Function中的b')
}
function F(){
this.a = function () {
console.log('我是F中的a')
}
}
F.prototype.a = function () {
console.log('我是F的prototype中的a')
}
var f = new F();
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的那些事的更多相关文章
- 对于js原型和原型链继承的简单理解(第二种,对象冒充)
关键代码 this.parent = Cat; this.parent.apply(this); function Cat(){ this.climb = function(){ aler ...
- 对于js原型和原型链继承的简单理解(第三种,复制继承)
复制继承:简单理解,就是把父对象上的所有属性复制到自身对象上: function Cat(){ this.climb = function(){ alert("我会爬树"); } ...
- 对于js原型和原型链继承的简单理解(第一种,原型链继承)
原型是js中的难点加重点,也是前端面试官最爱问的问题之一,因为面试官可以通过被面试者对原型的理解.来判断被面试者对js的熟悉程度. 原型的定义 Js所有的函数都有一个prototype属性,这个属性引 ...
- js 原型链的介绍
对象的原型链:一个对象所拥有的属性不仅仅是它本身拥有的属性,他还会从其他对象中继承一些属性.当js在一个对象中找不到需要的属性时,它会到这个对象的父对象上去找,以此类催,这就构成了对象的原型链. 下面 ...
- js关于原型,原型链的面试题
之前面试的时候遇到过原型和原型链方面的题目,具体的已经忘了,只记得当时回答的稀里糊涂,今天查了一些资料,把自己所理解的写出来,加深记忆. 1,前提 在js中,对象都有__proto__属性,一般这个是 ...
- Object.prototype 原型和原型链
Object.prototype 原型和原型链 原型 Javascript中所有的对象都是Object的实例,并继承Object.prototype的属性和方法,有些属性是隐藏的.换句话说,在对象创建 ...
- JS原型链简单图解
JS中原型链,说简单也简单. 首先明确: 函数(Function)才有prototype属性,对象(除Object)拥有__proto__. 首先,我画了一张图. 所谓原型链,指的就是图中的proto ...
- 彻底理解什么是原型链,prototype和__proto__的区别以及es5中的继承
再讲一遍好了( 参考https://blog.csdn.net/cc18868876837/article/details/81211729 https://blog.csdn.net/lc23742 ...
- js 原型链 prototype __proto__
1.说明 函数(Function)才有prototype属性,对象(除Object)拥有__proto__. 2.prototype与__proto__区别 示例: <!DOCTYPE html ...
随机推荐
- FJWC2017&FJOI2017一试 游记
day1 早上是以前泉州七中的杨国烨讲课.(据说当时看新闻说是一对双胞胎一起上thu的其中一个)课题是图论/网络流. 下午第一道一开始推出来了一个之和面积有关的式子,然后觉得可以容斥一发,觉得 ...
- 一个ros包依赖另一个ros包提供的库
背景: 编写一个点云配准的ros包,记为A,在其中打算使用多种点云配准算法. 同一个ros工作空间下有另一个ros包,记为B,B中提供了几种点云配准算法,并将它们都编译成一个库文件并安装在工作空间中. ...
- PCL智能指针疑云 <三> 智能指针作为函数的传值参数和传引用参数
一 函数的参数传递可以简单分类为“传值”和“传引用”. 声明函数时,形参带引用“&”,则函数调用时,是把实参所在的内存直接传给函数所开辟的栈内存.在函数内对形参的修改相当于对实参也进行修改. ...
- Java虚拟机之JVM调节参数
-XX:+PrintGC 使用这个参数,虚拟机启动后,每次GC就会打印日志. -XX:+UseSerialGC 使用串行垃圾回收器. -XX:+PrintGCDetails 打印详细信息.包括各个区的 ...
- Spring Cloud Config教程(五)客户端使用
要在应用程序中使用这些功能,只需将其构建为依赖于spring-cloud-config-client的Spring引导应用程序(例如,查看配置客户端或示例应用程序的测试用例).添加依赖关系的最方便的方 ...
- Windows Server 部署WEB API时内部错误
Windows Server 部署WEB API时,发生HTTP 错误 500.21 - Internal Server Error,如图所示: 错误原因:IIS注册Framework4.0 解决方法 ...
- [CSP-S模拟测试]:邻面合并(状压DP)
题目背景 $NEWorld$作为一个$3D$游戏,对渲染(图形绘制)的效率要求极高.当玩家扩大视野范围时,可见的方块面数量将会迅速增多,以至于大量的顶点处理很快就成为了图形管线中的瓶颈.乔猫想了想,决 ...
- android 3.0 ationbar使用总结
1,ationbar的基本讲解 http://www.apkbus.com/forum.php?mod=viewthread&tid=125536 仅仅需要根据需求写出一个menu资源文件 2 ...
- centos7 yum安装jdk
安装之前先检查一下系统有没有自带open-jdk 命令: rpm -qa |grep java rpm -qa |grep jdk rpm -qa |grep gcj 如果没有输入信息表示没有安装. ...
- HTTP访问控制(CORS)踩坑小记
前几天在帮后端排查一个cors的问题的时候发现的一些小坑特此记录 ** cors的本质是出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求. 例如,XMLHttpRequest和FetchAPI遵 ...