javacript 变量、函数声明、函数表达式之声明提升详解

作者: tww844475003 分类: 前端开发 发布时间: 2022-07-10 14:31

变量声明提升

变量声明提升至项部。

if (false) {
  var a = 10;
}
console.log(a); // undefined

// 相当于
var a;
if (false) {
  a = 10;
}
console.log(a); // undefined

结论:由于变量声明提升,故输出 undefined,而非报错信息。 Uncaught ReferenceError: a is not defined。

函数声明提升

函数声明提升至顶部。

foo();
function foo() {
  console.log(1)
}

// 相当于
function foo() {
  console.log(1)
}
foo();

结论:由于函数声明提升,故输出 1,而非报错信息。 Uncaught TypeError: foo is not defined。

函数表达式提升

只是变量声明提升,函数表达式函数体并没有提升。

console.log(1, foo)
foo();
var foo = function() {
  console.log(1)
}

// 相当于
var foo;
console.log(foo)
foo();
foo = function() {
  console.log(1)
}

结论:由于只是变量声明提升,故输出 undefined 和 Uncaught TypeError: foo is not a function

函数提升优先级高

函数声明和变量声明都会被提升。但是函数会首先被提升,其次才是变量

foo();
function foo() {
  console.log(1);
}
var foo = function() {
  console.log(2);
}

结论:输出1非2,或者Error。

提升后 this 作用域

let o = {
  m: function() {
    let self = this;
    console.log(this === o); // true this 是对象o
    foo();

    function foo() {
      console.log(this === o); // false this 是全局对象或 undefined
      console.log(self === o); // true self 是外部的 this 值
    }
  }
}
o.m();

在嵌套函数 foo() 内部,this 关键字不等于对象 o,这被广泛认为是 javascript 语言的一个缺陷。那如何解决了,如上代码所示可以用 self 赋值,那有没有其它办法了,答案是当然有的。

es6 的箭头函数 和 bind() 都可以解决。

let o = {
  m: function() {
    let self = this;
    console.log(this === o); // true this 是对象o

    // function foo() {
    //   console.log(this === o); // false this 是全局对象或 undefined
    //   console.log(self === o); // true self 是外部的 this 值
    // }

    const foo = () => {
      console.log(this, this === o);  // true this 是对象o
      console.log(self, self === o);  // true this 是对象o
    }

    // const foo = (function() {
    //   console.log(this === o);  // true this 是对象o
    // }).bind(this);

    foo();
  }
}
o.m();

注意:这里使用的是函数表达式声明,函数体并没有提升,所以函数调用需要移下来,不然就会报 foo is not function。

构造函数调用

new o.m() 会是什么样的效果了?

let o = {
  m: function() {
    let self = this;
    console.log(this === o); // true this 是对象o

    // function foo() {
    //   console.log(this === o); // false this 是全局对象或 undefined
    //   console.log(self === o); // true self 是外部的 this 值
    // }

    const foo = () => {
      console.log(this, this === o);
      console.log(self, self === o)
    }

    // const foo = (function() {
    //   console.log(this === o)
    // }).bind(this);

    foo();
  }
}
new o.m();

构造函数调用会创建一个新的空对象,这个对象继承构造函数的 prototype 属性指定的对象。构造函数就是为初始化对象设计的,这个新创建的对象会被用作函数的调用上下文。

前端开发那点事
微信公众号搜索“前端开发那点事”

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注