定义提升(1)

来源:互联网 发布:数据库系统设计与实现 编辑:程序博客网 时间:2024/05/01 02:13

在《JavaScript权威指南》第六版的4.3节和5.3节中分别讲了函数的两种定义方式:

函数声明方式:  function foo(){}函数表达式方式:var foo= function(){}

两者的区别在于函数声明的方式会有一个“定义提升”(hoisting),即将函数声明提升到顶部,这样之后的代码也都可以访问到它。函数表达式的方式则不存在定义提升。通过下面两个例子展示两者的区别:

例子1:foo();//调用成功:function foo(){ console.log('ok');}


例子2:   foo();//调用失败,"uncaught TypeError: Property 'foo' of object [object Object] is not a function"var foo = function(){  console.log('ok');}

例子1中虽然是先调用foo,然后才声明的foo函数,但是由于定义提升,foo的声明被提高到顶部,因此foo调用成功。例子1的代码等价于:

function foo(){  console.log('ok');}        foo();//调用成功

例子2中,foo是函数表达式,不存在定义提升,所以先调用后定义的方式是行不通的。和函数声明同样有定义提升的效果的还有var关键字定义的变量,请看下面例子:

例子3:          console.log(i);//undefinedvar i = 1;console.log(i);//1
var i =1;可以看成变量定义和初始化两部分,var i; i =1;其中变量定义提升,放在了最开始的部分,而初始化还是留在原地,所以第一次输出的是undefined,第二次输出的是1;

因此之前的例子2等价于下面的代码:

   var foo;     foo();//调用失败   foo = function(){  console.log('ok');}
这也就说明了为什么报错的内容是“foo不是一个函数”。

由于有定义提升,在同一作用域下所以要特别注意函数同名覆盖的问题。由于多次用var声明一个变量是无所谓的(《JavaScript权威指南》第六版的5.3.1节),这里只需要讨论函数之间同名覆盖、函数与变量同名覆盖两个问题。请看下面的例子:

例子4:function fun1(){alert('A');}fun1(); //结果为 Bfunction fun1(){ alert('B');}
可以看到函数声明的提升,会按照出现的顺序进行覆盖。

例子5:(function(a){    console.log(a);//输出函数a的内容    function a(){};    var a=10;}(100))

可以看到函数声明和变量声明的提升,会以函数声明为主。因为在函数执行上下文中,变量声明不会干扰已经存在的同名变量,形参和函数声明。说到执行上下文(EC)又是一个比较大的话题,我把它放到下一篇,这里就略过。

最后再看一个比较综合的例子:

例子6:function Foo() {    getName = function () { alert (1); };    return this;}Foo.getName = function () { alert (2);};var getName = function () { alert (4);};function getName() { alert (5);}问:Foo.getName();getName();Foo().getName();getName();

答案:Foo.getName();//2
           getName();//4
           Foo().getName();//1
           getName();//1

解释可以参考最后参考文章中给出的第二个链接,这里就不再赘述了。

参考文章:

1、JavaScript函数声明和函数表达式的区别:函数声明的提升

2、一道常被人轻视的JS前端面试题


1 0
原创粉丝点击