JavaScript变量、执行上下文、作用域、作用域链

1.1 原始值和引用值

ECMAScript变量可以包含两种不同类型数据:原始值和引用值。

  • 原始值:最简单的数据(基本数据类型)
  • 引用值:由多个值构成的对象(引用类型)

1.2 值复制

复制原始值时:修改复制后的值,原先的值不回被改变
复制引用值时:修改复制后的值,原先的值会被改变,因为它复制的是地址(指向对象的指针)而不是值

1.3 执行上下文

每一段程序都有很多外部变量。一旦你的一段程序有了外部变量,这段程序就不完整,不能独立运行。你为了使他们运行,就要给所有的外部变量一个一个写一些值进去。这些值的集合就叫上下文。

1.4 变量作用域

变量在声明它的函数体和嵌套的(父级,不包括同级和子级)函数体内都是有定义的。

换句话说,变量声明在全局作用域中均有效。

例:

        var scope = 'global';
        function t() {
            var scope;
            console.log(scope);//undefined
            scope = 'local';
            console.log(scope);//local
        }
        t();
    因此函数内声明的 scope 覆盖了全局变量 scope
    又因为没有给它赋值,所有输出的是 undefined
        var name = 'global';
        if (true) {
            var name = 'local';
            console.log(name);
        };
        console.log(name);

同理由于变量在本身函数体内和嵌套的函数体内都有定义,因此后面定义的 name 会覆盖前一个 name 并作用于嵌套函数体中。

1.5 作用域链

因为变量定义在父子级中都可以使用,如果需要重复定义变量值,则会有访问时到底采用哪个变量值的问题,因此定义作用域链来规定变量的访问顺序。

(注:函数参数被认为是当前上下文的变量)

先看一段代码:

        name = 'xxh';
        function t() {
            var name = 'txxh';
            function s() {
                var name = 'sxxh';
                console.log(name);//sxxh
            }
            function ss() {
                console.log(name);//txxh
            }
            s();
            ss();
        }
        t();

函数调用时会创建一个包含其中变量的对象。
当调用函数 s 时,将创建函数的执行环境(对象),并将该对象置于链表开头,然后将外部函数 t 的对象链接在之后,最后是全局对象。

在函数执行时,从作用域链中查找变量,以便读、写值。

本作用域链为 s ( ) => t ( ) => window。

1.6 作用域链增强

  • with语句

    with语句主要用来增强作用域链,将语句的对象添加到作用域链的头部。

        person = {
            name: 'xxh',
            age: 24,
            height: 175,
            wife: {
                name: 'undefined',
                age: 24
            }
        };
        with (person.wife) {
            console.log(name);
        }

作用域链为:person.wife => window

with语句结束后,作用域链恢复正常

        function bulidUrl() {
            let qs = '?debug=true';

            with (location) {
                let url = href + qs;
            }

            return url;
        }

作用域链:location => bulidUrl => window

1.7 变量声明

ES6之前,var 都是声明变量的唯一关键字。ES6不仅增加了 let 和 const 两个关键字,而且还让这两个关键字压倒性的超越 var 成为首选。

  • var 声明

    var 声明会被拿到函数或全局作用域的顶部,位于作用域中的所有代码之前。这个现象叫 “提升” 。

        function add(num1, num2) {
            var sum = num1 + num2;
            return sum;
        }

        let result = add(10, 20);
        console.log(sum);//报错,这里sum不是有效变量
  • let 声明
    let 和 var 很相似,但它的作用域是块级的,这是JavaScript的新概念。块级作用域由最近的一对包含花括号 { } 界定。
        function foo() {
            let c;
        }
        console.log(c); // undefined ,因为 let 声明只在块级作用域中才能访问


        {
            let d;
        }
        console.log(d); //undefined

且不能对同一个变量重复进行 let 声明:

        function foo() {
            let c;
        }
        console.log(c); // undefined ,因为 let 声明只在块级作用域中才能访问

        {
            let d;
        }
        console.log(d); //undefined

let 声明变量只在块级作用域中有效的特点,非常适合在循环中声明迭代变量。

        for (var i = 0; i < 10; ++i) { }
        console.log(i);
        for (let j = 0; j < 10; ++j) { }
        console.log(j);
	使用var声明的迭代变量会泄露到循环外部;
	let则不回,let非常适合在循环中声明迭代变量
  • const 常量声明

    使用 const 声明的变量必须同时初始化为某个值。一经声明,在其生命周期的任何时候都不能重新复制。但如果声明的是引用类型,可添加属性。

        const a;//报错,没有初始化

        const b = 3;
        console.log(b);
        b = 4;//报错,一经初始化不能重新赋值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值