在介绍区别之前,我们先来看下解决这个需求的两种方式:

  • 需求:验证:name或者age是不是obj的属性
  1. var obj = {
  2. name: '小芝麻'
  3. };
  4. 复制代码

方法一:基于判断属性值是否为undefined来验证是否有这个属性(不专业方案)

if (obj.name !== undefined) {
    // OBJ中存在这个属性
}
if (obj['age'] === undefined) {
    // OBJ不存在这个属性
}
复制代码

方法二:基于检测符 in 来检测当前属性是否属于这个对象 =>语法: 属性名 in 对象(专业方案)

if ('age' in obj) {
    // AGE是OBJ属性返回TRUE,不是它的属性返回FALSE
}
复制代码

在讲解全局执行上下文中:带VAR不带VAR的区别,我们需要先了解全局对象和全局变量对象的区别

思维导图

33.在全局私有上下文中:带VAR和不带VAR的区别 - 图1

一、全局对象和全局变量对象的区别

之前我们说过浏览器想要把代码执行就需要先有个执行环境栈ECStack;

与此同时也会创建一个全局对象GO;和其他的引用类型值一样,也存储在堆内存中,有一个十六进制的空间地址; 这里存储了很多内置的属性和方法;

  • 执行环境栈ECStack中有个window,让window指向这个全局对象的空间地址;
  • 我们平时用的alert("xxx")的方法,全称:window.alert(...),只不过我们平时省略了window;

1、全局对象

  • 全局对象:

    • 浏览器默认会自带很多供JS调取使用的内置API,这些属性方法都在GO中存储着,在浏览器端,把GO对象赋值给window,在node端把GO赋值给了global

我们在控制台详细输出window,看一下;

33.在全局私有上下文中:带VAR和不带VAR的区别 - 图2这些就是我们的全局对象中的内容

2、全局变量对象

全局变量对象:

  • 当全局代码执行过程中,会声明一些变量,这些变量存储在全局变量对象VO

总结:综上所属,我们知道:

  • 全局对象GO:是浏览器天生自带的存储属性和方法的堆,是一个对象;
  • 全局变量对象VO:是我们自己写代码创建的变量要存储的地方;是栈内存;

完全是两个不同的东西

二、全局执行上下文中:带VAR不带VAR的区别

“在全局执行上下文中”,带VAR不带VAR定义值是两套不同的机制

  • 带VAR是创建一个全局变量,存放在全局变量对象VO(G)
  • 不带VAR创建的不是变量,而是全局对象GO(global object)的一个属性

知道了上面的内容,我们来用例题分析一下:

var n = 100;
console.log(n);
console.log(window.n);
m = 200;
console.log(m);
console.log(x);
复制代码

33.在全局私有上下文中:带VAR和不带VAR的区别 - 图3

总结:

全局上下文中:

  • 基于VAR创建变量,会给VO(G)GO中各自存储一份,
  • 不带VAR的,只是给GO设置一个属性而已;
  • 当我们输出这个变量值的时候,首先看是否为全局变量,是则输出全局变量的值,如果不是,则在看是否为全局对象的属性,如果再不是,则报错!!

三、私有执行上下文中:带VAR不带VAR的区别

  • 1、带VAR的情况

在函数里:var x=100;

  • 在私有上下文的AO(FN)变量对象中声明一个x的私有变量(x是当前上下文的私有变量,和上下文以外没有必然联系)
  • 2、不带VAR的情况

在函数里: y=200;

  • 1、浏览器发现y不是私有变量,则向其上级上下文中查找(按照SCOPE-CHAIN(作用域链,我们下一篇文章会说)查找),如果上级也没有则继续查找…一直到EC(G)全局上下文为止,找到哪一级,就是哪一级的变量
  • 2、如果找到全局也没有,则给GO(window)设置一个属性:window.y=200

四、全局和私有上下文中带var的区别;

  • 全局执行上下文中:基于VAR创建变量,会给VO(G)GO中各自存储一份;
  • 私有执行上下文中:只在私有变量对象AO中创建了变量,没有给window添加属性;

五、例题

1、输出结果

/*
 * 全局上下文中的变量提升
 *     var a;
 *       ->给VO(G)中新增一个全局变量 a
 *       ->给GO中新增一个属性 a
 *       ->默认值都是 undefined
 */
console.log(a); //=>undefined
if (!('a' in window)) {
    // 'a' in window 检测a是否为window的一个属性 =>TRUE
    // !true => FALSE  条件不成立
    var a = 13;
}
console.log(a); //=>undefined
复制代码

2、输出结果

/*
 * 全局上下文中的变量提升(最新版本浏览器中)
 *     function fn;
 *       ->VO(G)中存在一个fn全局变量
 *       ->GO中存在一个fn属性
 */
console.log(fn); //=>undefined
// fn();//=> undefined() =>Uncaught TypeError: fn is not a function  JS中,一但当前代码报错,那么下面的代码都不会再执行了
if ('fn' in window) { 
    fn(); 
    function fn() {
        console.log('哈哈哈');
    }
}
fn();
//================================================
/*
 * 全局上下文中的变量提升(最新版本浏览器中)
 *     function fn;
 *       ->VO(G)中存在一个fn全局变量
 *       ->GO中存在一个fn属性
 */
console.log(fn); //=>undefined
if ('fn' in window) {  //=>TRUE
    // 进来第一件事情:给FN赋值  fn=function(){ ... }
    fn(); //=>'哈哈哈'
    function fn() {
        console.log('哈哈哈');
    }
}
fn(); //=>'哈哈哈'