声明函数和函数表达式的定义

JavaScript中的声明函数即是准备用来多次调用的函数,而函数表达式也就是常说的匿名函数,往往只会调用一次。

//声明函数
function sayHi(){
    console.log("hi");
}
//函数表达式
var nm = function(){
    console.log("hello");
}

了解两者的主要区别

JavaScript的代码运行之前会将源码交给js解析器进行解析,之后再交给执行环境执行。

而在js解析器中,有两个提升,一是变量提升,二是函数声明提升。

  1. 变量的声明会被提取出来(这里一般指var),先执行变量的声明,变量会声明为undefined,再进行其他代码的执行,其表现如下:
console.log(name);  //undefined
var name = "前端猪仔";
  1. 声明函数会被提取出来,先执行函数的声明,再进行其他代码的执行,其表现如下
sayHi();  //hi
function sayHi(){
    console.log("hi");
}
nm();  //Uncaught TypeError: undefined is not a function
var nm = function(){
    console.log("hello");
}

关于声明函数的一点事

函数声明不能被条件式的定义。如果你需要条件定义,那就应该用函数表达式。

if(true){
    function say(){
        console.log("hi");
    }
}else {
    function say(){
        console.log("hello");
    }
}
say();  //hello

因为函数的声明被js解析器提前了,而在js的解析中,处在同一个作用域的第二个函数取代了第一个函数。关于js的作用域,在我的理解中是函数才是块级作用域的限定,而不是{}号,当然在ES6中,let,const都是真正意义上的块级作用域,可以限定在{}内。

而为什么函数表达式可以被条件式的定义,其在于,虽然变量的声明被提前了,但是只是赋值了undefined,所以可以条件式的定义执行语句。

关于函数表达式的一点事

在函数表达式中函数是变量赋值的一部分,拥有自己的作用域。

function sayHi(){
    console.log("hello");
}
var say = function sayHi(){
    console.log("hi");
}
sayHi();  //hello
say();  //hi

虽然第一个函数名和第二个函数名相同,但是第二个函数是变量赋值的一部分,所以相当于不同于第一个函数的实体,且在赋值完毕后,该函数名便不在存在,所以不会起到函数命名的冲突。

讲到这里,之前一直有个很不能理解的立刻执行函数:

(function(a){
    console.log(a);
})(123);      //123

(function(a){
console.log(a);
}(1234)); //1234

function(a){
console.log(a);
}(12345)
//因为未执行赋值操作,所以
javascript引擎将开头的function关键字当做函数声明,并忽略掉最后的括号

现在总算明白里一点,给匿名函数加括号是因为这样可以让代码在执行的时候认为该匿名函数是函数表达式而不是函数声明,才可以立即执行。

可以使用这种技术可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,所以( function(){…} )()内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。

当然我觉得ES6出现的let和const可以使得在一定程度上不需要再进行模仿私有作用域的操作

关于我写博客的问题

我一直再学习新知识,至少对我而言很多都是新知识,但是不是说我看过一边这个关于新知识我就会掌握的,所以我往往不会说看到新知识我就写个博客,因为没有必要。

我通常会再第二次接触到这个知识的时候写博客,而且不能写太难的,因为那些不知道自己到底能不能说的透彻,虽然简单的也不一定可以。比如说这篇博客,我就是看了知识,然后看了好几篇文章,觉得终于好像理解了一点才敢下笔写。所以我通常会挑点有意思的,值得我去巩固的写。

还有最后一件事,感觉广东的天气时冷时热的,大家要注意看天气助手,即使添衣保暖。

本文使用 markdown.com.cn 排版