顶层对象的属性

顶层对象,在浏览器环境指的是window对象,在Node指的是global对象。ES5之中,顶层对象的属性与全局变量是等价的。

window.a = 1;
a // 1 a = 2;
window.a // 2

上面代码中,顶层对象的属性赋值与全局变量的赋值,是同一件事。

顶层对象的属性与全局变量挂钩,被认为是JavaScript语言最大的设计败笔之一。这样的设计带来了几个很大的问题,首先是没法在编译时就报出变量未声明的错误,只有运行时才能知道(因为全局变量可能是顶层对象的属性创造的,而属性的创造是动态的);其次,程序员很容易不知不觉地就创建了全局变量(比如打字出错);最后,顶层对象的属性是到处可以读写的,这非常不利于模块化编程。另一方面,window对象有实体含义,指的是浏览器的窗口对象,顶层对象是一个有实体含义的对象,也是不合适的。

ES6为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。

var a = 1;
// 如果在Node的REPL环境,可以写成global.a
// 或者采用通用方法,写成this.a
window.a // 1 let b = 1;
window.b // undefined

上面代码中,全局变量avar命令声明,所以它是顶层对象的属性;全局变量blet命令声明,所以它不是顶层对象的属性,返回undefined

global 对象

ES5的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的。

  • 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window
  • 浏览器和 Web Worker 里面,self也指向顶层对象,但是Node没有self
  • Node 里面,顶层对象是global,但其他环境都不支持。

同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this变量,但是有局限性。

  • 全局环境中,this会返回顶层对象。但是,Node模块和ES6模块中,this返回的是当前模块。
  • 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined
  • 不管是严格模式,还是普通模式,new Function('return this')(),总是会返回全局对象。但是,如果浏览器用了CSP(Content Security Policy,内容安全政策),那么evalnew Function这些方法都可能无法使用。

综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。

// 方法一
(typeof window !== 'undefined'
? window
: (typeof process === 'object' &&
typeof require === 'function' &&
typeof global === 'object')
? global
: this); // 方法二
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};

现在有一个提案,在语言标准的层面,引入global作为顶层对象。也就是说,在所有环境下,global都是存在的,都可以从它拿到顶层对象。

垫片库system.global模拟了这个提案,可以在所有环境拿到global

// CommonJS的写法
require('system.global/shim')(); // ES6模块的写法
import shim from 'system.global/shim'; shim();

上面代码可以保证各种环境里面,global对象都是存在的。

// CommonJS的写法
var global = require('system.global')(); // ES6模块的写法
import getGlobal from 'system.global';
const global = getGlobal();

上面代码将顶层对象放入变量global

参考文档

02 | 顶层对象和global对象的更多相关文章

  1. 第一百零八节,JavaScript,内置对象,Global对象字符串编码解码,Math对象数学公式

    JavaScript,内置对象,Global对象字符串编码解码,Math对象数学公式 学习要点: 1.Global对象 2.Math对象 ECMA-262对内置对象的定义是:"由ECMASc ...

  2. JavaScript的内置对象(Global对象)

    内置对象的定义 由 javaScript 实现提供的.不用自己创建,这些对象在 ECMAScript 程序执行之前就已经存在了. 意思就是说,开发人员不必显示地实例化内置对象:因为它们已经实例化了. ...

  3. CSS 换行问题white-space属性 window对象和global对象

    white-space: nowrap禁止换行 1.word-wrap:break-word; 内容将在边界内换行,仅用于块对象,内联对象要用的话,必须要设定height.width或display: ...

  4. JavaScript的内置对象和浏览器对象

    在javascript中对象通常包括两种类型:内置对象和浏览器对象,此外,用户还可以自定义对象. 对象包含两个要素:1.用来描述对象特性的一组数据,也就是若干变量,通常称为属性.2.用来操作对象特性的 ...

  5. Nodejs随笔(三):全局对象之global

    首先,进入node REPL: mesogene@mesogene-team:~$ node > 查看global对象,发现其他全局对象(包括Buffer.require对象)以及全局方法都包含 ...

  6. JavaScript中的global对象,window对象以及document对象的区别和联系

    JavaScript中的global对象,window对象以及document对象的区别和联系 一.概念区分:JavaScript中的global对象,window对象以及document对象 1.g ...

  7. 5.7.1.3 Global 对象的属性

    Global对象还包含了一些属性,例如,特殊的值undefined.NaN以及Infinity都是Global对象的属性.此外,所有原生引用类型的构造函数,像Object和Function,也都是Gl ...

  8. 重操JS旧业第四弹:Date与Global对象

    1 Date原理 Date类型表示时间,js中采用UTC国际协调时间,以1971年1月1日0分0秒0微秒开始,经过的毫秒数来表示时间,比如一年的时间计算 1分:1000*60: 1小时:1000(毫秒 ...

  9. node基础—global对象(全局对象)

    global对象的__filename属性和__dirname属性 __filename属性:返回当前执行的文件的文件路径,该路径是经过解析后的绝对路径,在模块中,该路径是模块文件的路径,此属性并非全 ...

随机推荐

  1. kibana操作

    一些KIBANA的操作,记录下,免下次重复写 #创建索引名为kb_question的索引,并添加mapping,即各字段属性 PUT kb_question { "mappings" ...

  2. 关于cgroup的几个核心名词及其关系

    子​​​系​​​统​​​(subsystem) 所谓子系统可以理解为操作系统里的各种资源(组件),如CPU,内存,磁盘,网卡(带宽) 层​​​级(Hierarchies) 所谓层级就是子系统的集合,又 ...

  3. JavaScript --css样式

    1.JavaScript显示隐藏控制 隐藏:display:none; 显示:display:block; 参考链接:https://blog.csdn.net/sleepwalker_1992/ar ...

  4. 『Python』多进程

    Python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在Python中大部分情况需要使用多进程.Python提供了multiprocessin ...

  5. P4783-[模板]矩阵求逆

    正题 题目链接:https://www.luogu.com.cn/problem/P4783 题目大意 给出一个矩阵,求它的逆矩阵. \(1\leq n\leq 400\) 解题思路 记给出矩阵\(P ...

  6. P3760-[TJOI2017]异或和【树状数组】

    正题 题目链接:https://www.luogu.com.cn/problem/P3760 题目大意 给出\(n\)个数字的一个序列\(a\),求它所有区间和的异或和 \(n\leq 10^5,\s ...

  7. BufferedInputStream与BufferedOutputStream的缓存底层实现

    首先观察BufferedInputStream 的继承体系,可以看出他是继承自一个FilterInputStream,而这个又是继承自InputStream 我们在之前的装饰器模式就讲过,这个Buff ...

  8. Unity——可复用背包工具

    Unity可复用背包工具 Demo展示 设计思路 游戏中有非常多的背包样式,比如玩家道具背包,商城,装备栏,技能栏等:每个形式的背包都单独写一份逻辑会非常繁琐,所以需要有一套好用的背包工具: 这些背包 ...

  9. golang []byte和string的高性能转换

    golang []byte和string的高性能转换 在fasthttp的最佳实践中有这么一句话: Avoid conversion between []byte and string, since ...

  10. 洛谷3721 HNOI2017单旋(LCT+set+思维)

    这题难道不是spaly裸题吗? 言归正传QWQ 一看到这个题目,其实第一反应是很懵X的 从来没有见过类似的题目啊,什么\(spaly\),单旋.QWQ很懵逼啊 不过,我们可以注意到这么一件事情,就是我 ...