js 变量、函数提升 与js的预编译有关
参考网址:http://www.codesec.net/view/178491.html
先简单理解下作用域的概念,方便对变量与函数提升的概念的理解
function foo() {
var x = 1;
if (x) {
var x = 2;
}
console.log(x);
}
foo();//
结果为2,可见js中并没有块级作用域的概念
可以使用下面的方法创造自己的作用域,这样不会干扰到外部变量
function foo() {
var x = 1;
if (x) {
(function() {var x = 2;
}());
}
console.log(x);
}
foo();//
结果为1,可见js中的作用域是以函数为边界的
1.变量提升:
变量提升与js的预编译有关,下面通过例子辅助说明
var a = 100;
var b = 200;
function foo(){
console.log(a);// undefined
a = 10;
console.log(a);//
var a = 1;
console.log(a);//
console.log(b);//
}
foo();
js预编译时会先在当前作用域中找到var声明的变量分配空间,赋值为undefined,如果找不到就会到下一级作用域中找
上面的代码的等价代码如下:
var a = 100;
var b = 200;
function foo(){
var a;
console.log(a);// undefined
a = 10;
console.log(a);//
a = 1;
console.log(a);//
console.log(b);//
}
foo();
这样看是不是容易理解多了。第一行var声明了a,但是没有赋值,因此为undefined,下面打印10、1也就顺理成章了。
至于变量b,它在当前作用域中找不到,因此需要到外层作用域中找,在window下找到了变量b,可以看到它的值为200
2.函数提升
首先要明确两点:
<1> 只有函数声明才会进行函数提升
<2> 函数提升会将函数体一起提升上去,这点与变量提升有所不同
下面来证明函数表达式不能进行函数提升:
~function() {
alert(typeof next); // undefined
~function next() {
alert(typeof next); // function
}()
}()
函数前面加个~的目的是将函数声明变成函数表达式,实际上也可以加其它运算符,比如+,-,!等,总之这个函数声明被变成了函数表达式。
从打印结果来看第一个alert出的是undefined,说明next根本没有发生函数提升。
下面来接着验证:
a();//
var a = function(){
console.log(321);
}
a();//
function a(){
console.log(123);
}
从结果可以看出,先打印出来的反而是放在后面的a(),上面代码的等价表示如下:
var a = function a(){
console.log(123);
}
a();
a = function(){
console.log(321);
}
a();
那么如果当变量提升与函数提升同时发生的时候,哪个的优先级更高呢?我们来做个实验:
function fn(){
console.log(a);
var a = 2;
function a(){}
console.log(a);
}
fn();// function a(), 2
从打印顺序中可以看出,函数提升比变量提升优先级高,因为函数提升是将函数体整体提升,提升上去后立马赋值。等价代码如下:
function fn(){
var a = function(){}
console.log(a);
a = 2;
console.log(a);
}
fn();
下面再来几个有趣的例子:
B = 100;
function B(){
B = 2;
console.log(B);
}
B(); // B is not a function
//函数提升导致的 ////////////////////
B = 100;
var B = function(){
B = 2;
console.log(B);
}
B(); //
//函数表达式不存在函数提升 function change() {
alert(typeof fn); // function
alert(typeof foo); // undefined
function fn() {
alert('fn');
}
var foo = function(){
alert('foo');
}
var fn;
}
change();
//fn提升了,foo没有提升
下面还有几个思考题:
1.
var a = 1;
function b() {
console.log(a);
a = 10;
function a() {}
}
b();// ? function a() {}
console.log(a);// ? 1
2.
a = 10;
(function a(){
a = 1;
console.log(a);// ? function b(){a = 1; .....}
})();
这段代码难以理解,测试代码为:
var a = 10;
var b = 20;
(function b(){
a = 1;
b = 2;
console.log(a);// ?
console.log(b);
})(); console.log(a);
console.log(b);
网上有一段解释是这样的(这样的代码太难理解,最好还是函数和变量不要同名):
感觉楼主的理解还不够深入,正确理解应该是经过以下过程: 当进入执行上下文(代码执行之前)时,VO(变量对象)里已经包含了下列属性: 函数的所有形参(如果我们是在函数执行上下文中) — 由名称和对应值组成的一个变量对象的属性被创建;没有传递对应参数的话,那么由名称和undefined值组成的一种变量对象的属性也将被创建。 所有函数声明(FunctionDeclaration, FD) —由名称和对应值(函数对象(function-object))组成一个变量对象的属性被创建;如果变量对象已经存在相同名称的属性,则完全替换这个属性。 所有变量声明(var, VariableDeclaration) — 由名称和对应值(undefined)组成一个变量对象的属性被创建;如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。
3.
function a(i) {
console.log(i);// ? 10
var i = 1;
console.log(i);// ? 1
};
a(10);
代码分析如下:
function a(i) {
var i;
i = i ; //i是传进来的值
console.log(i);// ? 10
i = 1;
console.log(i);// ? 1
};
a(10);
js 变量、函数提升 与js的预编译有关的更多相关文章
- Js 变量声明提升和函数声明提升
Js代码分为两个阶段:编译阶段和执行阶段 Js代码的编译阶段会找到所有的声明,并用合适的作用域将它们关联起来,这是词法作用域的核心内容 包括变量声明(var a)和函数声明(function a(){ ...
- js中函数提升及var变量提示
其中,在javascript中,函数声明及var声明的变量会得到提升.但是函数声明会先于var声明的变量被提升.即便function写在后面. 看下面的例子: var aa = 221; functi ...
- 【JS】函数提升变量提升以及函数声明和函数表达式的区别
今天看js的变量提升问题,里面提到了函数提升.然后发现自己之前一直把函数声明和函数表达式弄错,导致函数提升出错 一.变量提升 console.log(a) var a=100 //undefined ...
- js变量定义提升、this指针指向、运算符优先级、原型、继承、全局变量污染、对象属性及原型属性优先级
原文出自:http://www.cnblogs.com/xxcanghai/p/5189353.html作者:小小沧海 题目如下: function Foo() { getName = functio ...
- JS变量的提升详解
此次说明的是var与function的变量提升 那么先看一段代码 <script type="text/javascript"> console.log(test); ...
- 解读JavaScript中的Hoisting机制(js变量声明提升机制)
hoisting机制:javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面. 知识点一:javascript是没有 ...
- js变量声明提升
1.变量提升 根据javascript的运行机制和javascript没有块级作用域这个特点,可以得出,变量会声明提升移至作用域 scope (全局域或者当前函数作用域) 顶部的. 变量声明提升至全局 ...
- 【JavaScript高级进阶】JavaScript变量/函数提升的细节总结
// 测试1 console.log('----------test1--------------'); console.log(global); // undefined var global = ...
- VS中c++文件调用c 函数 ,fatal error C1853 预编译头文件来自编译器的早期版本号,或者预编译头为 C++ 而在 C 中使用它(或相反)
出现错误:error C1853: "Debug\ConsoleApplication1.pch"预编译头文件来自编译器的早期版本号.或者预编译头为 C++ 而在 C 中使用它(或 ...
随机推荐
- jQuery中的$.each的用法
$.each(Array,function(i,value){ this; //this指向当前对象 i; //i表示当前下标 value; //value表示当前元素 })
- mouseover&mouseout和mouseenter&mouseleave
mouseenter&mouseleave: 进入被选元素触发,进入被选元素的子元素不会重复触发. mouseover&mouseout: 进入被选元素触发,从被选元素进入其子元素会再 ...
- 报错 ERROR in static/js/vendor.b3f56e9e0cd56988d890.js from UglifyJs
开发vux项目在引入 // 表单验证组件-start import zh_CN from 'vee-validate/dist/locale/zh_CN' import Validator from ...
- WEB安全第二篇--用文件搞定服务器:任意文件上传、文件包含与任意目录文件遍历
零.前言 最近做专心web安全有一段时间了,但是目测后面的活会有些复杂,涉及到更多的中间件.底层安全.漏洞研究与安全建设等越来越复杂的东东,所以在这里想写一个系列关于web安全基础以及一些讨巧的pay ...
- C# 计算当前时间距离今晚00:00:00还有多少分多少秒
.net 计算当前时间距离今晚00:00:00还有多少分多少秒 string dateDiff = null;//获取当前时间 DateTime DateTime1 = DateTime.Now; / ...
- 【BZOJ4428】[Nwerc2015]Debugging调试 记忆化搜索+分块
[BZOJ4428][Nwerc2015]Debugging调试 Description 你看中的调试器将不会在这件事上帮助你.有代码可以通过多种方式在调试与正式发布的间隙发生不同的行为,当出现这种情 ...
- localstorage - HTML 5 Web 存储总结---【巷子】
001.localStorage概念 在html5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储,解决了cookie存储空间不足的问题(cookie中每条cookie存储 ...
- html5新属性contenteditable 对于那些不可编辑的标签,现在都可以编辑了
contenteditable = true 表示该html标签的内容可以编辑,对于那些不可编辑的标签,现在都可以编辑了.
- Groovy中的面向对象
Groovy中的面向对象 前面说到groovy支持脚本和类,前面一节已将简单说了脚本和类之间的关系,这一节主要介绍一下groovy中类的相关知识,即面向对象相关知识. 1.类型 1.1 原始类型 gr ...
- day08:软件系统的体系结构&Tomcat详解&Web应用&http协议
day08 软件系统体系结构 常见软件系统体系结构B/S.C/S 1.1 C/S C/S结构即客户端/服务器(Client/Server),例如QQ: 需要编写服务器端程序,以及客户端 ...