JS基础知识总结(一)

全局作用域

打开浏览器时,浏览器会形成一个全局作用域,给当前代码提供运行环境,并存储基本数据类型值
基本数据类型存储在栈内存中,全局作用域最大的一个栈内存
window 是全局下最大的对象,里面存储了大量的内置属性
window中天生自带一个window属性

浏览器渲染机制:

先形成dom树 然后css树 最后形成render树
dom的回流和重绘

变量

带var和被function过,都是变量。

全局变量

1.会给window新增一个键值对
2.全局下定义的函数,相当于给window新增键值对,属性名是函数名,属性值是整个函数

私有变量

1.在函数体中被var,被function过,是一个私有变量;
2.函数的形参也是私有变量

带var 不带var的区别

在全局作用域下
var n = 13;=>有变量提升阶段
n = 13;=>没有变量提升阶段
1.带var关键字的会变量提升,不带var的没有变量提升阶段
2.都是window的属性
3.带var可以不赋值,相当于给全局对象window增加一个属性,不带var的必须赋值,否则
- 逗号分隔表示都var了,相当于省略了写var

var a =1,b=2,c=3;
  • 分号分隔,前面带var的属于变量。不带var的相当于给全局对象增加了一个属性。
var a =1;b=2;c=3;
  • 连等,前面带var的属于变量。不带var的相当于给全局对象增加了一个属性
var a = b =c =1;

函数定义的步骤

1.首先开辟一个堆内存 假设引用地址是fff000
2.把函数体里的内容以字符串的形式存在堆内存里
3.把引用地址赋给函数名sum,sum代表整个函数

函数运行步骤:

1.形成私有作用域
2.形参赋值
3.变量提升
4.代码从上往下执行
5.作用域是否销毁

无节操之变量提升(特殊情况)

  • 只对等号左边的进行变量提升
  • 等号右边函数作为值存在时不进行变量提升
  • ruturn右边的代码不进行变量提升,下面的代码还是要变量提升的
  • 不管条件是否成立,带var关键字的都会进行变量提升 带function关键字,标准浏览器只声明不定义,在ie老版本浏览器下会声明+定义
  • 自执行函数本身不会变量提升
  • 在块级作用域形成之后,先对function进行定义(块级作用域:if、else、for,if和else是两个块级作用域)
  • 重名变量,重名变量不会重复声明,但是会重复定义
  • let const 不进行变量提升
  • 函数当作参数时,不进行变量提升
setTimeout(function f2(){},13)
  • 条件判断的函数:在条件判断之前,带var和带function都只声明不定义,当条件判断成立以后,第一件事是给函数赋值,条件不成立,判断体不执行了,结合了es6的块级作用域

匿名函数

自执行函数:当代码运行到这一行时,定义和执行一块完成;
匿名函数不进行变量提升

in检测属性名是否属于这个对象的

if(!("a") in window){
     var a = 100;
}
console.log(a)=>undefined

对象的定义

  • 开辟一个空间地址,堆内存
  • 把键值对存储在堆内存里
  • 把空间地址赋值给对象名;

块级作用域

除了私有作用域和对象以为{}包裹的作用域都是块级作用域

变量提升阶段

这是一个阶段,在当前作用域下,对带var关键字和function关键字的提前声明和定义
var关键字:提前声明 在内存里有变量,但没有赋值 值是undefined

let(es6)和var(es5)的区别

  • 通过var定义的变量有变量提升,通过let定义的变量没有变量提升
  • let定义的变量不会是window的属性
  • let在当前作用域里,变量不能重名

暂时性死区

在块级作用域下,用let不能提前拿到声明的变量,这个叫做暂时性死区

const 常量

  • 通过var定义的变量有变量提升,通过const定义的变量没有变量提升
  • const定义的变量不会是window的属性
  • 在当前作用域里,变量不能重名,
  • 不能重复赋值,重复赋值就会报错
  • 声明的变量,如果值是基本数据类型,那么不可以修改,如果值是引用数据类型,可以操作引用地址,不可以替换引用地址
  • const声明的常量必须赋值,不赋值会报错

如何判断是否是私有变量

1、当前变量有没有被var过,function过
2、形参也是私有变量
3、如果变量不是私有的,向上一级作用域查找
4、上一级作用于判断函数在哪定义的,函数上一级作用域就是谁,跟函数执行没有任何关系;
5、当获取变量值时,首先看知否是私有变量,如果不是会向上一级作用域查找,如果上一级作用域也没有,那么会继续向上查找,知道找到window为止,如果window也没有,那么就会报错,这样一级一级向上查找形成的作用域就是作用域链

栈内存 : 作用域:

  • 打开浏览器会形成一个栈内存全局,函数执行的时候形成一个栈内存私有,栈内存一般情况下,是让js运行的环境
  • 栈内存释放:全局下的栈内存,关闭页面或者关闭浏览器都可以释放该栈内存,函数执行结束后,一般情况下栈内存私有就会释放
  • 不会释放:当栈内存中有引用数据类型,被外界变量、对象、元素上的一个属性所占有,导致该栈内存不被释放。
  • 引用数据类型都会开辟空间地址,如{}、[];
    谷歌浏览器:每隔一段时间,回去检查当前的空间地址有没有被占用;如果没有被占用,那么浏览器会将其回收;
    火狐、IE浏览器: 采用的是计数规则;当堆内存地址被占用一次,那么对当前进行计数+1,如果不再占用那么就会-1;如果当前地址被占用0次;那么马上将其回收;

堆内存:

  • 浏览器加载时,碰到引用数据类型,都会开辟一个新的内存空间,对象:键值对;函数:代码字符串。给这个内存空间赋值一个16进制的内存地址,将这个内存地址指向声明的那个变量,这个内存空间就是堆内存。
    堆内存释放:
    需要手动将该内存指向null,指向空指针,浏览器判断该堆内存没有变量接收它,浏览器会在空闲的时候将其释放。

查找上级作用域:

  • 上一级作用域判断函数在哪定义的,函数上一级作用域就是谁;跟函数执行没有任何关系;
  • 当获取变量值时,首先看是否是私有变量,如果不是会向上一级作用域查找,如果上一级作用域也没有,那么会继续向上查找,直到找到window为止,如果window也没有,那么就会报错;这样一级一级向上查找形成的作用域就是作用域链;
var a = 4;
        function b(x, y, b) {
            console.log(a);//4
            arguments[2] = 10;
            console.log(a);//4
        }
        a = b(1, 2, 3);
        console.log(a);//undefined    没有return

闭包——是一种浏览器机制

在函数运行时形成一个保护里面变量不受外界污染的私有作用域,这就称之为闭包,闭包是一种机制,存储值。
保存机制:当前私有作用域中,有引用数据类型被外界占有,导致当前作用域变成一个不销毁的
- 封装性
- 保护的作用
函数执行的一瞬间就会形成闭包;

闭包的几种形式

1.自执行函数
- window.xxx = xxx;(把函数里面的值赋给全局下的)
- 自执行函数(匿名函数) 定义加执行一次性完成。

//自执行函数例子
var name = "lily";
    var age  = 20;
    ~(function(name,age){
        var total = 10;
        window.total = total; //把total赋值给全局下total变量

         //下面这种不带var的定义方式不推荐
         //name = "lucy";
         //age = 30;

      })(name,age)//函数运行的小括号里传的是实参
       console.log(total);  =>10

2.函数内部返回一个函数
- 预处理机制(柯里化函数思想):有些内容现在先提前处理下,但还有部分逻辑现在不需要处理,等你自己执行返回的函数再处理 例如:bind方法就是利用这种思想
- 在返回小函数之前,先提前把公有的内容定义好,小函数执行时就能获得这些公有的内容。

function fn(){
var i = 0;
return function(){
i++;
}
}
console.log(fn());

3.函数的内部返回一个对象
- 解决公有和私有的问题
- 把需要暴露给外界的内容,放在对象中给返回

 //解决闭包公有和私有的问题
    var utils = (function(){
        var a = 10;
        function get(){
            console.log("get");
        }
        function set(){
            console.log("set");
        }
        function fn2(){console.log("fn")};

        return { //通过对象暴露内部的函数或变量
            get:get,
            set:set
        }
    })()
//     fn2(); 获取不到里面的函数
    utils.get() //获取闭包暴露出来的函数=>get
例题:
<body>
<input type="button" value="0">
<input type="button" value="1">
<input type="button" value="2">
<input type="button" value="3">
</body>
<script>
   var oBtns = document.getElementsByTagName("input") ; 
   //思路1:
   for(var i=0; i<oBtns.length;i++){
       oBtns[i].onclick = (function (i) {
           return function () {
               alert(i);
           }
       })(i);
   }

//思路2:
for(var i=0; i<oBtns.length;i++){
           changeTab(i)
   }
    function changeTab(i) {
        oBtns[i].onclick=function () {
            alert(i);
        }
    }


//思路3:es6写法 通过let定义变量
 for(let i = 0;i<oBtns.length; i++){
        oBtns[i].onclick=function () {
            alert(i);
        }
    }
</script>

作用域销毁

  • 全局作用域:关闭页面或关闭浏览器时销毁
  • 私有作用域:通常情况下,函数运行完后就销毁了;
  • 函数每次执行都会开辟一个新的私有作用域,并且新的私有作用域跟之前作用域没关系,是两个不同的栈内存
    • 不销毁:函数内部的内容被外界占用了,这时作用域就不能销毁了
      • 函数执行return出一个引用数据类型的值
      • 函数执行return出的引用数据类型值并且被外界接收;
    • 不立即销毁:函数运行完后返回一个需要被执行的小函数,只有等小函数运行完后,这个函数运行产生的作用域才能被销毁

堆内存销毁

堆内存的引用地址赋给变量了,这时堆内存就销毁不了了,解决办法:把变量设成null,变成空指针,浏览器在空闲时会释放对内存,这就是垃圾回收机制。

this

this在作用域下有特殊意义
指函数运行时调用的主体,谁让函数执行的,this就指向谁(this只能代表值,不能赋值)
- 1、在全局作用域下,this指向window
- 2、方法运行时,方法名前面有没有“点”,若有“点”,“点”前面是谁this指的就是谁,若没有则this指的是window
- 3、自执行函数的this永远指向window
- 4、事件驱动函数运行里的this是绑定的元素
- 5、回调函数的this指向window
- 6、像forEach map…第二个参数可以修改this的指向
oInput[i].onclick = function () {
alert(this.zhufeng)//绑定的元素 oInput[i]
}

- 7、构造函数中this指向当前类的实例
- 8、call、apply、bind可以改变this关键字
- 9、原型中的this,需要看函数执行前面有没有点,点前面是谁,this就是谁。

//每次点击都累加1
    //方法1:
var oDiv = document.getElementById("div1");
var i = 0;
;(function(){
oDiv.onclick = function () {
    this.innerHTML = ++i;
}
    })()

//方法2:
    var oDiv = document.getElementById("div1");
    oDiv.onclick = function () {
    var i = 0;
    return function () {
        this.innerHTML = ++i;
    }
    }()
//自定义属性的方式
    var oDiv = document.getElementById("div1");
    oDiv.index = 0;
    oDiv.onclick = function () {
        this.innerHTML = ++this.index;
    }
var i = 5;
    function fn() {
        i+= 2;
        return function (n) {
            console.log(n+--i);
        }
    }
    var f = fn();
    f(3);//9
    fn()(4);//11
    f(5);//11
 var num = 3;
    var obj = {
        num:5,
        fn : (function(){
            this.num*=2;
            var num = 4;
            return function(){
                this.num *=2;
                num *= 4;
                alert(num);
            }
        })()
    }
    var fn = obj.fn;
    alert(num);//6
    fn();//16
    obj.fn();//64
    console.log(window.num,obj.num);//12,10

for循环中用let

会形成父作用域,每循环一次,都会形成一个子作用域;在子作用域中会把当前的i进行保存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值