前言:这是笔者学习之后自己的理解与整理。如果有错误或者疑问的地方,请大家指正,我会持续更新!

声明、定义、初始化

  声明的意思是宣称一个变量名的存在,定义则为这个变量分配存储空间,初始化则是给该变量名的存储空间赋予初始值;

  javascript 中,变量没有固定类型,其存储空间会随着初始化(并赋值)而变化;

        <script type="text/javascript">
var a;//声明a
console.log(a);//undefined; 只声明,没有赋值,返回undefined a = 'hello world!';//(定义)初始化变量a并且赋值'hello world!'
console.log(a);//hello world! var a;//再次声明a,但没有赋值,a的值不会被清空
console.log(a);//hello world!
</script>

hoisting 机制

  javascript 代码在执行时,一般是一行一行往下执行的,但是这里面又有一个变量声明提升的概念;

  javascript 引擎在执行时,会把所有变量声明和函数声明都提升到当前作用域的最前面(hoisting 机制);

变量声明提升

        <script type="text/javascript">
// console.log(a);//a is not defined a没有声明
console.log(b);//undefined 没找到b(没有初始化赋值),但已经声明了
var b = 'hello world!'; //声明并初始化b赋值'hello world!'
console.log(b);//hello world!
</script>

  上面代码中 a 和 b 的区别就是b声明提前了,a 没有声明;所以上面代码相当于:

        <script type="text/javascript">
var b;//声明b
// console.log(a);//a is not defined a没有声明
console.log(b);//undefined
b = 'hello world!'; //初始化并赋值'hello world!'
console.log(b);//hello world!
</script>

函数声明提升

  一直对一些基本的概念的理解有些模糊,先梳理以下:

  1. 函数声明(function statement),使用function关键字声明一个函数,再指定一个函数名,叫函数声明。如:function fnName(){};
  2. 匿名函数(anonymous functions),使用function关键字声明一个函数,但是没有命名,这个函数就叫匿名函数,写法就是:function(){};
  3. 函数表达式(function expression),把一个匿名函数当做值传给一个变量,叫函数表达式,这是最常见的函数表达式语法形式。如:var fnName = function(){};

函数声明

  函数声明(function statement),使用function关键字声明一个函数,再指定一个函数名,叫函数声明。如:function fnName(){};

  但需要注意的是:

  1. 函数的声明可以是有条件的,比如嵌套在 if 语句中,有的浏览器会将这种有条件的声明看成无条件的,不论条件是true还是false,我们最好不要这样写;
  2. 在严格模式下,只允许在全局作用域或函数作用域的顶层声明函数。也就是说,不允许在非函数的代码块内声明函数。

  非严格模式下:

        <script type="text/javascript">
//非严格模式
if(true){
function find(){
console.log(456);
}
}
find();//456 if(false){
function cantFind(){
console.log(123);
}
}
cantFind();//TypeError: cantFind is not a function
</script>

  严格模式下:

        <script type="text/javascript">
'use strict' //严格模式下
if(true){
function find(){
console.log(456);
}
}
find();//ReferenceError: cantFind is not defined
</script>

函数表达式

  函数表达式(function expression),把一个匿名函数当做值传给一个变量,叫函数表达式,这是最常见的函数表达式语法形式。如:var fnName = function(){};

  1. 在 function 前面加!、+、 -、=甚至是逗号等或者把函数用()包起来都可以将函数声明转换成函数表达式;
  2. 但是!、+、-等运算符还会和函数的返回值进行运算,有时造成不必要的麻烦,所以我们一般用()把函数声明包起来或者用 = ,达到转换函数表达式的目的;
        <script type="text/javascript">
//在function前面加!、+、 -、=甚至是逗号等到都可以将函数声明转换成函数表达式,我们一般用()或者 =
var a = function b(){
return b;
}
console.log(a());//function b(){console.log(b);}
console.log(b());//ReferenceError: b is not defined
//函数表达式的标识符在外部作用域是看不到的,只能在内部作用域看到
</script>

  函数声明提升有两种情况:1.函数声明;2.把函数作为一个值传给一个变量(函数表达式);

  和变量声明提升一样,函数声明也会提升,并且定义也会提升(这个说法也不太准确,看下面的例子);

        <script type="text/javascript">
play();//函数声明提升了,之所以可以正常运行,是因为定义也被提前了
function play(){
console.log('hello world!');//hello world!
}
</script>

  以上代码中函数play()声明提升了,之所以可以正常运行,是因为函数声明提升了,定义也被提升了(这个说法也不太准确,看下面的例子),以上代码相当于:

        <script type="text/javascript">
function play(){
console.log('hello world!');//hello world!
}
play();
</script>

  我们有时候会把一个函数作为值传给一个变量,这时变量会被声明提升,但函数不会,它只是一个函数表达式,我们只需要它的返回值给变量;

  如果它是一个具名函数表达式,那么函数表达式的标识符(函数名)在外部作用域是找不到的,只在内部作用于能找到;

        <script type="text/javascript">
//console.log(play);//ReferenceError: play is not defined 声明错误
//play();//ReferenceError: play is not defined 声明错误 console.log(games);//undefined 变量声明了,但没赋值,所以没找到
//games();//TypeError: games is not a function 类型错误 var games = function play(){ //函数表达式
console.log(typeof play);
}
//play();//ReferenceError: play is not defined 声明错误
games();//function 函数表达式的标识符(函数名)在外部作用域是找不到的,只在内部作用于能找到;
</script>

  上面写的函数声明的定义也被提升了,这个说法并不太准确,

<script type="text/javascript">
if (!("a" in window)) {
function a() {
return '为什么下面弹出的a是undefined';
}
}
console.log(a); //undefined
//如果定义也被提前,这里应该是function a(){},所以这里定义并没有被提前,只有函数名被提前了,然后if语句进不去了,
//因为函数声明可以和函数表达式相互转换,只是写法不同而已,
//所以上面的代码有个说法,这里的函数a可以理解成var a = function(){},函数声明的方式提前的是函数名,然而这又不能解释为什么函数能在函数声明之前能被调用; b();
function b(){
console.log('函数声明的疑问,为什么b能执行');
}
</script>

  因为函数声明可以和函数表达式相互转换,只是写法不同而已,所以上面的代码有个说法,函数a可以理解成 var a = function(){},函数声明的方式提前的是函数名,然而这又不能解释为什么函数能在函数声明之前能被调用;

变量名解析顺序

  同一作用域下,相同变量名,后面的赋值会覆盖前面的;

  同一作用域下,如果变量名和函数名相同,那么函数名会覆盖变量名,不论它们在代码的顺序如何;但是它们的初始化赋值是按顺序执行的;

  所以,同一作用域下应避免使用相同变量名;

        <script type="text/javascript">
console.log(a);//function a(){console.log('我是函数');} 函数名和变量名相同,函数名会覆盖变量名 var a = 'hello world!';
function a(){
console.log('我是函数');
}; console.log(a);//hello world!
a();//TypeError: a is not a function 类型错误
</script>

  上面代码中,a的值最后是字符串,原因就在于:

  1. 变量的赋值是按顺序执行的;
  2. 函数声明提升会把表达式也提前;
  3. 相同变量名,后面的赋值会覆盖前面的;

  上面的代码相当于:

        <script type="text/javascript">
console.log(a);//function a(){console.log('我是函数');} 函数名和变量名相同,函数名会覆盖变量名 function a(){
console.log('我是函数');
};
var a = 'hello world!'; console.log(a);//hello world!
a();//TypeError: a is not a function 类型错误
</script>

有一道经典面试题:

        <script type="text/javascript">
b = c;
console.log(b);
console.log(c);
b();
console.log(a);
function c() {
a = 1, b = 2, c = 3;
};
</script>

  函数c还没运行,所以里面的变量是不知道的,但是函数c已经声明提前了,又因为第一行b=c,所以b和c都是函数c ;

  函数c运行之后,里面的变量a,b,c被发现是全局变量,并且给它们赋值,所以外部能找到a=1,并且你还会发现b=2; c=3;

  如果函数c不曾运行过,那么是找不到它们的 ;

这道题换一下:

        <script type="text/javascript">
b = function c() {
a = 1, b = 2, c = 3;
}; b();
console.log(a);
console.log(b);
console.log(c);
</script>

  函数 b 运行之后,发现了里面的全局变量,并且给它们赋值 a=1; b=2;

  但是有个特殊的变量 c,c 是函数表达式的名字,函数的名字,规范说明函数名不能被改变,所以这里设置 c=3 其实是对函数名赋值,是无效的,也不会被当做全局变量;而且函数表达式的标识符只有内部作用域可以找到,所以外部是找不到的,报错 ReferenceError: c is not defined 引用错误;

jacascript 函数声明、函数表达式与声明提升(hoisting机制)的更多相关文章

  1. JS 函数提升&变量提升以及函数声明&函数表达式的区别

    感谢原文作者:迟早会有猫 原文链接:https://www.cnblogs.com/SidselLoong/p/10515809.html 今天看js的变量提升问题,里面提到了函数提升.然后发现自己之 ...

  2. JS执行顺序-函数声明提升、匿名函数、函数表达式

    大方向上: JS 是按照 代码块 进行 编译.执行 的. 学习至: 1.变量声明提升 2.新唐的博客 3.js中匿名函数的创建与调用方法分析 4.前端圣经 - <高程三> 5.深入理解变量 ...

  3. JavaScript系列:函数 自执行 表达式 声明 定义

    可用方式 (function($) {})(jQuery); !function( $ ){}(jQuery); +function( $ ){}(jQuery); -function( $ ){}( ...

  4. JS函数声明与定义,作用域,函数声明与表达式的区别

    Scoping & Hoisting 例: var a = 1; function foo() { if (!a) { var a = 2; } alert(a); }; foo(); 上面这 ...

  5. Javascript 函数声明、函数表达式与匿名函数自执行表达式

    函数表达式(Function Expression)注:将函数定义为表达式语句(通常是变量赋值)的一部分 //func() 错误 var func = function () { } //func() ...

  6. js中 函数声明/函数表达式/匿名函数/箭头函数/立即执行函数

    函数声明: function add(a, b) { // ... } 1.顾名思义,声明一个函数, 用关键字 “function” 来告诉,这是一个函数. 2.任何地方,想用就可以拿过来使用 函数表 ...

  7. JavaScript学习总结(三、函数声明和表达式、this、闭包和引用、arguments对象、函数间传递参数)

    一.函数声明和表达式 函数声明: function test() {}; test();    //运行正常 function test() {}; 函数表达式: var test = functio ...

  8. JS高级 — 函数的声明和表达式

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  9. IIFE中的函数是函数表达式,而不是函数声明

    下面的代码打印什么内容,为什么? var b = 10; (function b(){ b = 20; console.log(b); })(); 针对这题,在知乎上看到别人的回答说: 函数表达式与函 ...

随机推荐

  1. 【基础】这15种CSS居中的方式,你都用过哪几种?

    简言 CSS居中是前端工程师经常要面对的问题,也是基本技能之一.今天有时间把CSS居中的方案汇编整理了一下,目前包括水平居中,垂直居中及水平垂直居中方案共15种.如有漏掉的,还会陆续的补充进来,算做是 ...

  2. 笔记:Hibernate 框架配置说明

    下载 Hibernate ,打开地址 www.hibernate.org ,点击 Hibernate ORM -> Downloads 下载 4.3.11 版本,要使用Hibernate 需要把 ...

  3. React 系列文章(1): npm 手动搭建React 运行实例 (新手必看)

    摘 要 刚接触React 开发, 在摸索中构建react 运行环境,总会遇到各种坑:本文,将用最短时间解决webpack+react 环境搭建问题. 1.如果你还没有React基础 看这里. 2.如果 ...

  4. zabbix监控redis性能

    创建采集脚本 mkdir -p /etc/zabbix/scripts chown -R zabbix.root /etc/zabbix/scripts vim redis_status.sh  #! ...

  5. HA集群heartbeat配置--Nginx

    HA即(high available)高可用,又被叫做双机热备,用于关键性业务.简单理解就是,两台机器A和B,正常是A提供服务,B待命限制,当A宕机或服务宕掉,会切换至B机器继续提供服务.常用实现高可 ...

  6. 涉及模式之 装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...

  7. Struts2学习笔记三 访问servlet

    结果跳转方式 转发 <!-- 转发 --> <action name="Demo1Action" class="cn.itheima.a_result. ...

  8. 20162311张之睿 Linux基础与Java开发环境实验报告

    实验一 Java开发环境的熟悉 实验内容 1.使用JDK编译.运行简单的Java程序: 2.使用Eclipse 编辑.编译.运行.调试Java程序. 实验要求 1.没有Linux基础的同学建议先学习& ...

  9. 高级软件工程2017第6次作业--团队项目:Alpha阶段综合报告

    高级软件工程2017第6次作业--团队项目:Alpha阶段综合报告 Deadline:2017-10-30(周一)21:00pm (注:以下内容参考集大作业4,集大作业5,集大作业6,集大作业7 一. ...

  10. 冲刺NO.5

    Alpha冲刺第五天 站立式会议 项目进展 今日项目完成内容主要包括了JS的学习,事务管理员模块与学生模块的完善与补充,并且开始编写信用信息管理模块和奖惩事务管理模块. 问题困难 前端部分的技术掌握的 ...