JavaScript之预编译与变量提升的那些事、window、AO、GO、return、if


01、概述

JavaScript代码在执行之前首先经过预编译。预编译的过程中函数声明会被整体提升,变量只有声明被提升,赋值留在原地。


02、示例代码-1-函数的提升

precompileVariablePromotion();
// 预编译/变量提升
function precompileVariablePromotion() {
	console.log('预编译/变量提升');
}
precompileVariablePromotion();
// 预编译/变量提升

此例中的两种执行顺序都能正确调用函数,说明函数发生了提升,且函数体的内容也一同被提升。


03、示例代码-2-基本数据类型的提升

console.log(a);
// undefined

var a;

console.log(a);
// undefined

a = 7;

console.log(a);
// 7

此例中的a在打印时都没有报错,所以说明了a被提升了,只是没有赋值,所以前两个打印的值为undefined,第三个打印才是赋值,也说明了赋值留在原地。


04、示例代码-3-函数提升优先级高于基本类型数据的提升

console.log(precompileVariablePromotion);
// ƒ precompileVariablePromotion(precompileVariablePromotion) {
//     var precompileVariablePromotion = 7;
//     var precompileVariablePromotion = function () { };
// }
var precompileVariablePromotion = 3;
function precompileVariablePromotion(precompileVariablePromotion) {
	var precompileVariablePromotion = 7;
	var precompileVariablePromotion = function () { };
}
var precompileVariablePromotion = 5;

此例中函数发生了提升,并且函数体同时被提升。因为函数提升的优先级高于基本类型数据提升,所以函数提升会覆盖掉所有同名的基本类型数据提升。


05、window对象

var a = 1;
// 如果给一个为声明的变量赋值
// 那么此变量会被挂载到window对象上
b = 2;
console.log(window.a, window.b);
// 1 2

window.a = 7;
window.b = 6;

console.log(window.a, window.b);
// 7 6

此例中的两种方式是一样的效果,都是把值挂载到window对象上。


06、在一个函数中给一个未定义的变量赋值,变量会被挂载到window对象上

function precompileVariablePromotion() {
	var a = b = 7;
	// 此写法等同于
	// b = 7;
	// var a = b;
	// 且从右往左执行
	
	// 在一个函数中给一个未定义的变量赋值,
	// 此变量会被挂载到window对象上
}
precompileVariablePromotion();
// console.log(a);
// Uncaught ReferenceError: a is not defined
console.log(window.b, b);
// 7 7
// 此处的b被挂载到window上了

07、函数内的变量提升

function precompileVariablePromotion(params) {
	console.log(params);
	// 因为函数提升的优先级最高,
	// 所以此处打印的是函数表达式
	// ƒ params() { }
	var params = 7;
	console.log(params);
	// 因为到此处时之前的变量提升已经结束,
	// 已经到了赋值阶段
	// 所以打印了7
	// 7
	function params() { };
	// 当代码运行到此处时,
	// 函数已经提升过了
	// 所以不会再做任何操作
	// 因此下一个打印的值依然是7
	console.log(params);
	// 7
	var b = function () { };
	console.log(b);
	// ƒ () { }
	function c() { };
	// 函数c只是起到迷惑的作用
}
precompileVariablePromotion(3);

08、函数形参的提升优先级低于函数

function precompileVariablePromotion(a, b) {
	console.log(a);
	// 3
	c = 7;
	var c;
	a = 5;
	b = 6;
	console.log(b);
	// 6

	function b() { };
	// 在预编译时b已经被提升,
	// 所以在运行时不会再做任何操作
	// 也就是说 b = 6; 能正常赋值
	// 所以两个打印都是 6

	function d() { };
	console.log(b);
	// 6

	// 如果打开此处的注释
	// 那么第一打印就是
	// ƒ a() { }
	// 这里进步一步说明了
	// 函数提升的优先级高于形参提升的优先级
	// function a() { };
}
precompileVariablePromotion(3);

09、GO(global object)全局上下文

console.log(precompileVariablePromotion);
// ƒ precompileVariablePromotion() {
//    console.log(7);
// }
var precompileVariablePromotion = 1;
function precompileVariablePromotion() {
	console.log(7);
}
console.log(precompileVariablePromotion);
// 1
// 在预编译时,函数声明已被提升
// 之后声明了变量,且给变量赋值为1
// 所以在函数后面打印到的就是1

10、只有函数声明才会发生函数体一同提升

console.log(a);
// ƒ a() { }
console.log(b);
// undefined
// 因为b就是个普通的变量
// 在此处b发生了变量提升
// 但是没有值
// 所以是undefined
// 只有函数声明才会发生变量提升和函数体一起提升
function a() { };
var b = function () { };

11、往外查找变量原则

function precompileVariablePromotion() {
	var a = b = 7;
	// 此处的b被挂载到全局window上
	console.log(a);
	// 7
	console.log(b);
	// 7
	console.log(window.b);
	// 7
}
precompileVariablePromotion();
// console.log(a);
// Uncaught ReferenceError: a is not defined
console.log(b);
// 7

12、如果自己身上有就不往外查找

var b = 2;
function precompileVariablePromotion() {
	var a = 3,
		b = 7;
	console.log(a);
	// 3
	console.log(b);
	// 7
	// 因为函数内部有b变量,
	// 所以不会往外查找
	console.log(window.b);
	// 2
}
precompileVariablePromotion();
console.log(b);
// 2

13、AO与GO结合、并且注意函数是否被调用

var b = 3;
console.log(a);
// ƒ a(a) {
//     console.log(a);
//     var a = 2;
//     console.log(a);
//     function a() {
//         var b = 5;
//         console.log(b);
//     }
// }
function a(a) {
	console.log(a);
	// ƒ a() {
	//     var b = 5;
	//     console.log(b);
	// }
	var a = 2;
	console.log(a);
	// 2
	function a() {
		var b = 5;
		console.log(b);
	}
}
a(1);

14、是否往全局查找变量

a = 1;
function test() {
	console.log(a);
	// undefined
	// 函数内发生了变量提升
	// 因为 var a = 3;
	// 所以不会往全局找
	a = 2;
	console.log(a);
	// 2
	var a = 3;
	console.log(a);
	// 3
}

test();
var a;

15、预编译只管找变量和形参,不关注代码是否会被执行,所以变量提升与执行时是否进入某个判断无关

function test() {
	console.log(b);
	// undefined
	// 预编译只管找变量和形参,
	// 不关注代码是否会被执行
	// 所以变量提升与是否进入某个判断无关

	console.log(a);
	// undefined
	// 此处的a用的是GO(全局)里面的变量
	if(a){
		var b = 2;
	}
	c = 3;
	console.log(c);
	// 3
	console.log(b);
	// undefined
}
var a;
test();
a = 1;
console.log(a);
// 1

16、函数内变量提升并返回(return在后)

function test() {
	a = 1;
	function a() { };
	var a = 2;
	return a;
}
console.log(test());
// 2

17、函数内变量提升并返回(return在前)

function test() {
	return a;
	a = 1;
	function a() { };
	var a = 2;
}
console.log(test());
// ƒ a() { }

18、变量提升不会阻碍判断

a = 1;
function test(e) {
	function e() { };
	arguments[0] = 2;
	console.log(e);
	// 2
	console.log(a);
	// a发生了变量提升
	// 但是还没有赋值
	// 所以进不了判断
	if (a) {
		var b = 3;
	}
	var c;
	a = 4;
	var a;
	console.log(b);
	// undefined
	// b发生了变量提升
	// 因为预编译不管是否会进入判断
	// 都会发生变量提升
	f = 5;
	console.log(c);
	// undefined
	console.log(a);
	// 4
}
var a;
test(1);

console.log(f);
// 5
console.log(a);
// 1

19、多个相同函数声明的时候,最后声明的函数会覆盖先前所有提升过的函数

fn();
// 2

function fn() {
	console.log('1');
}

function fn() {
	console.log('2');
}

20、通过字面量声明的函数,如果在声明之前调用会报错,与定义变量的形式一样,声明会提前,但是赋值留在原地

fn();
// Uncaught TypeError: fn is not a function

var fn = function () {
	console.log('fn');
}

21、形参、实参、函数表达式、函数声明

function fn(a) {
	console.log(a);
	// ƒ a() {}
	var a = 7;
	console.log(a);
	// 7

	function a() {};
	console.log(a);
	// 7
	var b = function() {};
	console.log(b);
	// ƒ () {}

	function d() {};
	var d = a;
	console.log(d);
	// 7
}

fn(1);

22、变量声明与函数声明的提升顺序,函数声明提升高于一切

console.log(a);
// ƒ a() {
//     return 3;
// }

function a() {
	return 3;
}
var a = 7;
console.log(a);
// 7

23、变量声明的合并

console.log(a);
// ƒ a() {
//     return 3;
// }

var a = 3;
function a() {
	return 3;
}
var a = 7;

console.log(a);
// 7

24、预编译与逻辑判断无关

函数内部有自己的变量就不会向外部查找,且在预编译时所以的变量都要经过提升这个过程,不管判断和逻辑。

var a = 4;
(function () {
	// 'undefined'不等undefined
	if (typeof a == undefined) {
		var a = 5;
		console.log(a);
	} else {
		console.log(a);
		// undefined
	}
})();

25、函数声明会提升,函数表达式不会提升,等同于定义变量

foo();
// foo
bar();
// Uncaught TypeError: bar is not a function

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

var bar = function() {
	console.log('bar');
}
  • 30
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: 在 JavaScript 中,变量提升指的是在代码执行前,变量声明就已经被提升(即复制)到了当前作用域的最顶端。这意味着,无论变量在代码中定义在哪里,它都会在代码执行前被提升到所在作用域的最顶端。 例如: ``` console.log(a); // undefined var a = 1; ``` 在这个例子中,虽然变量 `a` 实际上定义在了第二行,但是在代码执行前,它已经被提升到了最顶端。所以在第一行中,当我们尝试访问 `a` 时,它已经被声明过了,所以输出 `undefined`。 注意,变量提升仅仅是声明(复制)被提升,而不是赋值。所以在上面的例子中,变量 `a` 的值在第二行被赋值为 1,而不是在第一行被赋值为 `undefined`。 ### 回答2: JavaScript变量提升JavaScript中的一种特性。在JavaScript中,变量的声明会在代码执行之前进行处理,也就是说它们会被“提升”到其作用域的顶部。这意味着你可以在声明之前使用变量,而不会引发错误。 例如,假设我们有以下的JavaScript代码: ``` console.log(x); // undefined var x = 5; console.log(x); // 5 ``` 在这个例子中,变量x被提升到了代码的顶部,所以在第一个console.log语句中,x被声明了但尚未被赋值,所以它的值是undefined。然后,变量x被赋值为5,并在第二个console.log语句中打印出来。 需要注意的是,只有变量的声明会被提升,而不是它们的赋值。例如: ``` console.log(y); // ReferenceError: y is not defined y = 10; console.log(y); // 10 var y; ``` 在这个例子中,变量y在它的声明之前被使用会引发错误。只有在变量y的声明后,它的赋值才会生效。 变量提升在理解JavaScript的作用域和执行顺序时非常重要。它使得我们可以在变量声明之前使用变量,但也可能导致一些意外的结果,所以在编写代码时要小心使用。 ### 回答3: JavaScript变量提升是指在代码执行之前,所有变量的声明都会被提升到代码的顶部。这意味着我们可以在变量声明之前使用这些变量。但是要记住的是,只有变量的声明会被提升,而不是初始化。 例如,我们可以在变量声明之前输出变量的值: console.log(x); // undefined var x = 5; 这段代码中,变量x在声明之前被赋值为undefined,因此在打印x时,它的值是undefined。 变量提升还可以应用于函数声明。我们可以在函数声明之前调用函数: myFunction(); // "Hello, World!" function myFunction() { console.log("Hello, World!"); } 在这个例子中,函数myFunction在声明之前被调用,所以我们可以在调用函数之前定义它。 需要注意的是,变量提升仅适用于使用var关键字声明的变量,而不适用于使用let和const关键字声明的变量。使用let和const声明的变量是块级作用域的,不会被提升。 综上所述,JavaScript变量提升是一种将变量的声明提升到代码顶部的机制,使我们可以在变量声明之前使用这些变量。这在代码书写和阅读上提供了一定的便利,但也需要注意一些细节,以避免出现意料之外的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值