摘要:预解析声明告知浏览器在全局作用域中有一个变量名为的变量。执行代码的就是栈内存,作用域也是栈内存。关键字在中主要研究都是函数中的中的代表的是当前行为执行的主体方法,函数,事件中的上下文代表的是当前行为执行的环境区域例如小明在沙县小吃吃蛋炒饭。
基本认识
数据类型
基本数据类型
string, number, null, boolean, undefined
引用数据类型
object: [],{},/d/,Date
function
函数类型
开辟内存空间
把函数中的代码当作字符串先存储
把内存地址复制给当前函数名
JS引擎
当浏览器加载HTML页面时候,首先会先提供一个供全局JS代码执行的环境 --> 全局作用域 (global、window)
函数先把代码体当作字符串,存储到堆内存,引用赋值给当前函数名。
执行会开辟栈,来执行当前代码。
声明declare:告知浏览器在全局作用域中有一个 变量名 为 xxx 的变量。(如果一个变量只是声明了但是没有赋值,默认值:undefind)
定义defined:对变量进行赋值
预解析
在当前的作用域中,JS代码执行之前,浏览器首先会默认的把所有的带var,和function的进行提前的声明或定义
var 和 function 关键字
对于带var 和 function 关键字的在预解析的时候操作
var -> 在预解析的时候只是提前声明了
function -> 在预解析的时候提前的声明了 + 定义 都完成了。
预解析只发生在当前的作用域下进行解析。
一开始只会对widnow环境下的进行预解析,只有函数执行的时候才会对函数中的进行解析
JS内存的分类
根据作用分类
栈内存: 用来提供一个供JS代码执行的环境 --> 作用域 (全局作用域/私有的作用域,和函数)
堆内存: 用来存储引用数据类型的值 --> 对象存储的是属性名和属性值,函数存储的是代码字符串
区分私有变量和全局变量
在全局作用域下声明(预解析的时候)的变量是全局变量
在私有作用域中声明的变量和函数形参都是私有变量.
在私有作用域中,代码执行的时候遇到了一个变量,首先需要确定是否为私有变量,如果是私有变量,那么和外面的作用域没有任何关系;
函数执行
当函数执行的时候(直接目的:让函数体中的代码执行),首先会形成一个新的私有作用域。
执行代码的就是栈内存,作用域也是栈内存。
如果有形参,先给形成赋值
进行私有作用域预解析
私有作用域的代码从上至下执行
函数形成一个新的私有作用域保护了里面的私有变量不受外界的干扰。(外边变量修改不了私有变量的,私有变量的也修改不了外边变量)
作用域链
如果不是私有变量,则往当前的上级作用域进行查找,如果上级没有则继续查找,则一直找到顶级作用域(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); // 10 num2 = 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下也没有,分为两种情况:
获取值:console.log(total); --> 报错(JS中,如果在不进行任何特殊处理的情况下,报错之后,代码退出执行)
设置值: 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 为true var num = 12; } console.log(num); // undefined
函数表达式
匿名函数表达式:把函数定义的部分当作一个值赋值给变量/元素.
fn(); // 报错 var fn = function() { // 匿名函数之函数表达式 // 把函数定义的部分当作一个值赋给变量/元素的某一个事件 console.log("ok"); } fn(); // ok fn(); // 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); // undefined return 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;
栈内存释放或作用域销毁
栈内存作用:存放作用域
作用域:
全局作用域(浏览器天然开辟,浏览器关闭的时候才释放)
私有作用域(只有函数执行,才会产生私有做作用域)
销毁情况
一般情况下,函数执行会形成一个新的私有的作用域,当私有作用域中的代码执行完成后,当前作用域都会主动进行释放和销毁。
作用域有被子级作用域引用,父级的私有变量不能销毁。
函数执行返回了一个引用数据类型值,并且在函数外边一个变量接收,这种情况下一般形成的私有作用域都不能被销毁。(闭包)
在一个私有的作用域中,给DOM元素的事件绑定方法,一般情况下,私有作用域都不会销毁。( DOM对象,在执行性函数中被引用)
返回的回调函数再次被执行,不会被立即销毁内存 (不立即销毁)
// 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); // 31This关键字
在JS中主要研究都是函数中的this
JS中的this代表的是当前行为执行的主体(方法,函数,事件...)
JS中的上下文(context)代表的是当前行为执行的环境(区域)
例如: 小明在沙县小吃吃蛋炒饭。 this->小明 ,context->沙县小吃
小明可以在沙县小吃吃,也可以在其他地方吃。上下文环境可以变化。而吃的主体小明是不变的。
this和context是没有必然联系。
this是谁,和函数在哪里定义,在哪里执行都没有任何的关系。和执行主体有关系。
如何判断执行主体?
函数执行,首先看函数名前面是否有.,有的话,.前面是谁,this就是谁;没有的话this就是window
function fn() { console.log(this); } var obj = { fn: fn } fn(); // fn中的this, window obj.fn(); // fn中的this, obj function 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
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/88261.html
摘要:不包括作为其嵌套函数的被解析的源代码。作用域链当代码在一个环境中执行时,会创建变量对象的一个作用域链。栈结构最顶层的执行环境称为当前运行的执行环境,最底层是全局执行环境。无限制函数上下文。或者抛出异常退出一个执行环境。 前言 其实规范这东西不是给人看的,它更多的是给语言实现者提供参考。但是当碰到问题找不到答案时,规范往往能提供想要的答案 。偶尔读一下能够带来很大的启发和思考,如果只读一...
摘要:然而事实上并不是。函数本身也是一个对象,但是给这个对象添加属性并不能影响。一图胜千言作者给出的解决方案,没有麻烦的,没有虚伪的,没有混淆视线的,原型链连接不再赤裸裸。所以是这样的一个函数以为构造函数,为原型。 注意:本文章是个人《You Don’t Know JS》的读书笔记。在看backbone源码的时候看到这么一小段,看上去很小,其实忽略了也没有太大理解的问题。但是不知道为什么,我...
摘要:理解的函数基础要搞好深入浅出原型使用原型模型,虽然这经常被当作缺点提及,但是只要善于运用,其实基于原型的继承模型比传统的类继承还要强大。中文指南基本操作指南二继续熟悉的几对方法,包括,,。商业转载请联系作者获得授权,非商业转载请注明出处。 怎样使用 this 因为本人属于伪前端,因此文中只看懂了 8 成左右,希望能够给大家带来帮助....(据说是阿里的前端妹子写的) this 的值到底...
在过往学习的JavaScript都是在基础,现在为大家介绍更为深入的JavaScript知识。 JavaScript函数 JavaScript函数和Java函数是有一部分相似的,所以学习起来也会相对简单 基本构造 1.直接构造 //function代表函数标志,name为函数名称,参数可有可无 functionname(参数){ //... return; } 2....
摘要:捕获所有参数绑定当一个函数用作构造函数时使用关键字,它的被绑定到正在构造的新对象。使用来调用函数,或者说发生构造函数调用时,会自动执行下面的操作你不知道的创建或者说构造一个全新的对象。在箭头函数中,与封闭词法上下文的保持一致。 this 实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数的调用位置(也就是函数的调用方法)。 四条规则:(你不知道的JS) 1. 默认绑定 func...
阅读 1745·2023-04-26 00:20
阅读 1762·2021-11-08 13:21
阅读 1906·2021-09-10 10:51
阅读 1523·2021-09-10 10:50
阅读 3226·2019-08-30 15:54
阅读 2114·2019-08-30 14:22
阅读 1408·2019-08-29 16:10
阅读 3070·2019-08-26 11:50