第一节预解释、作用域、this原理

--------------------------------------------预解释----------------------------------------------------
数据类型的分类:
基本数据类型
number、string、boolean、null、undefined

引用数据类型
object:{} [] /^$/ Date
function

基本数据类型和引用数据类型的本质区别:
基本数据类型是按照值来操作的,引用数据类型是按照内存地址来操作的

思考1:
var num=12;
var obj={name:'张三',age:18};
function fn(){
   console.log('i love you');
}

1、当浏览器加载HTML页面的时候,首先会提供一个供全局js代码执行的环境---->全局作用域(window)
2、按照以上思考1画图,分析。(易错点:fn存储的是一个地址,代表的是当前函数的整体)

3、预解释、变量提升
   var num=12;
   1>在当前的作用域中,js代码执行之前,浏览器首先会默认的把所有带var和function的进行提前的声明或者定义
   声明:var num;
   定义:num=12;

   2>对于带var和function关键字的在预解释的时候操作还是不一样的
   var -->在预解释的时候只是提前的声明
   function-->在预解释的时候是声明+定义都完成了

   3>预解释只发生在当前作用域当中,例如:开始只对Window下的进行预解释,只有函数执行的时候才会对函数中
   的进行预解释

4、js中内容的分类
   栈内存:用来提供一个供js代码执行的环境--->全局作用域
   堆内存:用来存储引用数据类型的值,-->对象存储的是属性名和属性值,函数存储的是代码字符串


----------------------------------------------------作用域链-------------------------------------------------------------

如何区分私有变量和全局变量:
1、预解释的时候,在全局作用域下声明的变量是全局变量
2、在私有作用域中声明的变量(预解释的时候)和函数的形参都是私有的变量

作用域链:在私有作用域中,我们代码执行的时候遇到了一个变量,首先我们需要确定它是否为私有的变量,如果是私有的
变量,那么和外面的没有任何关系,如果不是私有的,则往当前作用域的上级作用域进行查找,如果上级作用域也没有则继续查找,一直找到window为止

当函数执行的时候,首先会形成一个新的私有的作用域,然后按照以下步骤执行:
1、如果有形参,先给形参赋值
2、进行私有作用域中的预解释
3、私有作用域中的代码从上到下执行
...
函数形成一个新的私有的作用域保护了里面的私有变量不受外界干扰,这种保护机制我们称为闭包

在全局作用域中,带var和不带var的关系?
区别:带var的可以进行预解释,所以赋值的前面执行不会报错;不带var的是不能进行预解释的,在前面会报错

关系:num2=12--->相当于给window增加了一个叫做num2的属性名,属性值是12
var num=12 相当于给全局作用域添加了一个全局变量num,不仅如此,它也相当于给window增加了一个属性名num2,属性值是12

--------------------------------------------预解释是一种毫无节操的机制---------------------------
预解释是毫无节操的一种机制
1》在预解释的时候不管条件是否成立都要把带var的进行提前声明
2》预解释的时候只预解释“=”左边的,右边的是值,不参与预解释
3》自执行函数定义的function在全局作用域下不进行预解释
4》函数体中return下面的代码虽然不执行了,但是需要预解释,return后面跟着的function 是不进行解释的
5》在js中如果变量的名字和函数的名字重复了,也算冲突
//in 判断"num"是否为window这个对象的一个属性,是返回true 不是返回false

---------------------------------------------如何查找上级作用域-------------------------------------------

如何查找当前作用域的上一级作用域?
看当前函数是在那个作用域下定义的,那么它的上级作用域就是谁,和函数在哪执行的没有任何关系

------------------------------------------关于内存的释放和作用域销毁----------------------------------
堆内存
对象数据类型或者函数数据类型在定义的时候首先会开辟一个堆内存,堆内存有一个引用地址,如果外面有变量等知道了这个地址,我们就说这个内存在占用了,就不能销毁了
    var obj1={name:'张三'};
    var obj2=obj1;
    obj1=null;
    obj2=null;

我们想让堆内存释放(垃圾回收)/销毁,只需要把所有引用它的变量值赋值为null即可,如果当前的堆内存中没有任何东西占用了,那么浏览器会在空闲的时候把它销毁
小扩展:
谷歌浏览器会每隔几毫秒会把当前的内存从头到尾看一遍,看看有没有内容有没有被占用,如果内存没有占用,就会主动清理掉
Ie 火狐通过计数器的原理,比如obj1={name:'张三'}}这个堆内存,会在浏览器的某一个位置记录当前这个堆内容有一个被占用了,计一个1,obj2=obj1,计为2(堆内存被两个占用),obj1=null,计1,obj2=null计0,内容被释放了。
Ie容易计混,所以会出现泄漏的问题,详见高程3

栈内存    
1>全局作用域(浏览器天生开辟的)
当页面关闭的时候全局作用域才会销毁

2>私有作用域(只有函数执行会产生私有作用域)
 一般情况下,函数执行会形成新的私有的作用域,当私有作用域中的代码执行完成后,我们的当前作用域都会主动的进行释放和销毁
但是还是存在特殊情况的:当前私有作用域中的部分内容被作用域以外的东西占用了,那么当前作用域就不能销毁了
A、函数执行返回了一个引用数据类型的值,并且在函数的外面被一个其他的东西接收了,这种情况下一般形成的私有作用域都不会被销毁
    function fn(){
        var num=100;
        return function () {

        }
    }
    var f=fn();

B、在一个私有的作用域中给DOM元素的事件绑定方法,一般情况下我们的私有作用域都不销毁
    var odiv=document.getElementById('odiv');
    ~function(){
        odiv.onclick= function () {

        };
    }();


C、下列情况属于不立即销毁-->fn返回的函数没有被其他的东西占用,但是还需要执行一次,所以暂时不销毁,当返回的值执行完成后,浏览器会在空闲的时间把它销毁了--->不立即销毁

 function fn(){
     var num=100;
     return function () {

     }
 }
fn()();
//首先执行fn,返回一个小函数对应的内存地址,然后紧接着让返回小函数再执行
-----------------------------------------------this-----------------------------------------------------
this的关键字
不在函数中的this指的是window,比如:console.log(this);
我们在js中主要研究的是函数中的this。

js中的this指的是当前行为的主体。
     function 吃饭(){
        this---->张三
     }
     吃饭();
Js中context(上下文)代表的是当前执行的环境(区域)
张三在卧龙吃烤鱼  this指的是张三(当前的行为是由谁来发生的),卧龙就是上下文。
~function(){
   张三.吃饭();
}();
function sum(){
   张三.吃饭();
}
sum();
this指的是当前行为的主体,this是谁和函数在哪里定义的,和在哪里执行的没有任何关系,只和执行的主体有关系。

那么如何区分this呢?
1、函数执行的时候,看函数前面是否有”.”有的话,”.”前面是谁this就是谁,没有”.”this
就是window
思考:
    function fn() {
        console.log(this);
    }
    var obj = {fn: fn};
    fn();
    obj.fn();
    function sum(){
        fn();
    }
    sum();
2、自执行函数中的this永远是window
3、给元素某一个事件绑定方法,当事件触发的时候执行对应的方法,方法中的this是当前的元素
    function fn(){
        console.log(this);
    }
    document.getElementById('odiv').onclick= fn;
    document.getElementById('odiv').onclick= function () {
        fn();
    };
4、在构造函数当中,类中(函数体中)出现的this.xxx=xxx中的this是当前类的一个实例
5、this的第5种情况:使用call/apply/bind来改变this的指向(优先级最高)


----------------------------------------------综合练习-----------------------------------------------------
综合练习题1:
    function fn(){
        var i=10;
        return function (n) {
            console.log(n+(++i));
        }
    }
    var f=fn();
    f(10);
    f(20);
    fn()(10);
    fn()(20);


综合练习题2:
     function fn(i){
        return function (n) {
            console.log(n+(i++));
        }
    }
    var f=fn(13);
    f(10);
    f(20);
    fn(15)(10);
fn(16)(20);


综合练习3:
    var num = 20;
    var obj = {
        num: 30,
        fn: (function (num) {
            this.num *= 3;
            num += 15;
            console.log(num);
            var num = 45;
            return function () {
                this.num *= 4;
                num += 20;
                console.log(num);
            }
        })(num)
    };
    var fn = obj.fn;
    fn(); 
obj.fn();

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏web后端

PHP json中的Malformed UTF-8 characters问题

一般情形下,json嵌套层级太深这种失败是罕见,但是又相对比较容易识别的;另外一种错误,是关于utf-8编码的,则情形相对比较复杂;

5466
来自专栏决胜机器学习

设计模式专题(十六)——迭代器模式

设计模式专题(十六)——迭代器模式 (原创内容,转载请注明来源,谢谢) 一、概述 迭代器模式(Iterator)提供一种方法,顺序访问一个聚合对象中的每个元素...

3668
来自专栏开源优测

python selenium2 - webelement操作常用方法

完整路径 C:\Python27\Lib\site-packages\selenium\webdriver\remote\webelement...

3055
来自专栏鸿的学习笔记

Python的浅复制和深复制

在前文已经看到过了可以使用list函数去复制一个列表,这个就是浅复制,浅复制会构建一个新的对象,并且维护之前对象(子对象)的引用,而深复制则是将之前的子对象通过...

1254
来自专栏java学习

Java基础总结大全(1)

一、基础知识: 1、JVM、JRE和JDK的区别: JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性。 ...

39611
来自专栏java学习

Java基础总结大全(1)

一、基础知识: 1、JVM、JRE和JDK的区别: JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性。 ...

3545
来自专栏xx_Cc的学习总结专栏

C - 基础总结

35611
来自专栏大神带我来搬砖

在python中像java一样反射——动态实例化指定包下面所有的类

在项目中需要在python中把某个包下面所有的类都实例化一个对象,把这些对象放到一个集合中,在java中可以通过反射机制来实现,先获得这个包下面所有的Class...

4107
来自专栏Celebi的专栏

C/C++ 学习笔记七(内存管理)

工作中经常使用到C/C++,为对C有个比较深刻的了解,重新拾起学习C的任务。在看书的同时,记录下思考的过程,也记录下重要的知识点。

2670
来自专栏栗霖积跬步之旅

1.2使用多线程

一个进程正在运行时,至少会有一个线程在运行。线程在后台默默执行,比如调用main方法的线程就是如此,它是由JVM创建的。 class Test { pu...

2016

扫码关注云+社区

领取腾讯云代金券