JS之预解释原理
预解释的原理
- 预解释的不同机制
var的预解释机制function的预解释机制- 预解释机制
- 面试题练习
预解释的的不同机制
预解释也叫预声明,是提前解释声明的意思;预解释是针对变量和函数来说的;但是变量和function的的预解释是两套不同的机制;
- 当浏览器加载我们的HTML页面的时候,首先会提供一个供JS代码执行的环境->全局作用域global(浏览器中的全局作用域,也叫顶级作用域是window)
- JS中的内存空间分为两种:栈内存、堆内存
- 栈内存;提供JS代码执行的环境,存储基本数据类型的值;->全局作用域或者私有的作用域其实都是栈内存;
- 堆内存;存储引用数据类型的值(对象是把属性名和属性值储存进去,函数是把函数体内的代码当做字符串储存进去)
- 在当前的作用域中,JS代码执行之前,浏览器首先会默认的把所有代var和function的进行提前的声明或者定义,->“预解释”(也叫变量提升)
var的预解释机制
var a=1
1、代码运行之前,先扫描有没有带
var关键字的变量名,有的话,为这个变量名在内存里开一个空间;这时候变量名a是不代表任何值的;用undefined来表示;undefined是一个标识符/记号,表示找不到这个变量名所代表的数据;不存在的意思;这个阶段叫变量的声明;2、当代码运行的时候,则给数据1开辟一个内存空间;
3、让数据1和变量名a绑定在一起;变量类型指的就是数据类型;按照js语言的原理来说变量类型有undefined类型;但是数据类型是没有undefined这种数据类型的;只有”undecided”这种字符串类型(字符串类型是数据类型的一种);同理也没有unll这个数据类型,但是有”null”这种字符串类型;
var num;
//1、声明(declare):var num; ->告诉浏览器在当前作用域中有一个num的变量了,如果一个变量只是声明了但是没有赋值,默认的值是undefined
console.log(num);//->undefined
num = 12;
//2、定义(defined):num=12; ->给我们的变量进行赋值
console.log(num);//->12 //变量提前使用的话,就是undefined
console.log(testStr);//undefined
var testStr="22222222"
function 关键字的预解释步骤
function fn(){……}
在代码执行之前,把所有的带function关键字的脚本都扫描一遍,然后定义变量;并且同时给变量赋值;
1、函数的定义只是保存一些字符串;预解释的时候在内存里保存
fn大括号里面的字符串;2、代码运行时候,读到
fn()时候,这个时候就是函数的运行;函数的运行,会先开辟一个堆内存把字符串当做代码在堆内存中再次运行,函数产生的作用域内还会再进行预解释和代码运行;函数如果多次执行;会产生多个作用域;但是产生的多个作用域里面的内容都是相互独立的;互相没有关系;(在原型和原型链时候再仔细研究原理;)
fn(100,200);//->可以在上面执行,因为预解释的时候声明+定义就已经完成了
function fn(num1, num2) {
var total = num1 + num2;
console.log(total);
}
总结
- 1、
var和function关键字的在预解释的时候操作还是不一样的var-> 在预解释的时候只是提前的声明了这个变量,只有当代码执行的时候才会完成赋值操作function-> 在预解释的时候会提前的把声明加定义都完成了(在代码执行的时候遇到定义的代码直接的跳过)
- 2、预解释只发生在当前的作用域下,例如:开始只对window下的进行预解释,只有函数执行的时候才会对函数中的进行预解释;
[重要]刚开始只对window下的进行预解释,fn函数中目前存储的都是字符串,所以var total没啥实际的意义,所以不进行预解释 -> “预解释是发生在当前作用域下的”
综合题;
console.log(obj);//->undefined
var obj = {name: "xie", age: 25};
function fn(num1, num2) {//代码执行到这一行的时候直接的跳过这一块的代码,因为在预解释的时候我们已经完成了声明加定义
var total = num1 + num2;
console.log(total);
}
var num1 = 12;
fn(num1, 100);//执行fn,把全局变量num1的值赋值给形参num1,把100赋值给形参num2
下面是一个预解释思路
var a,
b = 0,
fn = function () {
var a = b = 2;
};
fn();
console.log(a, b);
把上面解析成下面就好理解了
var a;
window.b = 0;
window.fn = function () {
//var a = b = 2;
var a = 2;//a是私有的和全局没关系
b = 2;//b是全局的
};
fn();//window.fn()
console.log(a, b);//undefined 2
预解释机制
1、不管条件是否成立都要进行预解释
console.log(a);//->undefined
if (!!("a" in window)) {//"a" in window -> true
var a = "xie";
}
console.log(a);//->xie
例子中的if是不成立的,预解释的时候,碰到非
functon内的var,都会声明,无论你写在if else 还是别的判断里; 假设if语句起作用的话,那么第一次log(a)的时候,就会报错了(没有声明的变量,是不能直接用的,除非typeof),而声明并且没有赋值的表现才是undefined;假设不成立; 最开始总结的预解释步骤:代码运行之前,先扫描有没有带var关键字的变量名,有的话,为这个变量名,在内存里开一个空间;预解释是发生在代码执行前的,所以if根本阻挡不了预解释;2、预解释只发生在”=“的左边,只把左边的进行预解释,右边的是值是不进行预解释的
匿名函数之函数表达式:把函数定义的部分当做值赋值给一个变量或者元素的事件
fn1();//->undefined() Uncaught TypeError: fn is not a function JS中只有函数可以执行 && JS上面的代码如果报错了,在不进行任何的特殊处理情况下我们下面的代码都不在执行了
var fn1 = function () {
console.log("ok");
};
fn1();
//预解释的时候:fn=xxxfff000
fn2();//->"ok"
function fn2() {
console.log("ok");
}
fn2();//->"ok"
预解释的时候:var fn1 = function()... ->fn的默认值是undefined;这里即使有function,也是不能进行预解释的
3、函数体中return下面的代码都不在执行了,但是下面的代码需要参加预解释;而return后面的东西是需要处理的,但是由于它是当做一个值返回的,所以不进行预解释;
function fn() {
console.log(total);
return function sum() {};//return是把函数中的值返回到函数的外面,这里是把function对应的内存地址返回的到函数的外面,例如:return xxxfff111;函数体中return下面的代码都不在执行了
var total = 10;
console.log(total);
}
4、匿名函数的function在全局作用域下是不进行预解释的;
匿名函数之自执行函数:定义和执行一起完成了;函数内的声明,只是在函数内使用;
(function(num){
var testStr="test"+num;
console.log(num);
})(100);
console.log(testStr);// testStr is not defined
- 5、在预解释的时候,如果遇到名字重复了,只声明一次。 不重复的声明,但是赋值还是要重复的进行的
预解释:
var fn; 声明
fn = xxxfff000; [声明]不用了+定义
fn = xxxfff111; [声明]不用了+定义
// ->fn=xxxfff111
var fn = 12;//window.fn=12
function fn() {//window.fn=function(){}
}
JS中作用域只有两种:
- window全局作用域;
- 函数执行形成的私有作用域;
{name:“”}if(){}for(){}while(){}switch(){}这些都不会产生作用域;
ES6可以用let形成块级作用域;http://www.cnblogs.com/snandy/archive/2015/05/10/4485832.html
面试题
// 涉及this的指向和闭包
var num = 20;
var obj = {
num: 37,
fn: (function (num) {
this.num *= 3; // global num * 3
num += 15; // global num + 15
var num = 45;
return function () {
this.num *= 4; // 37*4
num += 20; // 调用外部函数的num (45+20)
console.log(num);
};
})(num), //->把全局变量num的值20赋值给了自执行函数的形参,而不是obj下的30,如果想是obj下的30,我们需要写obj.num
};
var fn = obj.fn; // 执行了第1次
fn(); //->65 , 执行了第2次=> window.num = 240
obj.fn(); //->85 闭包, obj.num = 37*4 = 148
console.log(window.num, obj.num); // 240,148
JS之预解释原理的更多相关文章
- 我理解的js中预解释
浏览器在执行代码前,先找带var和带function的地方,把带var的声明且赋予初始值undefined,把带function的声明且定义. 带var关键字预解释 让我们先看下这段代码执行的结果: ...
- JavaScript提高篇之预解释作用域以及this原理及其应用
1.预解释 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- [js]js栈内存的全局/私有作用域,代码预解释
js代码如何执行的 浏览器提供执行环境: 全局作用域(提供js执行环境, 栈内存) --> 执行js需要预解释 - 带var : 提前声明 - 带function关键字的: 提前声明+定义 js ...
- JS 预解释相关理解
1.JS中的内存空间分为两种:栈内存.堆内存 栈内存:提供JS代码执行的环境;存储基本数据类型的值; ->全局作用域或者私有的作用域其实都是栈内存 堆内存:存储引用数据类型的值(对象是把属性名和 ...
- JS学习:第一周——NO.1预解释
1.何为预解释? 在当前作用域下,在JS代码执行之前,浏览器会对带var和带function的进行提前声明或定义: ①带var的:只声明不定义:告诉浏览器,有这么一个变量,但是并没有赋值 ②带func ...
- [js]js中4种无节操的预解释情况
js中4种无节操的预解释情况 - 1. if语句即使条件不成立,条件里的表达式也会进行预解释. - 2. 匿名函数的预解释: 只对等号左边与解释 - 3. 自执行函数的预解释: 不进行预就解释, 执行 ...
- [js]js的惰性声明, js中声明过的变量(预解释),后在不会重新声明了
js的惰性声明, js中声明过的变量(预解释),后在不会重新声明了 fn(); // 声明+定义 js中声明过一次的变量,之后在不会重新声明了 function fn() { console.log( ...
- js中的预解释
在js中,带var 和function关键字的需要预解释: 那什么是预解释?就是在js代码执行之前,先申明好带有var 关键字和带有function关键字的变量,在内存里先安排好.但是带有var关键字 ...
- JS预解释
1.声明(declare) var num // 告诉浏览器在全局作用域中有一个num变量 定义(defined) num = 12 // 给我们的比变量进行赋值 2.var:在预解释时只是提前 ...
随机推荐
- python常见面试题讲解(二)计算字符个数
题目描述 写出一个程序,接受一个由字母和数字组成的字符串,和一个字符,然后输出输入字符串中含有该字符的个数.不区分大小写. 输入描述: 第一行输入一个有字母和数字以及空格组成的字符串,第二行输入一个字 ...
- Maven系列(一) -- maven仓库的搭建
从今天开始,我要写一个maven系列的文章,以帮助大家来更好的熟悉maven仓库,并且将自己优秀的的代码开源出去,一方面为开源做贡献,另一方面顺便提升自己的知名度,让我们把愉快的开始吧 为什么要搭建m ...
- Java四种访问修饰符
Java 四种访问权限 一.概述 访问等级比较:public > protected > default > private 无论是方法还是成员变量,这四种访问权限修饰符作用都一样 ...
- Redis详解(十)------ 从零开始搭建集群
在上一篇博客我们介绍了------Redis哨兵(Sentinel)模式,哨兵模式主要是解决高可用问题,在master节点宕机时,slave节点能够自动切换成为master节点 本篇博客我们来介绍Re ...
- 洛谷 P1352 没有上司的舞会 树形DP板子
luogu传送门 题目描述: 某大学有n个职员,编号为1~n. 他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司. 现在有个周年庆宴会,宴会每邀请来一个职员都会 ...
- 线程池 & 线程调度
线程池1. 第四种获取线程的方法:线程池,一个 ExecutorService,它使用可能的几个池线程之 一执行每个提交的任务, 通常使用 Executors 工厂方法配置. 2. 线程池可以解决两个 ...
- Vue 全选/取消全选,反选/取消反选
这是一个组件: <template> <div> <div> <input type="checkbox" v-model="i ...
- python字母串查找基本操作
字符串查找基本操作主要分为三个关键词:find().index().count(). 这三个用法相同,格式都是为:自定义字符串名.关键词(‘子串’,开始位置,结束位置),开始和结束范围可不写. 1.f ...
- 05 . Python入门值循环语句
一.Python循环语句 程序一般情况下是按照顺序执行的 编程语言提供了各种控制结构,允许更复杂的执行路径 Python中的循环语句有for和while但没有do while 循环语句允许我们执行一个 ...
- web-信息泄露基础知识总结(持续更新)
web-信息泄露 1.git泄露 Git是一个开源的分布式版本控制系统,在执行git init初始化目录的时候,会在当前目录下自动创建一个.git目录,用来记录代码的变更记录等.发布代码的时候,如果没 ...