基本认识

数据类型

基本数据类型

string, number, null, boolean, undefined

引用数据类型

object: [],{},/\d/,Date
function

函数类型

  1. 开辟内存空间

  2. 把函数中的代码当作字符串先存储

  3. 把内存地址复制给当前函数名

JS引擎

当浏览器加载HTML页面时候,首先会先提供一个供全局JS代码执行的环境 --> 全局作用域 (globalwindow

函数先把代码体当作字符串,存储到堆内存,引用赋值给当前函数名。
执行会开辟栈,来执行当前代码。

预解析

声明declare:告知浏览器在全局作用域中有一个 变量名 为 xxx 的变量。(如果一个变量只是声明了但是没有赋值,默认值:undefind)
定义defined:对变量进行赋值

预解析

在当前的作用域中,JS代码执行之前,浏览器首先会默认的把所有的带var,和function的进行提前的声明或定义

var 和 function 关键字

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

预解析只发生在当前的作用域下进行解析。
一开始只会对widnow环境下的进行预解析,只有函数执行的时候才会对函数中的进行解析

JS内存的分类

根据作用分类

栈内存: 用来提供一个供JS代码执行的环境 --> 作用域 (全局作用域/私有的作用域,和函数)
堆内存: 用来存储引用数据类型的值 --> 对象存储的是属性名和属性值,函数存储的是代码字符串

作用域链

区分私有变量和全局变量

  1. 在全局作用域下声明(预解析的时候)的变量是全局变量

  2. 在私有作用域中声明的变量和函数形参都是私有变量.

  3. 在私有作用域中,代码执行的时候遇到了一个变量,首先需要确定是否为私有变量,如果是私有变量,那么和外面的作用域没有任何关系;

函数执行

当函数执行的时候(直接目的:让函数体中的代码执行),首先会形成一个新的私有作用域。
执行代码的就是栈内存,作用域也是栈内存。

  1. 如果有形参,先给形成赋值

  2. 进行私有作用域预解析

  3. 私有作用域的代码从上至下执行

函数形成一个新的私有作用域保护了里面的私有变量不受外界的干扰。(外边变量修改不了私有变量的,私有变量的也修改不了外边变量)

作用域链

如果不是私有变量,则往当前的上级作用域进行查找,如果上级没有则继续查找,则一直找到顶级作用域(window)。

全局变量的细节

在全局作用域中,带var和不带var的关系

区别:带var的可以进行预解析,所以在赋值的前面执行不会报错;
不带var的是不能进行预解析的,在前面使用该变量名会报错。

场景在全局作用域下,带var和不带var的关系:

console.log(num); // undefiend
var num = 10;    

console.log(num2); // 报错
num2 = 10;

关系:先判断是否是全局变量,如果是就输出,如果不是会再去判断是否是window底下的属性。
num2=10; --> 相当于给window增加了一个叫做num2的属性名,属性值是10
var num=10; --> 首先它相当于给全局作用域增加了一个全局变量num,但是不仅如此,也相当于给window增加了一个属性num,属性值10

var num = 10;
console.log(num); // 10
console.log(window.num); // 10num2 = 10;
console.log(num2); // 10 // window.num2
console.log(window.num2); // 10

第一种:

function fn() {console.log(total); // 报错total = 100;
}
fn();
console.log(total); // 100

第二种:

function fn() {total = 100;
}
fn();
console.log(total); // 100

私有作用域中出现的一个变量不是私有的,则往上级作用域进行查找,上级没有则继续向上寻找,一直找到window为止,如果window下也没有,分为两种情况:

  1. 获取值:console.log(total); --> 报错(JS中,如果在不进行任何特殊处理的情况下,报错之后,代码退出执行)

  2. 设置值: total = 100; --> 相当于给window增加了一个属性名total,属性值为100

预解析机制

in操作符:"num" in window 判断num是否为window这个对象的一个属性,是的话返回true,不是返回false

预解析的时候不管你的条件是否成立,都要把带var的进行提前声明

if (!('num' in window)) { // 预解析,var num --> window.num  // 'num' in window 为truevar num = 12;
}
console.log(num);  // undefined

函数表达式

匿名函数表达式:把函数定义的部分当作一个值赋值给变量/元素.

fn(); // 报错
var fn = function() { // 匿名函数之函数表达式 // 把函数定义的部分当作一个值赋给变量/元素的某一个事件console.log('ok');
}
fn(); // okfn(); // ok
function fn() {console.log('ok');
}
fn(); // ok

自执行函数

自执行函数:定义和执行一起完成

自执行函数在全局作用域下不进行预解析,当代码执行到当前位置的时候定义和执行一起完成了。

(function(num) {})(100);
~function(num) {}(100);
!function(num) {}(100);
+function(num) {}(100);
!function(num) {}(100);

return 后续的语句

函数体中reutrn后续的代码虽然不在执行了,但是需要进行预解析。
return 的函数是返回值,并不需要预解析。

function fn() {console.log(num); // undefinedreturn function () { console.log(this); } // return 跟着的语句不会预解析var num = 100; // var 进行预解析
}var t = fn();
console.log(t());

函数权重高

在JS中如果变量名和函数名重复,是冲突。函数级别高,使用的是函数。

console.log(fn);
function fn() {
}
var fn = 10;

在预解析的时候,如果名字已经声明过了,不需要重新声明,但是需要重新赋值.

// 声明 + 定义: fn: oxfff11
// 声明:var fn;(不需要重新声明)
// 声明 + 定义: fn: oxfff222
// ---> fn: oxfff222
fn(); // 2
function fn() {console.log(1);}
fn(); // 2
var fn = 10; // 修改作用域值
fn(); // 报错
function fn() {console.log(2);}
fn(); // 停止执行

查找作用域

如何查找当前作用域的上级作用域

看当前函数是在哪个作用域下定义的,那么它的上级作用域就是谁。(和函数在哪里执行的没有任何的关系)
函数作用域,查询变量,定义的位置有关.

var num = 12;
function fn() {var num = 120;return function() {console.log(num);}
}var f = fn();
f(); // 120  // window环境下执行,先找父级,后找window
// 匿名函数也是堆内存。~function() {var num = 111;f();
}();

内存释放&作用域销毁

堆内存释放

堆内存作用:存放引用内存的属性值
释放方法:null空对象指针

对象数据类型或者函数数据类型在定义的时候首先都会开辟一个堆内存,
堆内存有一个引用的地址,如果外边有变量知道了这个地址,这个内存就被占用,不能销毁。

var obj1 = {name: 1};
var obj2 = obj1;
// 想让堆内存释放/销毁,只需要把所有的引用它的变量赋值为null即可。如果堆内存没有任何东西被占用了,那么浏览器会在空闲的时候,会把它销毁。
// 垃圾回收
obj1 = null;
obj2 = null;

栈内存释放或作用域销毁

栈内存作用:存放作用域

作用域:
全局作用域(浏览器天然开辟,浏览器关闭的时候才释放)
私有作用域(只有函数执行,才会产生私有做作用域)

销毁情况

一般情况下,函数执行会形成一个新的私有的作用域,当私有作用域中的代码执行完成后,当前作用域都会主动进行释放和销毁。
作用域有被子级作用域引用,父级的私有变量不能销毁。

  1. 函数执行返回了一个引用数据类型值,并且在函数外边一个变量接收,这种情况下一般形成的私有作用域都不能被销毁。(闭包)

  2. 在一个私有的作用域中,给DOM元素的事件绑定方法,一般情况下,私有作用域都不会销毁。( DOM对象,在执行性函数中被引用)

  3. 返回的回调函数再次被执行,不会被立即销毁内存 (不立即销毁)

// 1: 引用类型的返回值,被外界引用
function fn() {var num = 10;return function() {}
}
var f = fn();// 2:  DOM对象,在执行性函数中被引用
var oDiv = document.getElementById('div1');
~function() {oDiv.onclick = function() {}
}(); // 当自执行函数形成的这个私有作用域也不销毁// 3: 返回的回调函数再次被执行,不会被立即销毁内存  (不立即销毁)
function fn() {var num = 10;return function() {}
}
fn()(); // 首先fn执行,返回一个回调函数对应的内存地址,然后紧接着让返回的小函数再执行。
// 返回的回调函数再次被执行,不会被立即销毁内存,当返回的回调函数执行完成后,浏览器会在空闲的时候销毁。

function fn() {var i = 10;return function(n) {console.log(n + (++i));    }
}var f = fn();
f(10); // 21
f(20); // 32
fn()(10); // 21
fn()(20);  // 31

This关键字

在JS中主要研究都是函数中的this

JS中的this代表的是当前行为执行的主体(方法,函数,事件...)
JS中的上下文(context)代表的是当前行为执行的环境(区域)
例如: 小明在沙县小吃吃蛋炒饭。 this->小明context->沙县小吃
小明可以在沙县小吃吃,也可以在其他地方吃。上下文环境可以变化。而吃的主体小明是不变的。
thiscontext是没有必然联系。

this是谁,和函数在哪里定义,在哪里执行都没有任何的关系。和执行主体有关系

如何判断执行主体?

函数执行,首先看函数名前面是否有.,有的话,.前面是谁,this就是谁;没有的话this就是window

function fn() {console.log(this);
}
var obj = {fn: fn
}
fn(); // fn中的this, window
obj.fn(); // fn中的this, objfunction sum() {fn(); // fn中的this,window
};
sum();var o = {sum: function() {fn(); // fn中的this,window}
}
o.sum();

自执行函数中的this,指代window

给元素的某一事件绑定方法,当事件触发的时候,执行对应的方法,方法中的this是当前的元素.

document.getElementById('div1').onclick = function() {console.log(this); // 当前DOM对象
}

var num = 20;
var obj = {num: 30,fn: (function(num) {this.num *= 3;num += 15;return function() {this.num *= 4; num += 20;console.log(num);}   })(num)
};var fn = obj.fn;
fn(); // window,// 60 * 4 // 35 += 20 // 55
obj.fn(); // 75
console.log(window.num, obj.num); // 240, 120

ECMA_作用域深入This关键字相关推荐

  1. Linux----函数中变量的作用域、local关键字。

    问题引出: 问题说明: shell的函数中如果变量的前面没有加local关键字.在全局作用域内存在这个变量名的情况下.函数中会直接使用这个变量 而不是自己创建一个.要想做到在函数创建一个变量也是可以的 ...

  2. java 静态代码块 作用域_java static关键字和代码块

    static关键字 为什么需要学习static关键字? 针对某一个变量属于类而不属于某一个具体的对象的时候,我们可以考虑使用static关键字 static概述: 多个对象共享同一份数据 static ...

  3. scope在c语言中什么意思,JavaScript scope作用域与this关键字

    作为一个程序员, 你可能早已经习惯于面向对象语言中指代当前对象的引用(或者指针), 如的c++中的this或者 python 中的self,当然具有OO属性( javascript 其实更多的是一种所 ...

  4. 【JavaScript】比较 var 和 let 关键字的作用域

    比较 var 和 let 关键字的作用域 使用 var 关键字声明变量时,它是全局声明的,如果在函数内部声明则是局部声明的. let 关键字的行为类似,但有一些额外的功能. 在代码块.语句或表达式中使 ...

  5. 尚学堂requireJs课程---1、作用域回顾

    尚学堂requireJs课程---1.作用域回顾 一.总结 一句话总结: 尚学堂的课程的资料他的官网上面是有的 1.js作用域? ~ js中是函数作用域:局部变量的话要写var关键词 ~ 闭包可以解决 ...

  6. c语言的变量,常量及作用域等

    1.const定义常量 在C语言中,const可以用来定义的一个常量,在变量名前加上const即可. int const a: 定义了一个a的整数常量,且a的值不能被修改.如果要修改a的值,有以下两种 ...

  7. nonlocal和global关键字

    回顾: 1. Python的函数的概述函数定义函数调用2. Python函数中参数的类型和返回值形参和实参形参类型:普通参数: 实参的传递的顺序和个数和形参一直关键字参数: 指定传递的实参被特定形参接 ...

  8. python local global_Python 关键字global全局变量详解

    变量作用域 一般在函数体外定义的变量成为全局变量,在函数内部定义的变量称为局部变量. 全局变量所有作用域都可用,局部变量只能在本函数可用,变量的使用顺序是,局部变量 > 全局变量, 也就是说:优 ...

  9. C语言——变量篇(一)变量关键字static、auto、extern、register

    前言:笔者最近在看C语言时候遇到了一堆关键字,auto,static,extern,register等等.看上去头皮发麻,在这里整理一下,便于自己理解. 全局变量和局部变量 关于全局变量和局部变量,笔 ...

最新文章

  1. jQuery图片翻转弹出动画特效
  2. 编写 Servlet 2.3 Filter
  3. NPOI读取Excel生成DataTable转为Json后利用LitJons读取
  4. 一道Python面试题,设置一个动态变量名
  5. easyui 扩展tree 获取选中节点的级数
  6. java连接oracle数据库jdbc
  7. kvm初体验之八:调整vm的vcpu, memory, disk大小
  8. JAVA集合4(Map接口)
  9. python 等值面 插值_对离散点进行克里金插值并输出矢量等值面
  10. rn在java中什么意思,RN150中RN是什么意思
  11. 微信小程序自定义顶部导航栏
  12. Introduction to Reinforcement Learning notes
  13. 互联网春节红包的寓言:奇迹如斯,赢家寥寥
  14. Opengl ES系列学习--莫比乌斯带
  15. 混合波束成形| 宽带系统基于码本的信道估计 《Channel Estimation for Hybrid Architecture-Based Wideband Millimete
  16. 滚石导航网站源码v3.0 织梦模板+测试版+非常适合网址导航网站使用
  17. 【物联网】物联网安全---编辑中
  18. kubernetes flannel 网络
  19. 理想中的接口自动化项目
  20. OpenGL坐标系转换

热门文章

  1. 【机器学习】【发展史】概览
  2. 对抗神经网络GAN到底学到了什么
  3. SAP MM ME81N PO Value Analysis报表中Net Value 为负数是怎么回事?
  4. Python 之 Pandas (二)选择数据
  5. DFA确定性有穷自动机及其化简
  6. 多细胞生命进击之路:单细胞为何放弃自由,长成复杂的多细胞?
  7. 复杂科学2021年度精选:从诺贝尔奖到未来科学
  8. 综述 | 北斗系统应用趋势分析
  9. 英特尔大地震!解雇首席工程官,7纳米延期,或面临集体诉讼……
  10. 学界 | UC伯克利发布一个低成本家居机器人,会叠衣服、会泡咖啡