天天看点

内存空间、变量提升、作用域、this指向

一、内存空间

JS中每个数据都需要内存空间来存储,内存空间分对堆内存(stock)和栈内存(head)

  1. JS中的基本数据类型有固定的值大小保存在栈内存中
  2. JS中的引用数据类型大小值不固定,一般保存在堆内存中,JS不允许我们直接访问堆内存的位置,当我们访问引用数据类型的时候,实际是访问栈内存中保存的堆内存的引用地址

demo1:

var a = 12;
var b = true;
var c = 'abcd';
var d = {a:1}
           
内存空间、变量提升、作用域、this指向

demo2:

var a = 12;
var b = true;
var c = 'abcd';
var d = {a:1}
var e = c;
var f = d;
           
内存空间、变量提升、作用域、this指向

当var e = c; 复制基础数据类型时候会为新的变量赋值一个新值,虽然var e = c; 都是'abcd',但是e和c是两个相互不影响的新值

当var e = d; 复制引用数据类型的时候统一为了新的变量赋予新值,不同的是这个新值只是引用类型的地址指针,尽管相互独立。但是在堆内存中访问的数据仍然是同一个

实际应用中:要注意深拷贝和浅拷贝。

二、变量提升

  1. 函数及变量的声明都将被提升到函数的最顶部。
  2. 变量只有声明提升了,赋值不提升
  3. 函数内不声明直接使用的变量,创建的变量会按照作用域来查询来赋值

三、作用域

概念:

      执行环境定义了变量或者函数有权访问其他数据。每个执行环境都有与之相关的变量对象。环境中所定义的所有变量和函数都保存在这个变量对象中,代码无法访问,但是解析器在解析的时候会使用它

关键字:

作用域链:词法语法分析、生成代码,代码执行

  1. 每个函数都有自己的执行环境,当执行流入一个函数的时候,函数的环境就会被推入一个环境栈中,当函数执行之后,栈将其环境弹出,把控制权返回之前的执行环境
  2. 当代码在一个环境中执行的时候,会创建变量对象的一个作用域链
  3. 作用域链中的变量对象来自外部环境中。下一个变量对象来自一个环境,一直延伸到全局环境
  4. 标识符的解析是沿着作用域链一级级搜索标识符的过程,逐级向后回溯知道找到标识符的位置
  5. 保证对作用域链中所有变量和函数的有序访问
  6. 函数的作用域在创建的时候就获得了
  7. scope是函数的一个内部属性,他是所有父级变量对象的层级链
  8. 内层Scope可以访问外层Scope的变量
内存空间、变量提升、作用域、this指向
var a = 10;
        function testScope(arg) {
            var a = 10;
            function ab() {
                a = 20;
                var c = 2;
                console.log(a);
            }
            ab();
            console.dir(ab);
            console.dir(testScope);
            console.log(a);
        };
        testScope('hi');
        console.log(a);
           
内存空间、变量提升、作用域、this指向

四、this指向

  • Global context全局上下文中 指向window
  • simple call  独立调用 指向window
  • function context  this由函数怎么调用实现
  • arrow function  由词法或者静态作用域设置
  • As an Object method 当作为函数方法调用的时候 指向函数本身
  • 构造函数 new 方法中 指向被constructed 的新对象
  • call apply 指向运行时的this
  • bind  创建新函数 函数体和作用域和之前一样 但是 this 被永久绑定到传入的this中
  • As a Dom event handler this为触发事件的dom元素 

闭包:就是函数和函数声明时候作用域的组合

做几道题来加深理解

var name = 'window';

        var example1 = {
                name:'test',
                say1:()=>{
                console.log(this.name);
        },
        say2:()=>{
            return () =>{
                console.log(this.name);
            }
        },
        say3:()=>{
            return function(){
                console.log(this.name);
            }
        },
        say4:function () {
            console.log(this.name);
        },
        say5:function(){
            return function(){
                console.log(this.name);
            }
        },
        say6:function(){
            return () =>{console.log(this.name)};
        },
        }
        example1.say1();
        example1.say2()();
        example1.say3()();
        example1.say4();
        example1.say5()();
        example1.say6()();

        
        //
        function sayBye(){
            console.log(this.name);
        }
        sayNo = () =>{
            console.log(this.name);
        }

        var testObj = {
            name:'testObj',
        }
        testObj.sayBye = sayBye;
        testObj.sayNo = sayNo;

        testObj.sayBye();
        testObj.sayNo();

        example1.say1.call(testObj);
        example1.say1.apply(testObj);

        example1.say4.call(testObj);
        example1.say4.apply(testObj);

        example1.say4.bind(testObj)();
        example1.say1.bind(testObj)();

        //
           
//window   window window  test window  test      
//testObj window  window window testObj testObj  testObj  window