这是一道非常典型的JS闭包问题,结果和具体的解析请看这里

对于其中的`函数作用域链的问题`博主似乎没有解释清楚,有一些疑问:js中的变量到底是沿着作用域链还是原型链查找呢?

首先,要分清作用域链与原型链的区别,简单来说

作用域链是相对于函数的,原型链是相对于对象的

js中访问变量有多种方式
1. 直接通过标识符访问
2. 通过 . 或 [] 访问对象中的标识符

猜想访问方式不同,导致了查找的方式不同:
1. 直接通过标识符访问,访问的可能是函数中的标识符,也可能是全局对象(浏览器中是 window)的标识符,也就是说,可能沿着作用域链也可能沿着原型链访问
2. 通过 . 或 [] 访问对象中的标识符,js会沿着原型链查找

对于第二点,以下的小测试可以证明

① 相当于调用 window.test(),this 指向 window,访问的是 window.a;

② 中 this 指向 o,访问的是 o.a;

将全局的 a, 也就是 window.a 和 o.a 删除之后,得到的结果均是 1。

因此,通过 . 或 [] 访问`对象`中的标识符,js会沿着原型链查找。

第一点,直接通过标识符访问,也就是访问当前执行上下文EC的作用域中的变量,这一过程称为标识符解析,依赖于作用域链。

作用域链Scope其实就是对执行上下文EC中的变量对象VO|AO有序访问的链表

关于作用域链与执行上下文 EC 的关系,请看这里

测试

把 this.a 改为 a,②的结果就变啦。

① 和 ② 的执行上下文EC(即 this 的指向)分别为 window 和 o,但作用域链都是 test变量对象 + 全局变量对象。而test变量对象中没有 a,全局变量对象含有 a 。这就说明,在函数中直接通过标识符变量,js会沿着作用域中查找。

有趣的是,当删除了全局变量对象中的 a,再访问 a,浏览器并没有报错,而是输出 4;删除 Window.prototype.a 之后,输出的这是 1.
在 test 中添加一下代码 :

由结果可知,访问到的a 分别为 Window.prototype 和 Object.prototype 中的变量。

为什么呢?因为在浏览器中,全局变量对象在浏览器中指向 window, window 也是对象,且位于作用域链的末尾;作用域链查找完,仍然找不到,js 就会沿着全局变量对象的原型链查找。

结论

1. 直接通过标识符访问变量,首先沿着作用域链查找每一个变量对象,直到全局变量对象(window)仍没有,就沿着全局变量对象(window)的原型链查找
2. 通过 . 或 [] 访问对象中的标识符,就直接沿着原型链查找

js通过沿着作用域链还是原型链查找变量的更多相关文章

  1. 谈JS中的作用域链与原型链(1)

    学习前端也有一段时间了,觉得自己可以与大家分享一些我当初遇到疑惑的东西,希望能给对此问题有疑惑的朋友带来一点帮助. 先来普及一下JS的概念(不要嫌我啰嗦,可能一些朋友开始学习JS是跟着视频和写好的代码 ...

  2. JS的作用域链与原型链

    来一波,好记性不如烂笔头. 这两条链子可是很重要的. 作用域链 当执行一段JS代码(全局代码或函数)时,JS引擎会创建为其创建一个作用域又称为执行上下文(Execution Context),在页面加 ...

  3. js语言评价--js 基于哈希表、原型链、作用域、属性类型可配置的多范式编程语言

    js 基于哈希表.原型链.作用域.属性类型可配置的多范式编程语言 值类型.引用类型.直接赋值: 原型是以对象形式存在的类型信息. ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值,对 ...

  4. js 原型,原型链,原型链继承浅析

    对于网上的关于原型,原型链和原型链继承的晦涩语言说明就不累赘了,复制粘贴过来再解释一遍怕自己也整蒙了,本人最怕空气突然安静,四目对视,大眼对小眼,一脸懵逼. 我们先看下面

  5. 1--面试总结-js深入理解,对象,原型链,构造函数,执行上下文堆栈,执行上下文,变量对象,活动对象,作用域链,闭包,This

    参考一手资料:http://dmitrysoshnikov.com/ecmascript/javascript-the-core/中文翻译版本:https://zhuanlan.zhihu.com/p ...

  6. javascript作用域链与原型链有联系吗?

    一般来说,作用域链是针对变量的,js里面大的范围上来说,只有两种作用域,全局作用域和函数内部作用域,如果函数1里面又定义了函数2(一般都是匿名函数), 那么就有了这么一个作用域链全局作用域==> ...

  7. Js基础知识(二) - 原型链与继承精彩的讲解

    作用域.原型链.继承与闭包详解 注意:本章讲的是在es6之前的原型链与继承.es6引入了类的概念,只是在写法上有所不同,原理是一样的. 几个面试常问的几个问题,你是否知道 instanceof的原理 ...

  8. 在学习java之余,js的使用精髓-闭包和原型链

    这里分享下廖雪峰官网写的js教程,内容写的比较实用,易懂,其中简介的原型链和闭包的知识,小伙伴们一起上呀,畅游在知识的海洋中: 地址:https://www.liaoxuefeng.com/wiki/ ...

  9. js 中对象--对象结构(原型链基础解析)

    对于本篇对于如何自定义对象.和对象相关的属性操作不了解的话,可以查我对这两篇博客.了解这两篇可以更容易理解本篇文章 用构造函数创建了一个对象  obj对象的本身创建了两个属性  x=1   ,y=2 ...

随机推荐

  1. Android自定义控件View(一)

    虽然Android API给我们提供了众多控件View来使用,但是鉴于Android的开发性,自然少不了根据需求自定义控件View了.比如说QQ头像是圆形的,但是纵观整个Android控件也找不到一个 ...

  2. 学习鸟哥的Linux私房菜笔记(17)——Linux引导流程

    一.系统引导流程 第一步:固件fireware(CMOS/BIOS)--POST加点自检(与操作系统无关) 这一步主要是检查硬盘等硬件是否能正常工作 CMOS:是固化在主板上,详细:http://sc ...

  3. T-SQL部分函数(转)

    函数类别 作用 聚合函数 执行的操作是将多个值合并为一个值.例如 COUNT.SUM.MIN 和 MAX. 配置函数 是一种标量函数,可返回有关配置设置的信息. 转换函数 将值从一种数据类型转换为另一 ...

  4. 监控Nginx服务的Shell脚本

    Nginx 虽然处理并发量比 apache 确实要强点,但它这种 php-cgi 模式不是太稳定,这点网上也有朋友总结了,我在实现项目中也感受到了. 我们一台支付机,偶尔会出现以下情况的:php-cg ...

  5. 在navicat上设置定时计划执行存储过程

    原文 应用情景: 有一个存储过程,需要每天定时执行一次.所以在navicat上使用事件处理,当然还有其他的方法,这只是一种.作为参考 1.事件定义填写 2.事件计划设置 3.保存 点击上方保存即可 常 ...

  6. [MFC]SDI在图片背景上实现文本跟随鼠标移动

    SDI是单文档接口应用程序的简称.本文要实现的是在视图区域显示一张图片,然后在图片表层显示文字,并且文字跟随鼠标移动.思考一下,可以判断这个问题一共分为以下几个部分:1.显示图片:2.找到鼠标的位置: ...

  7. React Native中的DeviceEventEmitter.addListener与DeviceEventEmitter.emit

    官方文档没有对这两个方法做很好的解释,需要自己找资料研究.看了几篇文章,总结是和订阅发布模式差不多,用来事件监听发送的. React Native学习之DeviceEventEmitter传值   R ...

  8. 【27.48%】【codeforces 699D】 Fix a Tree

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  9. GridLayout网格布局

    网格布局特点: l  使容器中的各组件呈M行×N列的网格状分布. l  网格每列宽度相同,等于容器的宽度除以网格的列数. l  网格每行高度相同,等于容器的高度除以网格的行数. l  各组件的排列方式 ...

  10. zedboard之GPIO驱动器(离FPGA直到LINUX申请书)

    笔者:xiabodan   资源: http://blog.csdn.net/xiabodan/article/details/24308373 1 EDK 大家知道我们在EDK中建立GPIO然后倒出 ...