JS 基础知识复习

作为一名前端工程师,js的重要性毋庸置疑,但是js的教程呢,感觉是群魔乱舞,要么是后端大佬的解读,要么是半桶水的解读,让人十分困惑,当然,可能就是自己菜而已,理解的不深入,提到this总是让人瑟瑟发抖,各种this的面试题总有让你直呼不懂的地方,不过呢,最近看到了B站上一个视频教程,讲的比较清楚,对于堆栈,函数执行,this指向等问题做了比较详细的解答,今天算是自己的复习理解,如果发现有哪些地方自己不清楚的,在回去看一遍,加深理解。

那就一个一个的来吧,

如何查找上级作用域????其实很简单,就一句话

这个函数在哪个作用域下定义的,那么它的上级作用域就是谁,和函数在哪儿执行没半毛线关系
文字描述比较苍白,看下面的一个例子吧

    <script>
        var num = 12;
        function fn() {
            var num = 120;
            return function () {
                console.log(num); 
            }
        }
        var f = fn();
        f()
        ~function () {
            var num = 1200;
            f()
        }()
    </script>

//结果都是120,因为返回的函数是定义在fn里面,而fn里面的num=120,所以结果都是120

关于内存释放和作用域销毁!!

  • 堆内存 一般手动销毁就是设置为null
  • 栈内存,这里的情况就稍微复杂一点
    1. 如果不小心形成了闭包,那么是不会销毁的
    2. 在一个私有作用域中,给DOM元素绑定事件,一般情况下,这个私有作用域是不会被销毁的,可以参考下面的例子2

例子1

function fn(){
var num=10;
return function(){
}
}

var f=fn()

例子2

<div id="div1">点我啊</div>
//script

~function(){
     var odiv=document.getElementById('#div1');
      odiv.onclick=function(){
      xxxx
}

}()


其实这个不销毁的原理和上面的是一样的,因为dom元素也是一个对象,默认情况下,dom元素对象里面的onclick属性=null,但是我们给他赋值为一个方法之后,导致这个方法被本作用域外不引用了,请看下图

js数据类型分为基本数据类型和复杂数据类型,复杂数据类型基本就是指对象了(包括,对象,数组,函数)
基本数据类型都存储在内存的栈中
复杂数据存储在堆中

JS在执行的过程中,会先预解释,也就是变量提升,然后在从上往下执行,碰到复杂类型数据,就在放在堆中,并且将地址赋值给栈中的变量
这里需要提一下,函数在定义的时候,堆里面只是存的是函数体里面的字符串,等到函数执行的时候,会将代码放到栈里面来执行

函数在执行的时候,会在栈里面开辟出一个空间,作为函数的私有作用域,然后里面也会有一系列的流程
1,形参赋值
2,预解释
3,从上往下执行
执行完之后,一般会将这个栈空间销毁,也叫出栈。
这里又会引出一个概念,闭包,这个空间就不会被销毁
要形成闭包呢,需要在一个私有作用域中,也就是一个大函数中,返回一个引用类型的数据,最关键的地方是,这个返回的数据要被赋值给外面的一个变量,这样子,在这个作用域之外的地方也有变量引用了这个数据,此时就形成了闭包。
之前呢,我一直以为函数里面返回了函数,就形成了闭包,事实上不是,还需要非常关键的被外界引用

然后就是this指向了。
this指向的是当前行为的执行主体,JS里面还有context(上下文)的概念,就是这个主体所处在的环境(区域),
例如:张三 在 沙县 吃云吞 =》this就是张三,context就是沙县小吃,行为就是吃云吞,this和context没有啥必然联系,张三可以在沙县吃,也可以在上海小混沌吃,对吧
this的指向与方法在哪儿定义和在哪儿执行没有啥关系,那么如何判断this指向呢,很简单,下面的规律
1,如果某个函数前面有“.”,那么这个“.”前面是谁,this就是谁,如果没有“.”,那this就指向window
2,自执行函数里面的this永远指向window
3,给元素中的某一个事件绑定方法,当事件触发的时候,执行对应的方法,方法中的this就指向当前元素

`html

点我啊

function fn(){
console.log(this);
}
var obj={fn:fn};
fn(); //this=>window
obj.fn() // this=>obj
function sun(){
console.log(this) //window
fn() // this=>window
}
sun();
var oo={
sum:function(){
console.log(this) // oo
fn(); //this=>window
}
}
oo.sum()

document.getElementById("#div1").onclick=fn //此时fn里面的this指向#div1

document.getElementById("#div1").onclick=function(){
console.log(this); // this指向#div1
fn() // this指向window

}
//上面是规律,下面看看一道面试题
var num = 20;
var obj = {
num: 30,
fn: (function (num) {
this.num *= 3;
num += 15;
var num = 45;
return function () {
this.num *= 4;
num += 20;
console.log(num);
}
})(num)
};
var fn = obj.fn;
fn(); //65
obj.fn();//85
console.log(window.num, obj.num); //240 120


这是例子
var obj={
name:'张三',
say:function(){
console.log(window)
console.log(this.name)
}
}

obj.say(); //张三
var o1=obj.say
o1();// this指向window

在来一个例子

function Fn(name) {
this.name = name;
this.say = function () {
console.log('hello' + this.name + 'hahahaah');
}
}

var f1=new Fn("张三");
f1.say() //say 函数里面的this 指向需要say执行的时候来确定 此时say前面的“.”前面是f1,那么这this指向的就是f1
// 构造函数里面的this.name的this就是指向具体的实例,这里就是指向f1,虽然结果一样,但是两个的原理不一样


这是一个系列,不过放一片文章里面还是太长了,后续还是分出不同的标题吧

写篇文章真是不容易呀,那些大佬写的那么些高质量的文章 真不知道肝了多少精力和脑细胞。
原文地址:https://www.cnblogs.com/ysla/p/14130903.html