Javascript中的预解释——变量提升

来源:互联网 发布:淘宝hd老版本 编辑:程序博客网 时间:2024/05/22 00:42

预解释——变量提升

Hoisting 是您在JavaScript文档中找不到的术语。Hoisting 被认为是思考执行上下文(特别是创建和执行阶段)在JavaScript中如何工作的一般方式。但是,hoisting 可能会导致误解。例如,提升教导变量和函数声明被物理移动到编码的顶部,但这根本不是什么。真正发生的什么是在编译阶段将变量和函数声明放入内存中,但仍然保留在编码中键入的位置。
引自MDN

一、变量和函数在内存中的位置

JavaScript中的变量类型和其他语言一样,有基本数据类型和引用数据类型。基本数据类型包括:undefined、null、boolean、String、Number;引用数据类型主要是对象(包括{}、[]、/^$/、Date、Function等)。

var num = 100;var obj = {    name: 'Niko',    age: 20}function fn () {    console.log('hello world');}
  • 当浏览器加载html文档时会创建一个window的全局作用域
  • 基本数据类型按赋值来操作,引用数据类型按地址操作
  • 基本类型存放在栈内存中,引用类型放在堆内存中

image

基本类型是直接存储在栈内存中,而对象是存储在堆内存中,变量只是持有该对象的地址。所以obj持有一个对象的地址oxff44,函数func持有一个地址oxff66。

所以在以上基础上执行代码

console.log(fn);console.log(fn());

第一行输出的是整个函数的定义部分(函数本身):

function fn () {    console.log('hello world');}

如此,我们可以知道,fn保存的是一个地址,该地址指向堆内存中的函数体,既函数的定义。
console.log(fn())则输出函数的执行结果’hello world’,由于fn函数没有返回值,所以显示undefiend,

'hello world'undefined

函数的返回,return后面跟什么就返回什么,若不写return,则默认返回值undefiend

二、预解析

在理解了基本类型和引用类型还有两个内存地址之间的区别后,就能更好的理解当前作用域下的预解析机制了。

所谓预解析就是:在当前作用域中,把所有用var和function声明或定义的变量和函数提前到作用域的顶部

注意:在ES6中,使用let或const声明变量不会进行预解析,使用函数表达式var fn = function(){……}声明函数,也不会进行预解析。

2.1 声明和定义

  • 声明var box,在当前作用域中声明一个变量名为box的变量,此时box还未被赋值。如果一个变量只是声明了,但是没有赋值,默认值是undefined。用白话解释就是:在三年二班(作用域)里有个叫box(变量名)的老师要上课,至于上课内容,未知。
  • 定义box = 10,定义就是给变量赋值,完整的书写就是var box = 10

2.2 var声明的变量和function声明的函数在预解释中的区别

var声明变量和function声明函数在预解释时是有区别的,var声明变量在预解析时只是提前声明并提前到作用域顶部,而function声明函数则会同时声明和定义到作用域的顶部

2.3 预解析只发生在当前作用域下

console.log(num);var num = 100;console.log(num);fn(10,20)function fn (num1,num2) {    console.log(total)    var total = num1 + num2;    onsole.log(total)}

输出结果为:

undefiend100undefiend20

第一次输出num的时候,num已声明并预解析到作用域顶部,但此时num还未定义,所以输出undefiend;第二次输出时num已被赋值为100,变量已定义,所以正常显示100

由于函数的声明和定义是同时进行的,所以调用fn()时可以正常执行函数中的代码块;因为声明函数fn()的同时也创建了一个局部作用域,同样在局部作用域时也有同样的预解析机制,所以第一次输出total时同样也只是声明了变量而未定义->输出undefiend。

参考地址

www.jb51.net/article/87477.htm

原创粉丝点击