技术分享 javaScript原型链

  • 一个小题目
    • 前置知识
    • 变量提升和函数提升
    • this指针的指向
    • 原型链是什么
    • new操作符的工资流程

一个小题目

今天我们部门的技术分享上出现了这样一段代码:

function Foo(){getName=function(){console.log(1)}return this
}//1
Foo.getName=function(){console.log(2)}//2
Foo.prototype.getName=function(){console.log(3)}//3
var getName=function(){console.log(4)}//4
function getName(){console.log(5)}//5getName()
Foo().getName()
getName()
Foo.getName()
new Foo.getName()
new Foo().getName()
new new Foo().getName()

问我们这段代码的运行结果是怎样的

前置知识

首先我们需要了解以下前置知识:

  1. 变量提升和函数提升
  2. this指针的指向
  3. 原型链是什么
  4. new操作符的工资流程

本文对于这些知识进行浅谈,详细的知识作者还是建议读者去自行查找资料和学习。

变量提升和函数提升

变量提升简单来说就是使用var声明变量的时候,会在编译时将其提升至最顶端,例如本题的代码的前几行:(有错误)

//编译前
function Foo(){getName=function(){console.log(1)}return this
}
Foo.getName=function(){console.log(2)}
Foo.prototype.getName=function(){console.log(3)}
var getName=function(){console.log(4)}
function getName(){console.log(5)}//编译后
var getName;//getName=undefinedfunction Foo(){getName=function(){console.log(1)}return this
}
Foo.getName=function(){console.log(2)}
Foo.prototype.getName=function(){console.log(3)}
getName=function(){console.log(4)}
function getName(){console.log(5)}

当然细心的读者应该会发现,这个编译后的代码依旧存在一些问题,因为js不仅有变量提升,同时还有函数提升。

在JS中函数在编译后也会提升至最顶端,因此编译后的正确代码为:

function Foo(){getName=function(){console.log(1)}return this
}
function getName(){console.log(5)}//函数声明
var getName;//变量声明Foo.getName=function(){console.log(2)}
Foo.prototype.getName=function(){console.log(3)}
getName=function(){console.log(4)}

这里要注意:函数提升的优先级高于变量提升,当函数声明与变量名相同时,只要变量未赋值,此名称依旧是个函数,不会被覆盖;只有当变量赋值后,函数声明才会被同名的变量覆盖。

相信读到这里开篇提到的问题已经能解决一部分了

getName=function(){console.log(4)}

会覆盖同名函数,因此第一行的执行结果为4

this指针的指向

简单来说this是一个指向一个对象的指针,通常情况下你只需要记住调用方法时谁调用,this就指向谁。

例如我在全局中调用Foo()方法,那么此时进入方法里this的指向就是全局(Window对象)

那么我们第二行的运行结果也就很容易就理解了,首先Foo方法对全局里的getName重新赋值,并返回Window对象,所以第二行执行的方法为全局对象里重新赋值后的的getName()

因此第二行和第三行的执行结果为1
读到这里第三行的运行结果和第二行一样也不难理解了

原型链是什么

首先我们知道在js中函数也是一个对象,它也是具有普通对象的一些功能的,而JavaScript 对象体系是基于构造函数和原型链的。继承不通过类,而是通过原型对象实现,原型对象的所有属性和方法,都能被实例对象共享。

既然函数可以是一个对象,那么原题中的第二部分,就是为Foo添加了一个属性getName(),所以第4行的输出结果就是现在为其添加的这个方法的运行结果:2

接下来我们需要了解原题中第三部分的作用,也就是以下代码的作用:

  Foo.prototype.getName = function () { console.log(3) }

首先每个构造函数都有一个prototype属性指向原型对象,用来存放共有属性和方法的地址。

每个实例对象都有一个__proto__属性指向构造函数的原型对象。
例如本题的

Foo.__proto__===Function.prototype//true
Function.prototype.__proto__===Object.prototype//true

这样依次类推各个原型组成了“原型链”
在理解了原型链之后你还需要了解下面这句话:
当js试图得到一个对象的属性时,会先去这个对象的本身去寻找,如果这个对象本身没有找到这个属性,那么js就会去它构造函数的’prototype’属性中去寻找,也就是去’proto‘中寻找,如果’prototype’属性本身中依旧没有找到,’prototype’中依旧有一个‘proto’。

读到这里相信第三部分的代码意思也很清晰了,向原型链中添加一个方法:getName()

new操作符的工资流程

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。

简单来说new就是用来创建一个对象。

那么new操作符是怎么做到的呢?

第一步:创建一个空的对象(即{})

第二步:将空对象的原型prototype指向构造函数的原型

第三步:改变this指针的指向,并将剩余的参数传入,执行构造函数中的代码

第四步:判断构造函数的返回值,将成功后的对象返回

这时我们分析原题第五行的输出结果:

第一步:创建一个空对象

let obj= {}

第二步:将obj的原型指向Foo对象的getName()的原型

obj.__proto__=Foo.getName.prototype

第三步:改变this指向,传入剩余参数并执行构造函数Foo.getName()。运行到这里输出3。

第四步:判断构造函数的返回值,将成功后的对象返回

最后我们再看第六行的运行过程:
首先new Foo().getName()等价于(new Foo()).getName()

第一步:创建一个空对象

let obj= {}

第二步:将obj的原型指向Foo的原型

obj.__proto__=Foo().prototype```
第三步:改变this指向,传入剩余参数并执行构造函数Foo()第四步:判断构造函数的返回值,将成功后的对象返回第五步:执行返回的新对象的getName()方法,可我们的新对象中并没有此方法,于是去原型链上寻找,故输出3相信读到这里最后一行的答案也不需要作者多说什么了,其运行过程与第六行的基本一致。

技术分享经典 javaScript原型链面试题相关推荐

  1. JavaScript 原型链和继承面试题

    JavaScript 原型链和继承问题 JavaScript 中没有类的概念的,主要通过原型链来实现继承.通常情况下,继承意味着复制操作,然而 JavaScript默认并不会复制对象的属性,相反,Ja ...

  2. JavaScript系列—一道十面埋伏的原型链面试题

    这道题是我面试的时候碰到的 function Parent() {this.a = 1;this.b = [1, 2, this.a];this.c = { demo: 5 };this.show = ...

  3. 深度解析JavaScript原型链

    深度解析JavaScript原型链 文章目录 深度解析JavaScript原型链 前言 JavaScript原型链,这里只分享我自己的见解 一.原型链是什么 二.心得 三图解 总结 前言 JavaSc ...

  4. javascript原型链中 this 的指向

    为了弄清楚Javascript原型链中的this指向问题,我写了个代码来测试: var d = {d: 40};var a = {x: 10,calculate: function (z) {retu ...

  5. JavaScript原型链污染攻击

    前言 最近在看js的时候看到p神的一篇关于js原型链污染的文章,学习一下. 下面转自p神:深入理解 JavaScript Prototype 污染攻击 还有一篇案例关于js原型链污染的ctf题:从一道 ...

  6. JavaScript 原型链常用方法

    JavaScript 原型链常用方法 对象属性类型 数据属性 Configurable(表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性) En ...

  7. 如何理解JavaScript原型链

    如何理解JavaScript原型链 实例对象与原型对象的关系 构造函数.原型对象和实例对象之间的关系 原型链结构图 函数在原型链中的结构 原型链的理解和总结 实例对象与原型对象的关系 构造函数.原型对 ...

  8. 前端开发面试题—JavaScript原型链

    在JavaScript面向对象中,原型链是一个很重要的知识点,经常出现在大大小小的面试题中,关于原型链的面试题有很多问法和知识点.今天主要分享一下我遇到的一个关于原型链的面试题.问题很简单,什么是原型 ...

  9. javascript基础修炼(1)——一道十面埋伏的原型链面试题

    在基础面前,一切技巧都是浮云. 题目是这样的 要求写出控制台的输出 题目涉及的知识点 1.this的指向 2.原型机原型链 3.类的继承 4.原始类型和引用类型的区别 5.每一个知识点都可以拿出来做单 ...

最新文章

  1. C++ 中multiset 的使用
  2. Java EE (11) - 影响性能的因素
  3. hdu4499 搜索
  4. mc服务器音乐文件夹在哪,添加自定义音乐图文教程 我的世界怎么添加音乐
  5. Rabbit MQ 学习 (一)Window安装Erlang环境
  6. [HEOI2015]兔子与樱花
  7. linux 关闭本地防火墙_如何使用Linux防火墙阻止本地欺骗地址
  8. 姚前:分布式账本与传统账本的异同及其现实意义
  9. 科技正在淘汰传统行业,这次的“倒霉鬼”是券商
  10. PyCharm汉化包安装下载及PyCharm无法进行设置问题
  11. 【转载】「微信小程序」有哪些冲击与机会?
  12. linux环境下使用logrotate工具实现nginx日志切割
  13. 车牌号识别 python + opencv
  14. WPS文字的字数统计在哪?如何查看当前文档有多少个字?
  15. 解决报错Duplicate keys detected
  16. 利用ipconfig命令查看IP及释放和重获IP
  17. vue中使用leaflet加载open street map的一些使用
  18. 身份证号码中出生年月的提取
  19. python北京房价预测_Python爬虫告诉你北京房价有多高
  20. 完美世界CEO萧泓:年轻化战略大有可为

热门文章

  1. 使用elementUI渲染下拉框
  2. iOS小课堂: 集成 《阿里百川》教程( 打开商品详情页、 淘宝账号授权登录、 完成交易闭环)
  3. html图片遮住字了,css 内容为何被遮挡住了?
  4. 【解决显示器颜色不正常的办法】
  5. 【ECC小技巧】SAP 系统图标名称
  6. 算法——所有节点对的最短路径:Floyd-Warshall算法、Johnson算法
  7. 【老生谈算法】matlab实现用CZT求解系统函数的零极点——零极点
  8. 计算机打印机共享失败,两台win7系统共享打印机提示不成功的解决方法
  9. 计算机专业中专自我鉴定范文,计算机专业中专生自我鉴定
  10. 计算机应用700字自我鉴定,计算机及应用*自我鉴定范文700字