声明语句:声明语句是用来声明定义标识符(变量和函数名)并给其赋值。

1:var 变量声明(5.3.1节):

var语句用来声明一个或多个变量:var name_1 = [= value_1] [ ,..., name_n [= value_n]]

var i;
var j = 0;
var x=1, y=2;
var pi = 3.14,
f = function(x) {return x*x},
k = f(x);

2:遗漏声明(3.9节)

读取一个没有声明的变量的值:JavaScript会报错。

给一个未声明的变量赋值,(在非严格模式中)JavaScript实际上是给全局对象创建一个同名属性,这看起来像是JavaScript自动声明了一个全局变量。

x  // => Uncaught ReferenceError: x is not defined *读取一个未声明的变量会报错
x=1 // 给一个未声明的变量赋值,等于创建一个全局变量
x // => 1。

3:重复声明(3.9节)

使用var语句重复声明变量是合法且无害的。

var v1 = 1
var v1 = 2 // 重复声明带有初始化器,这条语句就像是简单的赋值语句
v1 // => 2var v2 = 1;
var v2 // 重复声明语句不带初始化器,那就什么也不发生
v2 // y的结果是1

4:严格模式:"use strict"语句(5.7.3节)

在JavaScript设计之初留下了许多被人诟病的问题,比如变量在声明之前就可以访问,比如给未声明的变量赋值,则这个变量会被定义为一个全局变量,这样会扰乱全局作用域的属性。

ECMAScript5定义了严格模式,严格模式是该语言的一个受限制的子集,它修正了语言的严重缺陷,并提供健壮的差错功能和增强的安全机制。

在严格模式中,给未声明的变量赋值会报错,在变量定义的代码之前读取该变量也会报错。

5:function:函数声明(5.3.2节)

关键字function用来定义函数。

  • 函数声明语句
function f(x) { return x + 1; }
  • 函数定义表达式
var f = function(x) { return x + 1; }

5.1:函数调用表达式(invocation expression)(4.5节)

函数调用表达式:以一个函数表达式开始,函数表达式后跟随一对圆括号,括号内是一个以逗号分割开的参数列表。

f()
f(0)
Math.max(x,y,z)

5.2:函数声明表达式和函数声明语句(4.3节、5.1节)

函数定义表达式:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/function

function [name]([param_1[, param_2[, ..., param_N]]]) {
[statements]
};

函数声明语句:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function

function name([param_1,[, param_2,[..., param_N]]]) {
[statements]
}

函数声明语句和函数表达式语句几乎没有区别,唯一的区别是函数定义表达式的函数名(name)是可选的,JavaScript预编译把一段函数定义代码编译成表达式还是语句,主要看这段code出现的位置。

表达式(expression):JavaScript解释器会将表达式计算(evaluate)出一个结果,如果没有赋值语句,则这个结果不会产生任何副作用。复杂的表达式由简单的表达式组合而成。语句(statement):语句用来执行使某件事情发生,是会产生“副作用”的表达式。

语句:直接使用符合函数声明语句的格式定义一个函数,则JS将函数编译为为函数声明语句。

function f1(x) { return x*x; }  // 这条语句会产生一个副作用,就是定义了一个name为f1的函数。
f1; // 输出f1,可以看到函数的值。(在JS中,函数也是一个值)
f1(3); // =>9 当然,你可以用函数调用表达式调用这个函数,输出结果是9

表达式:

  1. 出现在等号左边的函数定义,JavaScript通常会编译为函数定义表达式。
var f2 = function(x){ return x*x; }  // 这个函数定义会被编译为函数定义表达式,计算出的结果再赋值到变量f2。
f2; // 输出f2,可以看到函数的值。(在JS中,函数也是一个值)
  1. 出现在括号里的函数定义,JavaScript通常会编译为函数定义表达式:
[1,2,3].map(function(x){ return x*x })  // 定义一个匿名函数
(function(){return 1}()) // 定义一个立即调用函数
(function(){return 1})() // 同上

这也就是为什么立即调用函数一定要用括号括起来的原因,如果没有括号,js预编译会把它当作一个函数声明语句

  1. 出现在方括号里的函数定义,JavaScript通常会编译为函数定义表达式:
[function(){return 1;}]
  1. 箭头函数表达式:箭头函数表达式的语法比函数表达式更短。

表达式计算出一个值,在JavaScript中,函数就是一个值,可以被赋值可以被传递,但表达式不会对程序产生副作用

var f4 = function ff(x){ return x*x; }; ff;  // =>undefined *因为表达式不产生副作用,没有名为ff函数,如果调用ff(),会报错
(function ff(){return 1})(); ff; // 同上
[function ff(){return 1;}]; ff; // 同上

5.3:避免js引起错误编译, ( [ + - / 前加分号

上面有4种情况:等于号、圆括号、方括号,箭头函数会被认为是表达式。

一条语句如果以这些符号开头,那么js编译器会把他们当作表达式来解析,那么就会产生问题,因为JS一条句子结束可以不加分号,而这里表达式并不是一句语句,所以这个表达式会和前面(没有分号的句子)表达式合并成一条语句。

比如在任意一条语句后面定义匿名函数,都会报错。

var a = 1
(function(){ console.log('hello world') })()
// => Error: 1 is not a function

这是因为匿名函数这里被当作表达式解析,但表达式不是一条语句,所以会和前面的内容合并成一条语句。如果以 [ 也同理。当然我们不会以等于号开头以及箭头函数开头。所以要格外注意以 ([ 开头的句子。解决办法就是在 ( 前面加一上分号。当然,很多都会每一行结尾加分号,这也能避免这种麻烦。

var a = 1
;(function(){ console.log('hello world') })()

类似的情况还有加号+、减号-、正则的起始符/,所以遇到 ( [ + - / 这5个符号开头的句子,要注意让编译器知道这些表达式不属于前面的语句。

也就是如果你是一个不喜欢加分号的程序员,那就要在这5个符号开头的句子前加上分号,或者避免以这5个符号开头。

6:声明提前(hoisting)(3.10.1节)

JavaScript引擎在“预编译”会把var声明语句会和函数声明语句提前至函数顶部,这就意味着整个作用域内都可以该变量。但var声明语句的初始化代码不会被提升到函数顶部,所以在初始化代码之前访问变量,则变量的值为undefined,声明代码之前给变量赋值,则是一条正常的赋值语句。

console.log(v3)  // 声明被提前,但在初始化之前访问,不会报错,结果未undefined
var v3 = 1 // “预编译”已经将声明提前,“解释器”运行到此是初始化变量
console.log(v3) // 在初始化之后访问v3,结果是

在变量声明代码之前给变量赋值,是一条正常的赋值语句,并不是遗漏声明,因为代码声明已经被提至函数顶部。

function f(){
a = 1 // 预编译在代码解释之前完成,当解释器解释到这条赋值语句的时候,预编译已经声明变量a,所以这是一条正常的赋值语句
var a // 声明是预编译完成的,并不是js解释器完成的
}f();
a // => a is not defined 因为a=1并不是遗漏声明,所以没有创建全局变量

注意:在声明变量的代码之前调用变量是没有任何问题,而给遗漏声明的变量赋值JS会自动创建一个全局变量,但是访问为声明的变量会报错。console.log(v4); // Uncaught ReferenceError: v4 is not defined

作用域链上找不到对象时会报错,原型链上找不到属性是返回undfined,不报错。

f1()  // 函数声明也被提前,在定义函数之前就可以调用函数f1
function f1(){return 1;}
function f2(){return ff; function ff(){return 100;}}
f2()() // ff的声明被提前,所以返回的ff是一个函数对象

函数声明语句会提前,而函数定义语句不会提前。这就比较有趣了,var变量声明会被提前,但函数定义要到初始化表达式的时候,才会定义。

f3  // 和函数声明语句截然相反,函数表达式的定义并没有提升,f3的值是undefined,
var f3 = function() {return 1;} // 用函数定义表达式定义一个函数。
function f4(){return ff; var ff = function (){return 100;}}
f4() // ff声明提前,但表达式定义没有提前,所以返回的ff是一个undefined

@@@在ES2015之前,申明变量都用var,var只有函数作用域和局部作用域,没有块作用域,在ES2015开始,有let和const

JavaScript 函数声明和变量声明的更多相关文章

  1. javascript中函数声明、变量声明以及变量赋值之间的关系与影响

    javascript中函数声明.变量声明以及变量赋值之间的关系与影响 函数声明.变量声明以及变量赋值之间有以下几点共识: 1.所有的全局变量都是window的属性 2.函数声明被提升到范围作用域的顶端 ...

  2. (转载)javascript函数作用域和提前声明

    http://www.cnblogs.com/ArthurPatten/p/3274080.html 一些语言如C.java都有块级作用域,即花括号内的每一段代码都具有各自的作用域,而且变量在声明它们 ...

  3. javascript函数作用域和提前声明

    一些语言如C.java都有块级作用域,即花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的,但是javascript没有块级作用域.javascript使用函数作用域,即 ...

  4. JavaScript 函数的两种声明方式

    1.函数声明的方式 JavaScript声明函数有两种选择:函数声明法,表达式定义法. 函数声明法 function sum (num1 ,num2){ return num1+num2 } 表达式定 ...

  5. Javascript中的循环变量声明,到底应该放在哪儿?

    相信很多Javascript开发者都在声明循环变量时犹豫过var i到底应该放在哪里:放在不同的位置会对程序的运行产生怎样的影响?哪一种方式符合Javascript的语言规范?哪一种方式和ecma标准 ...

  6. JavaScript变量声明与变量声明提前

    JavaScript变量声明 JavaScript中存储数据的容器称为变量.用关键字和标识符创建新变量的语句,称为变量声明.可以通过关键字var进行变量声明,在ES6中增加了let.const关键字声 ...

  7. [JavaScript]JS中的变量声明与有效域

    1.变量声明 var a = 1; //使用var声明变量 b = 1; //不使用var 第一种情况,在当前域中声明一个名为a的变量,如果实在方法内则为局部变量,若在最外层声明则a为全局变量. 第二 ...

  8. javascript 函数的几种声明函数以及应用环境

    本页只列出常用的几种方式,当然还有比如new Function()以及下面三种的组合. 1.函数式声明 例子:function sum(a,b){ return a+b; }; 2.函数表达式声明(匿 ...

  9. 浅谈javascript函数,变量声明及作用域

    javascript函数跟变量的声明.作用域这些概念网上都已经讲烂了. 这里写个博客,也相当于做个笔记. 变量声明 首先看个例子: var globalVar = "gv"; fu ...

随机推荐

  1. 关于十二生肖的数学发现(C++)

    把数字看成是年份,然后根据生肖赋值.这里把鼠年赋值为1,牛年赋值为2,虎年赋值为3,兔年赋值为4,龙年赋值为5,蛇年赋值为6,马年赋值为7,羊年赋值为8,猴年赋值为9,鸡年赋值为10,狗年赋值为11, ...

  2. CF468C Hack it! 超详细解答

    CF468C Hack it! 超详细解答 构造+数学推导 原文极简体验 CF468C Hack it! 题目简化: 令\(f(x)\)表示\(x\)在十进制下各位数字之和 给定一整数\(a\)构造\ ...

  3. Dapr-简介及环境搭建

    一.Dapr是什么? Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的.无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架. 在 ...

  4. 防止SQL注入总结

    1.预编译(占位符)可以很大程度上防止SQL注入 预编译的原理是数据库厂商提供的JAR包中,对参数进行了转义 2.mybatis中,能用# 的地方,不用$,因为#是预编译占位符形式,可以防止SQL注入 ...

  5. redis5集群搭建步骤

    通常情况下为了redis的高可用,我们一般不会使用redis的单实例去运行,一般都会搭建一个 redis 的集群去运行.此处记录一下 redis5 以后 cluster 集群的搭建. 一.需求 red ...

  6. 零基础小白要如何跟好的学习嵌入式Linux

    作为一个新人,怎样学习嵌入式Linux?被问过太多次,特写这篇文章来回答一下. 在学习嵌入式Linux之前,肯定要有C语言基础.汇编基础有没有无所谓(就那么几条汇编指令,用到了一看就会). C语言要学 ...

  7. 零基础学习Linux心得总结

    很多同学接触linux不多,对linux平台的开发更是一无所知. 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机it行业从业人员,="" 掌握linux是一种很重要的 ...

  8. linux shell 基本语法之快速上手shell编程

    从程序员的角度来看, Shell本身是一种用C语言编写的程序,从用户的角度来看,Shell是用户与Linux操作系统沟通的桥梁.用户既可以输入命令执行,又可以利用 Shell脚本编程,完成更加复杂的操 ...

  9. Go并发编程--Mutex/RWMutex

    目录 一.前言 二. Mutex 2.1 案例 三. 实现原理 3.1 锁的实现模式 3.2 Go Mutex 实现原理 3.2.1 加锁 3.2.2 解锁 四. 源码分析 4.1 Mutex基本结构 ...

  10. 升级 dubbo 小心 default.version

    上周遇到个关于升级dubbo 2.6 到2.7的兼容性问题,差点造成线上故障,这里记录下,也给大家提个醒. 问题回放 有一个接口的提供方(dubbo 2.6.6)这么配置接口的版本号 <dubb ...