关于JS变量提升的一些坑
function log(str) {
// 本篇文章所有的打印都将调用此方法
console.log(str);
}
函数声明和变量声明总是会被解释器悄悄地被“提升”到方法体的最顶部
变量声明、命名、提升
在JS中, 变量有4种基本方式进入作用域:
- 语言内置: 所有的作用域里都有this和arguments;(需要注意的是arguments在全局作用域是不可见的)
- 形式参数: 函数的形式参数会作为函数体作用域的一部分;
- 函数声明: 像这种形式: function foo() {};
- 变量声明: 像这样: var foo;
变量提升
function test1() {
a = 5;
log(a);
log(window.a);
var a = 10;
log(a);
}
test1();
依次会输出 5 、undefined 、10 因为在解析时候是等价于
var a;
a=5;
log(a);
log(window.a);
a=10;
log(a);
接着看另外一个例子:
function test2() {
var a = 1;
var b = 2;
var c = 3;
}
/*test2中的语句,是这样被执行的 这个时候就把变量提升了
8 function test2(){
var a,b,c;
var a = 1;
var b = 2;
var c = 3;
}
*/
只有函数级作用域,if语句不会有:test3():
function test3(){
var a = 1;
log(a); // 1
if (true) {
var a = 2;
log(a); //2
}
log(a); // 2
}
函数的提升
我们写JS的时候,通常会有两种写法:
- 函数表达式 var fn=function fn(){}
- 函数声明方式 function fn(){}
我们需要重点注意的是,只有函数声明形式才能被提升。
变量赋值并没有被提升,只是声明被提升了。但是,函数的声明有点不一样,函数体也会一同被提升
function test3() {
fn();
function fn() {
log("我来自fn");
}
}
test3();
function test4() {
fn(); // fn is not a function
var fn = function fn() {
alert("我来自 fn test4");
}
}
test4();
函数表达式需要注意的
- 在function内部,fn完全等于fn1
- 在function外面,fn1则是 not defined
function test5() {
var fn = function fn1() {
log(fn === fn1); // true
log(fn == fn1); // true
}
fn();
log(fn === fn1); // fn1 is not defined
log(fn == fn1); // fn1 is not defined
}
test5();
!兼容
// b();
// var a = function b() {alert('this is b')};
// 则ie下是可以执行b的. 说明不同浏览器在处理函数表达式细节上是有差别的.
补充一点函数表达式
定义里面的指定的函数名是不是被提升的
function text7() {
a(); // TypeError "a is not a function"
b();
c(); // TypeError "c is not a function"
d(); // ReferenceError "d is not defined"
var a = function() {}; // a指向匿名函数
function b() {}; // 函数声明
var c = function d() {}; // 命名函数,只有c被提升,d不会被提升。
a();
b();
c();
d(); // ReferenceError "d is not defined"
}
text7();
大家先看下面一段代码test6,思考一下会打印什么?
function text6() {
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
log(a); // ?
}
text6();
||
||
||
|| 输出在下面
||
||
||
||
||
||
what? 什么鬼?为什么是1?
这里需要注意的是,在function b()中,
var = a // function 类型的
a=10; // 重新把10复制给a, 此时的a是function b()中的内部变量
return;
function a() {} // 不会被执行
所以,外面输出的a 依旧是最开始定义的全局变量
函数的声明比变量的声明的优先级要高
function text6() {
function a() {}
var a;
log(a); //打印出a的函数体
var b;
function b() {}
log(b); //打印出b的函数体
// !注意看,一旦变量被赋值后,将会输出变量
var c = 12
function c() {}
log(c); //
function d() {}
var d = 12
log(d); //
}
text6();
变量解析的顺序
一般情况下,会按照最开始说的四种方式依次解析
- 语言内置:
- 形式参数:
- 函数声明:
- 变量声明:
也有例外:
- 内置的名称arguments表现得很奇怪,看起来应该是声明在形参之后,但是却在声明之前。这是说,如果形参里面有arguments,它会比内置的那个优先级高。所以尽可能不要在形参里面使用arguments;
- 在任何地方定义this变量都会出语法错误
- 如果多个形式参数拥有相同的名称,最后的那个优先级高,即便是实际运行的时候它的值是undefined;
CAO!这么多坑,以后肿么写代码?
用var定义变量。对于一个名称,在一个作用域里面永远只有一次var声明。这样就不会遇到作用域和变量提升问题。
ECMAScript参考文档关于作用域和变量提升的部分:
如果变量在函数体类声明,则它是函数作用域。否则,它是全局作用域(作为global的属性)。变量将会在执行进入作用域的时候被创建。块(比如if(){})不会定义新的作用域,只有函数声明和全局性质的代码(单个JS文件)才会创造新的作用域。变量在创建的时候会被初始化为undefined。如果变量声明语句里面带有赋值操作,则赋值操作只有被执行到的时候才会发生,而不是创建的时候。
最后,
由于时间仓促,demo有很多不足之处,多谅解。
关于JS变量提升的一些坑的更多相关文章
- js变量提升的坑
关于js变量提升 变量提升 在js函数内部是可以直接修改全局的变量的,个人感觉是不好的设计, 但是确实存在这个概念 原理: 先查看有没有函数变量bb 查看形参有没有bb 查看全局有没有bb 报错, 找 ...
- js 变量提升+方法提升
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- JS 变量提升与函数提升
JS 变量提升与函数提升 JS变量提升 变量提升是指:使用var声明变量时,JS会将变量提升到所处作用域的顶部.举个简单的例子: 示例1 console.log(foo); // undefined ...
- js变量提升与函数提升的详细过程
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- JS变量提升和作用域
一.JS变量提升 1.当浏览器引擎解析js代码时,将js中的所有一开始就是var声明的和function声明的都提升到全局.此时又叫全局作用域 console.log(aa); console.log ...
- js 变量提升和函数提升原理
关于js的变量,开始的时候我们都会被告知,变量声明应该在引用该变量之前.关于为什么要这样做呢,开始的时候本着会用就行的目的,也没去深究.不过后来经常会发现一些让人很费解的..姑且称为现象吧.先看一段代 ...
- JS 变量提升
var a = 1; function foo() { console.log(a); var a = 2; } foo(); //undefined 根据变量提升机制,最后得出undefined; ...
- js变量提升与函数提升
在es6之前,js语言并没有块级作用域,即{}形成的作用域,只有全局作用域和函数作用域,所谓的提升,即是将该变量的声明或者函数的声明提升,举个例子 console.log(global); //und ...
- js变量提升小记
作为世界上最优美的语言javascript的使用者,呵呵,js的魅力是无穷的,今天来聊聊他的魅(dan)力(teng)之一,变量提升. 每种语言所定义的变量基本都会有一定得作用域,而js的作用域则存在 ...
随机推荐
- 从C#到Objective-C,循序渐进学习苹果开发(5)--利用XCode来进行IOS的程序开发
本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.前面几篇随笔主要介绍C#和O ...
- 使用jquery的append(content)方法的注意事项
append(content)函数:向每个匹配的元素内部追加内容. 如以下示例: 向所有段落中追加一些HTML标记. HTML 代码: <p>I would like to say: &l ...
- 下一代USB接口将支持双向拔插,于明年亮相
近日,USB接口标准制定组织表示新一代USB接口将于明年年中亮相,而其名称目前被暂定为了USB Type-C.该组织表示USB Type-C标准将允许制造商采用更纤薄的接口设计,在实用性大大提高的同时 ...
- Model元数据提供机制小结
在最开始先我得说说我看这部分的情况,最开始被各种ModelMetadata和各种ModelMetadataProvider给搞晕了,就几页书花了我好大的精力去看,直到后来看了一幅类图,细细看各个类之间 ...
- jQuery漂亮图标的垂直导航菜单
效果展示 http://hovertree.com/texiao/nav/3/ jQuery漂亮图标的垂直导航菜单 是一款当鼠标滑过菜单项时,会有一个背景遮罩层跟着鼠标移动,效果非常炫酷,图标还是矢量 ...
- mysql 批量插入数据
MySQL使用INSERT插入多条记录,应该如何操作呢?下面就为您详细介绍MySQL使用INSERT插入多条记录的实现方法,供您参考. 看到这个标题也许大家会问,这有什么好说的,调用多次INSERT语 ...
- 不用插件 让Firefox 支持网页翻译
1.进入http://labs.microsofttranslator.com/bookmarklet/ 2.在语言选择框的下拉列表中选择“简体中文” 3.右键点击“翻译”按钮,选择“将此链接加为书签 ...
- 2005年IT行业趋势Top10
未来三年内对组织有潜在的重大影响IT趋势.这里的IT趋势的摘要: 1. 计算位于任何地方 智能手机,平板,电视盒,可穿戴设备,可连接的屏幕,对于适应移动用户所求要的整体环境的需求在不断增强.这会继续提 ...
- 高效 Java Web 开发框架 JessMA v3.3.1 Beta-1 发布
JessMA(原名:Portal-Basic)是一套功能完备的高性能 Full-Stack Web 应用开发框架,内置可扩展的 MVC Web 基础架构和 DAO 数据库访问组件(内部已提供了 Hib ...
- Android应用开发基础之十:多媒体编程
多媒体概念 文字.图片.音频.视频 计算机图片大小的计算 图片大小 = 图片的总像素 * 每个像素占用的大小 单色图:每个像素占用1/8个字节 16色图:每个像素占用1/2个字节 256色图:每个像素 ...