JavaScript重难点解析3(原型与原型链、执行上下文与执行上下文栈)

  • 原型与原型链
    • 原型(prototype)
    • 显示原型与隐式原型
    • 原型链
    • instanceof是如何判断
  • 执行上下文与执行上下文栈
    • 变量提升与函数提升
    • 执行上下文
      • 全局执行上下文
      • 函数执行上下文
      • 执行上下文栈

原型与原型链

原型(prototype)

每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
原型对象中有一个属性constructor, 它指向函数对象

function A() {}console.log(A.prototype) // 打印一个空对象console.log(A.prototype.constructor===A) //true

给原型添加的方法可以直接调用

function Aaa() {}
Aaa.prototype.test = function () {console.log(' Aaa')
}
var aaa = new  Aaa()aaa.test() //打印Aaa

显示原型与隐式原型

每个构造函数都有一个prototype,即显式原型(属性)
每个实例对象都有一个__proto__,可称为隐式原型(属性)
对象的隐式原型的值为其对应构造函数的显式原型的值

function Fn() {   // 内部语句: this.prototype = {}
}
//创建实例对象
var fn = new Fn()  // 内部语句: this.__proto__ = Fn.prototype
console.log(Fn.prototype===fn.__proto__) // trueFn.prototype.test = function () {console.log('test()')
}fn.test()

内存结构图

原型链

在访问一个对象的属性时,首先在自身属性中查找,如果没有找到, 再沿着__proto__这条链向上查找, 如果还是没有, 则返回undefined。

function Fn() {}
console.log(Fn.prototype)
Fn.prototype.test = function () {console.log('test')
}var fn = new Fn()fn.test() //调用自己的test1
fn.toString()  //调用Object上的toString方法


这里对该结构做一个简单介绍,在所有代码执行之前JS引擎会自动创建Object原型对象,并自动生成Object构造方法(相当于定义Function Object() {…}),Object构造方法的prototype属性指向Object原型对象,还会生成函数构造方法(相当于定义Function Function() {…})和一个函数原型对象(也是一个Object对象)Function()的prototype和__proto__都指向函数原型对象,当我们代码执行到 function Fn() 时,堆中会创建一个Function的实例对象,Function对象的prototype指向函数原型对象。当执行到 Fn.prototype.test= function () {…}时,在空object对象上创建了test方法,当调用fn.test时,fn会在自身属性中查找,发现没有然后沿着__proto__查找,找到后执行。
最后做几点特殊说明:

  • 函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
  • 所有函数都是Function的实例(包含Function)
  • Object的原型对象是原型链尽头

instanceof是如何判断

表达式: A instanceof B
如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false
简单来说,看上例中画的图,如果A沿着__proto__走可以走到B的prototype上,那么就是true,不然就是false。
大家可以按照上例中的图对这几个例子画一画:

function Foo() {  }
var f1 = new Foo()
console.log(f1 instanceof Foo) // true
console.log(f1 instanceof Object) // trueconsole.log(Object instanceof Function) // true
console.log(Object instanceof Object) // true
console.log(Function instanceof Function) // true
console.log(Function instanceof Object) // true
console.log(Object instanceof  Foo) // false

原型链是JS的一大难点,不好理解,如果大家看完感觉不解的化可以根据自己的代码画图看看。多画几遍比多听要强很多。

执行上下文与执行上下文栈

变量提升与函数提升

变量声明提升

  • 通过var定义(声明)的变量, 在定义语句之前就可以访问到
  • 值: undefined

函数声明提升

  • 通过function声明的函数, 在之前就可以直接调用
  • 值: 函数定义(对象)
var a = 3
function fn () {console.log(a) //undefinedvar a = 4
}
fn()

根据变量提升和函数提升的概念以上程序可以翻译为:

var a
function fn () {var aconsole.log(a) a = 4
}
var a = 3
fn()

所以a为undifined。
在这里可以说明一个两种函数定义方法的区别:

fn2() //可调用  函数提升
fn3() //不能  变量提升function fn2() {console.log('fn2()')
}var fn3 = function () {console.log('fn3()')
}

执行上下文

全局执行上下文

在执行全局代码前将window确定为全局执行上下文
对全局数据进行预处理

  • var定义的全局变量==>undefined, 添加为window的属性
  • function声明的全局函数==>赋值(fun), 添加为window的方法
  • this==>赋值(window)
  • 开始执行全局代码

函数执行上下文

在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象(虚拟的, 存在于栈中)

  • 形参变量==>赋值(实参)==>添加为执行上下文的属性
  • arguments==>赋值(实参列表), 添加为执行上下文的属性
  • var定义的局部变量==>undefined, 添加为执行上下文的属性
  • function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
  • this==>赋值(调用函数的对象)
  • 开始执行函数体代码

执行上下文栈

在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象
在全局执行上下文(window)确定后, 将其添加到栈中(压栈)
在函数执行上下文创建后, 将其添加到栈中(压栈)
在当前函数执行完后,将栈顶的对象移除(出栈)
当所有的代码执行完后, 栈中只剩下window

以一道面试题为例:

console.log('gb: '+ i)
var i = 1
foo(1)
function foo(i) {if (i == 4) {return}console.log('fb:' + i)foo(i + 1) //递归调用: 在函数内部调用自己console.log('fe:' + i)
}
console.log('ge: ' + i)

执行上下文栈如图:

  1. window入栈,由于变量提升,程序开始i被定义为undifined,所以第一个打印console.log打印gb:undifined。打印完下一行对i赋值1。
  2. 程序执行到第三行foo(1)函数入栈,形参i=1不为4,直接执行console.log(‘fb:’ + i)打印fb:1。
  3. foo(i + 1)处一个新的foo(2)函数入栈,形参i=2,重复2的操作打印fb:2。
  4. foo(i + 1)处一个新的foo(3)函数入栈,形参i=3,重复2的操作打印fb:3。
  5. foo(i + 1)处一个新的foo(4)函数入栈,形参i=4返回,foo(4)出栈。
  6. foo(3)继续执行,到console.log(‘fe:’ + i)打印fe:3,foo(3)执行结束出栈。
  7. foo(2)继续执行,到console.log(‘fe:’ + i)打印fe:2,foo(2)执行结束出栈。
  8. foo(1)继续执行,到console.log(‘fe:’ + i)打印fe:1,foo(1)执行结束出栈。
  9. window继续执行,此时i为1,console.log('ge: ’ + i)处打印ge:1。

JavaScript重难点解析3(原型与原型链、执行上下文与执行上下文栈)相关推荐

  1. JavaScript重难点解析5(对象高级、浏览器内核与事件循环模型(js异步机制))

    JavaScript重难点解析5(对象高级.浏览器内核与事件循环模型(js异步机制) 对象高级 对象创建模式 Object构造函数模式 对象字面量模式 工厂模式 自定义构造函数模式 构造函数+原型的组 ...

  2. JavaScript重难点解析6(Promise)

    JavaScript重难点解析6(Promise 概念 为什么要使用Promise Promise 的状态 Promise 对象的值 Promise工作流程 基本用法 Promise其他方法 asyn ...

  3. JavaScript重难点解析4(作用域与作用域链、闭包详解)

    JavaScript重难点解析4(作用域与作用域链.闭包详解) 作用域与作用域链 作用域 作用域与执行上下文 作用域链 闭包 闭包理解 将函数作为另一个函数的返回值 将函数作为实参传递给另一个函数调用 ...

  4. JavaScript重难点解析2(立即执行函数IIFE,this关键字)

    JavaScript重难点解析2(立即执行函数IIFE,this关键字) 立即执行函数 this关键字 立即执行函数 也叫做匿名函数自调用,可以在定义一段函数之后直接让其执行. ;(function ...

  5. JavaScript重难点解析1(数据类型——var、let、const区别,类型补充,“===”、“typeof”、“instanceof”区别,Symbol数据类型)

    JavaScript重难点解析1(数据类型) var.let.const区别: 类型补充 "==="."typeof"."instanceof&quo ...

  6. 快速排序的难点_数据结构考研重难点解析:快速排序

    数据结构是计算机专业考研重点内容,大部分院校都是考到了数据结构,其中快速排序是其中的重点难点内容,因此中公考研计算机教研室为大家整理的"数据结构考研重难点解析:快速排序",希望对大 ...

  7. 跨考408计算机学科专业基础综合,考研北京航空航天大学计算机学科专业基础综合(408)重难点解析.doc...

    2010年考研北京航空航天大学计算机学科专业基础综合(408)重难点解析 跨考专业课特别奉献,为广大考研学子加油助力! 1.操作系统 今天我们来解析一下计算统考大纲操作系统部分的知识点.操作系统的研发 ...

  8. 计算机学科专业基础综合简称,2010年考研北京大学计算机学科专业基础综合(408)重难点解析...

    2010年考研北京大学计算机学科专业基础综合(408)重难点解析 考研全程辅导专家 2010年考研北京大学计算机学科专业基础综合(408)重难点解析 跨考专业课特别奉献,为广大考研学子加油助力! 计算 ...

  9. 一次解析系统_消防稳压泵的流量、压力、选型以及配套气压罐的重难点解析

    稳压泵 1.稳压泵宜采用离心泵,并宜符合下列规定: 1)宜采用单吸单级或单吸多级离心泵: 2)泵外壳和叶轮等主要部件的材质宜采用不锈钢. [重点.难点解析]稳压泵经常启动,为了延长它的使用寿命,防止频 ...

最新文章

  1. 转行数据分析师后悔了?脱颖而出才是关键!
  2. 腾讯副总裁姚星:腾讯AI Lab将致力打造通往AGI之路
  3. Ambari离线部署Hadoop集群踩到的坑
  4. 根据序列选择自回归模型(AR、ARMA、VAR、VMA、VECH)
  5. A1136 | 字符串处理、大整数运算
  6. Spring MVC PathVariable
  7. 34.Linux/Unix 系统编程手册(下) -- 进程组,会话和作业控制
  8. HIbernate学习笔记5 之 查询
  9. Cascade:自动化测试“旅程”
  10. 神州行省内流量套餐6元500M申请,发送BLSN6到10086即可
  11. 基于51单片机DTH11温湿度测量仪protues仿真设计_LCD显示
  12. 计算机网络mac地址作用是什么,路由器中MAC地址克隆的用途是什么
  13. AcWing - 寒假每日一题2023(DAY 11——DAY 15)
  14. 文件或目录损坏其无法读取问题解决方法2022-9-15
  15. arm服务器安装docker及docker-compose
  16. jar包是干什么用的
  17. Microsoft Excel 教程:如何在 Excel 单元格中设置文本格式?
  18. 数据库逻辑设计之 三大范式 及 反范式化 优缺点
  19. 洞泾镇科大智能机器人_【企业风采】G60科创走廊的标志性项目洞泾镇商会副会长企业科大智能总部园区,预计明年初全部落成...
  20. 踩坑篇,多达21页的,超级详细的Oracle安装和配置教程,没有之一

热门文章

  1. java中什么是底层数据结构_JavaScript 对象的底层数据结构是什么
  2. 日志能被截取吗 log4j_Java日志体系居然这么复杂?——架构篇
  3. bzoj5017 [Snoi2017]炸弹
  4. Map/Reduce
  5. 可用于wpf的图表控件:WPFTookit Chart
  6. Python笔记:使用pywin32处理excel文件
  7. XML读取信息并显示
  8. Handler用法总结
  9. C++ 模板何时被实例化
  10. 修改Tomcat欢迎界面为自己项目界面