JavaScript 函数声明和变量声明

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

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

原文地址:https://www.cnblogs.com/luciolu/p/11956994.html

时间: 2024-11-07 06:37:56

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

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

函数声明.变量声明以及变量赋值之间有以下几点共识: 1.所有的全局变量都是window的属性 2.函数声明被提升到范围作用域的顶端 3.变量声明被提升到范围作用域的顶端 4.变量声明比函数声明的优先级高,变量声明优先于函数声明被提升,如果两者同名同时存在,后被提升的函数声明会覆盖先被提升的变量声明 5.变量赋值不会被提升,到执行行代码才开始赋值 补充: 6.调用javascript函数的整个过程可以分为预编译期(也叫声明期)和赋值期(也叫计算执行期). 预编译期完成对所有变量(包括形参.函数内部

参数传递--函数声明与变量声明优先级?

javascript是一门解释性语言,自然没有编译过程,但在脚本执行之前会有语法检查和执行环境的构建,我们把这一过程姑且称为预处理吧. 一.函数声明,javaScript解析器把函数提升 fn();  //output  2 var fn= function(){ console.log(1); } function fn(){ console.log(2); } fn();  //output  1 首先,后面的fn()函数声明提前,所以第一个fn() 为2 其次,后面定义的fn()覆盖前面声

函数声明与变量声明

1.函数声明与变量声明都会进行变量的声明与提升 2.function name(){}这种格式为函数声明 var x = function name(){}这是函数表达式,相当于变量赋值,也就是说此处的函数不会进行变量的声明与提升 3.函数声明会覆盖变量声明,但不会覆盖变量赋值 function name(){} var name; alert(typeof name)//结果为function 但如果是 function name(){} var name=1; alert(typeof na

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

不放走任何一个细节.相信很多Javascript开发者都在声明循环变量时犹豫过var i到底应该放在哪里:放在不同的位置会对程序的运行产生怎样的影响?哪一种方式符合Javascript的语言规范?哪一种方式和ecma标准未来的发展方向匹配?本文将对四种常见的声明循环变量的书写方式进行简单的分析和比较. 习惯1:不声明直接使用 function loop(arr) { for (i = 0; i < arr.length; i++) { // do something } } 非常危险的使用习惯,

变量声明置顶规则、函数声明及函数表达式和函数的arguments属性初始化

一.变量声明和变量赋值: if (!("a" in window)) { var a = 1; } alert(a);//a为? 你可能认为alert出来的结果是1,然后实际结果是"undefined".要了解为什么,我们需要知道JavaScript里的3个概念: 1.所有的全局变量都是window的属性,语句 var a = 1;等价于window.a = 1; 可以用如下方式来检测全局变量是否声明: "变量名称" in window 2.声明

javascript篇-----函数作用域,函数作用域链和声明提前

在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的(也就是我们不能在代码段外直接访问代码段内声明的变量),我们称之为块级作用域,然而,不同于这类型的编程语言,javascript是没有块级作用域.取而代之的,javascript使用的是块级作用域:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的. 在如下的所示的代码中,在不同位置定义了变量 i . j 和 k ,它们都在同一个作用域内——这三个变量在函数体内均是有定义

深入理解变量声明提升和函数声明提升

变量声明提升 1.变量定义 可以使用var定义变量,变量如果没有赋值,那变量的初始值为undefined. 2.变量作用域 变量作用域指变量起作用的范围.变量分为全局变量和局部变量.全局变量在全局都拥有定义:而局部变量只能在函数内有效. 在函数体内,同名的局部变量或者参数的优先级会高于全局变量.也就是说,如果函数内存在和全局变量同名的局部变量或者参数,那么全局变量将会被局部变量覆盖. 所有不使用var定义的变量都视为全局变量 3.函数作用域和声明提前 JavaScript的函数作用是指在函数内声

javascript变量声明,hoisting机制,面向对象

以下不遵守可能引起未知错误 1.  表示区块起首的花括号,不要另起一行. 2.  不要省略句末的分号 3.  不要使用with语句,可以减少代码的书写,但是会造成混淆. 4.  不要使用"相等"(==)运算符,只使用"严格相等"(===)运算符. == 两边值类型不同的时候,要先进行类型转换,再比较,造成很多意想不到的情况. === 不做类型转换,类型不同的一定不等. 0 == ''// true 1 == true // true 2 == true // fal

函数声明的提升和变量声明提升

注:本文转自:http://blog.csdn.net/qq673318522/article/details/50810650仅做学习方便,没有任何商业目的: 变量声明提升 1.变量定义 可以使用var定义变量,变量如果没有赋值,那变量的初始值为undefined. 2.变量作用域 变量作用域指变量起作用的范围.变量分为全局变量和局部变量.全局变量在全局都拥有定义:而局部变量只能在函数内有效. 在函数体内,同名的局部变量或者参数的优先级会高于全局变量.也就是说,如果函数内存在和全局变量同名的局