1 JavaScript 简称JS,是一种动态的弱类型脚本解释型语言,和HTML,CSS并成为三大WEB核心技术,获得了几乎全部主流浏览器的支持 node
1994年,网景Netscape公司成立并发布了Netscape navigator浏览器,占据了很大的时长份额,网景意识到WEB须要动态,须要一种技术来实现
1995年9月网景浏览器2发布测试版本发布了livescript,随即在12月的测试版就改名为JavaScript,同时期,微软推出IE并支持JScript,VBScript。
1997年,网景,微软,SUN,borland公司和其余组织在ECMA肯定了ECMAscript语言标准,JS则是ECMAscript的标准实现之一。python
因为IE的捆绑销售行为,网景的单一浏览器时长萎缩,从1990年的90%降低到2006年的1%,1999年网景被AOL收购,收购不就,netspace公开了浏览器代码,并建立了Mozilla组织,Mozilla组织使用Gelo引擎重写浏览器,固然Mozilla将Geko引擎发布了Firefox浏览器
2003年5月,网景被解散
AOL于2007年宣布中止支持Netscape浏览器 正则表达式
HTTP cookie ,解决HTTP无状态
JavaScript
ssl协议
jar 格式文件,将Java的class文件打包,并加上签名
2012年4月9日,微软以10亿5千6百万购买800向美国在线的专利或专利受权,并收购了SSL,cookie等专利。express
ES,ECMAScript是由ECMA国际(前身为欧洲计算机制造协会,英文名称是European Computer Manufactures Association)经过ECMA-262标准化的脚本程序设计语言,该语言被普遍应用于互联网npm
JavaScript是商品名,目前商标权在Oracle公司手中,ES是标准名。数组
根据ES标准,有不少实现引擎,其中包括JavaScript或JScript,他们都是ECMA-262标准的实现和扩展。浏览器
1997年,制定了首个ECMA-262服务器
1999年12月,EC3,支持更强大的正则表达式cookie
ES4 太过激进,最终被放弃并发
2009年,ES5发布,获得普遍支持,支持严格模式,支持Json
2015年,ES6发布,引入很是多的新的语言特性,还兼容旧版本的特性,ES6以前按照版本号命名,从ES6开始使用年份做为版本号,ES6 及ECMAscript 2015.
运行HTML,CSS,JS技术都在发展,标准版本不少,浏览器内嵌的引擎实现不太一致,甚至有不按照标准实现,或者减小实现,或者改变实现,或者增长的功能,如IE,就致使了开发人员负担,很难作到一套代码能够兼容的跑在多种浏览器中,甚至不能跑在同一种浏览器的不一样版本中。
就在浏览器IE一家独大时,Firefox和Chrome开始变强
2008年9月2日,Google的Chrome浏览器发布,一并发布的js引擎,就是V8引擎,V8使用BSD协议开源
V8引擎支持C++开发,将JavaScript编译成了机器码,而不是字节码,仍是用不少优化方式提升性能,所以,V8引擎速度很快。
V8 引擎还能够独立运行,能够嵌入到其余任何C++程序中。
V8 引擎的诞生,使得服务器端运行JS称为了方便的事情。
nodejs是服务器端运行JavaScript的开源的,跨平台的运行环境
nodejs原始做者瑞安达尔于2009年发布,使用了V8引擎,并采用事件驱动,非阻塞异步IO模型
2010年,npm软件包管理器诞生,经过它,能够方便的发布,分析nodejs的库和源代码。
nodejs4.0引入了ES6的语言特性。
须要安装nodejs和visual studio code
相关下载nodejs
https://npm.taobao.org/mirrors/node/v12.10.0/node-v12.10.0-x64.msi
visual studio code
插件NodeExec和汉化包安装
从新启动软件便可生效,
和C 、Java同样
//单行注释
/*注释*/多行注释,也可使用在语句中
注: 使用快捷键F8运行代码,其代码必须是已经保存的文件,不能是空,F8可能和有道词典快捷键冲突,建议在此运行期间不运行有道词典。
1 标识符
标识符必须是字母,下滑线,美圆符号和数字,但必须是字母,下划线,美圆符号开头,依然不能是数字开头
标识符区分大小写
2 标识符的声明
var 声明一个变量
let 声明一个块做用域中的局部变量
const 声明一个常量JS中的变量声明和初始化时能够分开的
常量的存放位置和变量是不在一块儿的
console.log(a) // 后面声明的变量,前面可使用,但没意义 var a //只是声明,并未赋值,其类型是undefined, let b //声明为块变量 console.log(1,a,b) //打印 a=1 //变量赋值,不规范化操做,不推荐,在严格模式下回致使异常。在赋值以前不能引用,由于未为进行声明,其赋值的结果是全局做用域 b='123' console.log(2,a,b) const c=100 //定义常量 console.log(c) var d=10 //规范声明并初始化 console.log(3,d) c=200 //修改常量值,不可修改,由于其是常量 console.log(4,c)
结果以下
常量和变量的选择
若是明确知道一个标识符定之后便再也不改变,应该尽可能声明成const常量,减小被修改的风险,减小bug。
function test(){ var x=10; //声明并初始化x y=20; //声明vi可以初始化y console.log(x,y) } test() console.log(x,y) //此处在函数中,其全部参数皆不能冲破做用域 // x=100 // console.log(x)
结果以下
函数自己天生就是一个做用域
其实就是将声明定义到最前面罢了,及就是先调用,再定义
console.log(a) console.log(b) console.log(c) console.log(d) console.log(e) var a=200; // 提高做用域,只有var定义变量的方式能够提高做用域 var b; const c=300; //此处不能提高做用域 let d; e=300;
结果以下
序号 | 名称 | 说明 |
---|---|---|
1 | number | 数值型,包括整数类型和浮点型 |
2 | boolean | 布尔型,true和false |
3 | string | 字符串 |
4 | null | 只有一个值null |
5 | undefined | 变量声明未赋值的,对象未定义的属性 |
6 | symbol | ES6新引入的类型 |
7 | object类型 | 是以上基本类型的复合类型,是容器 |
ES是动态语言,弱类型语言
虽然先声明了变量,可是变量能够从新赋值成任何类型
console.log(a=1+'test',typeof(a)) // typeof:打印类型 console.log(a=false+'test',typeof(a)) //和布尔类型运算 console.log(a=null+'test',typeof(a)) //和null比较 console.log(a=true+'test',typeof(a)) console.log(a=undefined+'test',typeof(a)) //和数字
结果以下
console.log(a=1+false,typeof(a)) console.log(a=1+true,typeof(a)) console.log(a=1+null,typeof(a)) console.log(a=1+undefined,typeof(a))
结果以下
console.log(a=false+undefined,typeof(a)) console.log(a=true+undefined,typeof(a)) console.log(a=false+null,typeof(a)) console.log(a=true+null,typeof(a)) console.log(a=true & '',typeof(a)) //位运算 console.log(a=undefined && true,typeof(a)) //与运算
True是透明的,false则直接就是短路,返回直接就是false,类型是布尔。true主要是看后面的状况
console.log(a=false && null,typeof(a)) //若是前面是false,则返回结果是false,且类型是布尔类型 console.log(a=false && 'zhangbing',typeof(a)) console.log(a=true && '32534534',typeof(a)) //若是前面是true,则之后面为准 console.log(a=true && '' ,typeof(a))
弱类型,不须要强制转换
NaN,Not a Number,转换数字失败
遇到字符串,加括号就是拼接字符串,全部非字符串隐式转换为字符串
若是没有字符串,加号把其余全部类型都当数字处理,非数字类型隐式转换成数字,undefined特殊,由于它都没有定义值,全部其是一个特殊的数字Nan。
若是运算符是逻辑运算符,短路符,则返回就是短路时的类型,没有隐式转换
除非你十分明确,不然不要依赖隐式类型转换,写代码时,每每为了程序的健壮性,建议显式转换
将一个值一单引号或双引号引用后便造成了字符串
let a="a\"aaaaaa" // 可以使用转义符号 let b='adadsaasd' //单引号定义 let c="asfsdfsadfsdf'sdfsdfsdfsdf'" //混合定义 let d=`'abcd'` //反引号定义 let e=`x= ${a} y=${b}` //插值,相似于Java中的替换和python中的format console.log(a,b,c,d) console.log(e)
结果以下
字符 | 说明 |
---|---|
\0 | Null 字节 |
\b | 退格符 |
\f | 换页符 |
\n | 换行符 |
\r | 回车符 |
\t | Tab(制表符) |
\v | 垂直制表符 |
' | 单引号 |
" | 双引号 |
|反斜杠字符() | |
\XXX | 由从0到377最多三个八进制数XXX表示的Latin-1字符 |
\xXX | 由从00和FF的两位十六进制数字XX表示的Latin-1字符 |
\uXXXX | 由4位十六进制数字XXXX表示的Unicode字符,例如,\u00A9是版权符号的Unicode序列,见Unicode escape sequence |
\u{xxxxxx} | Unicode代码点(code point)转义字符 |
支持索引,切片,查询,替换和连接
console.log('adasddasdasd'.indexOf(1)) //查找位置,若不存在,则返回-1 console.log('abced'.indexOf('c')) //获取对应位置 console.log('12345'.charAt(4)) //索引获取元素 console.log('1234'.concat('666')) // 元素追加 const a='123456' //定义一个常量 console.log(a[3]) //经过索引获取元素 console.log(a.toUpperCase()) //大写转换 console.log(a.slice(1,3)) //切片,左闭右开 1,2处的元素 console.log(a.slice(-3,-1)) //45 const url=' www.baidu.com ' console.log(url.split('.')) //字符串分割 console.log(url.startsWith('www')) //匹配字符串起始,返回false或true console.log(url.substr(3,6)) //从索引为3开始6个字符 console.log(url.substr(3,6)) //从索引为3开始到索引为6结束 console.log(url.replace('com','edu')) //字符串一替换 console.log(url.trim()) //取出两边的空白字符
进制符 | 描述 |
---|---|
0bxxx/0Bxxx | 二进制 |
0oxxx | 八进制 |
0xxxx | 十六进制 |
在JS中,数据均为双精度浮点型范围只能在-(2^53-1)和2^53-1之间,整数类型也不例外,数字类型还有三种符号值:+Infinity(正无穷),-Infinity(负无穷)和Nan(not-a-number非数字)
二进制0b0010,0B100.
八进制0755,注意0855,将被认做是十进制,由于8不在八进制中,ES6中最好使用0o 前缀表示八进制
十六进制0xAA,0xff
指数表示1E3(1000),2e-2(0.02)
常量属性
var biggestNum=Number.MAX_VALUE; //最大值 var smallestNum=Number.MIN_VALUE; //最小的大于0的数 var infiniteNum=Number.POSITIVE_INFINITY; var negInfiniteNum=Number.NEGATIVE_INFINITY; var notANum=Number.NaN;
数字方法
方法 | 描述 |
---|---|
Number.paraseFloat() | 把字符串参数解析成浮点数,和全局方法parseFloat()做用同样 |
Number.parseLnt() | 把字符串解析成特定基数对应的整数类型数字,和全局方法parseInt()做用一致 |
Number.isFinite() | 判断传递的值是否为有限数字 |
Number.isInteger() | 判断传递的值是否为整数 |
Number.isNaN() | 判断传递的值是不是NaN |
内置数学对象Math
Math提供了绝对值,对数指数运算,三角函数运算,最大值,最小值,随机数,开方等运算函数,提供了P|值
console.log(typeof(parseInt('1234123423423')),'134234') //转换为数值类型 console.log(isNaN(10)) //判断是否为NaN console.log(isFinite(10/3)) console.log(Math.abs(-1)) //绝对值 console.log(Math.random()*1000) //生成随机数
符号 | 描述 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 余 |
++i | 单目运算符先加后赋值 |
i++ | 单目运算符先赋值后加 |
--i | 单目运算符先减后赋值 |
i-- | 单目运算符先赋值后减 |
单目运算符,自增和自减只针对一个参数的运算符
++ 和 --
i++ 表示先用,后加,其加的值为1
++i 表示先加,后用,其加的值也是1
总之,谁在左,谁先执行
反之--也是亦然。
let i=0; a=i++ //此处是先用后加,所以其a的值应该是0,以后加1 console.log(a) b=++i; //此处是先加后用,此处的b的值应该是i为1的基础是加1,及为2 console.log(b) c=i++; //此处是先用,及c为2 console.log(c)
结果以下
其中单目运算符的优先级高于双目运算符。
相关习题
let i=0; a=(++i+i+++i+++i) //其中单目优先级高,则可拆解为 ++i + i++ + i++ +i //++i结果为1 ,i++结果i为1 i++ 结果i为2 i的结果为3 最终为1+1+2+3=7 console.log(a)
结果以下
此题主要考虑两个点
1 单目运算符优先级高于双目运算符
2 加号+是双目运算符,两边的表达式必须先计算好
符号 | 描述 |
---|---|
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
!= | 不等于,宽松模式进行类型转换 |
== | 宽松模式等于,及就是进行类型转换 |
!== | 严格模式不等于,及不进行类型转换 |
=== | 恒等,及全等,不进行类型转换 |
console.log('1'==1) //此处为宽松模式,进行类型转换,此处为true console.log('1'===1) //此处为严格模式,此处返回为False console.log('200'>300) //此处为true,进行了类型转换 console.log('2a'<200) //此处为false,此处的2a是不能转换为数字的,所以不能参与比较,所以其返回值为false console.log(Number.MAX_VALUE>10000) //和最大比较,返回为true console.log(Number.MIN_VALUE < 0.00001) //和最小比较,范围为true console.log(Number.MAX_VALUE>Number.MIN_VALUE) //最大和最小比较,返回为true
结果以下
Column 1 | Column 2 |
---|---|
&& | 逻辑与 |
|| | 逻辑或 |
! | 逻辑非 |
这些运算符和其余高级语言相同。支持短路。
方法 | 描述 |
---|---|
& | 位与 |
| | 位或 |
^ | 异或 |
~ | 取反 |
<< | 左移 |
>> | 右移 |
条件表达式?真值:假值,邓建与简单的if ...else 结构
console.log(('3'>30)?'真':'假') console.log((4<5)?'假':'真')
JS 运行多个表达式写在一块儿的状况
console.log(a,b,c) var a=100,b=200,c=300 //提高做用域,会定义三个元素
结果以下
详情见 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
名称 | 说明 |
---|---|
Instanceof | 判断是否属于指定类型 |
typeof | 返回类型字符串 |
delete | delete操做符,删除一个对象(an object)或者一个对象的属性(an object's property) 或者一个数组中的某一个键值(an element at a specified index in an array)。 |
in | 若是指定的属性在对象内,则返回true |
instanceof 要求必须明确使用类型定义变量,就是对象必须是new关键字声明建立的,它能够用于继承关系的判断
typeof 就是返回对象的类型字符串
delete删除对象,属性,数组元素
a=new String('abcd') b=new Number(123) console.log(a instanceof String) console.log(b instanceof Number) console.log(typeof(a)) console.log(typeof(b)) console.log(typeof(100)) console.log('--------------delete-----------') x=42 var y=43 let z=60 myobj=new Number(); myobj.h=4 //增长属性 console.log(delete x); //隐式声明使用delete可以删除成功 console.log(delete y); //var声明的不能删除 console.log(delete z); //let声明的依然不能删除 console.log(delete myobj.PI) //不能删除预约义的对象, console.log(delete myobj.h) // 自定义的属性变量是能够删除的 console.log(delete myobj) //自定义的对象能够删除,由于其是隐式声明,所以能够删除 console.log('+++++++++++++++++++') var trees = new Array('redwoord','bay','cendar','cak','maple') for (var i=0;i<trees.length;i++) console.log(trees[i]) console.log('====================') delete trees[3];//删除其中的元素,其数组不会少,只会在当前索引对应的数据变为undefined for (var i=0;i<trees.length;i++) console.log(trees[i]) console.log('-------------object----------------') let mycar ={ make:'Honda', model:'Accord',year: 2019 }; console.log('make' in mycar); //true console.log('model' in mycar); //true
结果以下
if (cond1) { } else if (cond2) { } else if (cond3) { } else { }
条件为false的等效
false
undefined
null
0
NaN
空字符串其余的将均被视为True,如空列表。
if ([]) { let d=4;//定义为块变量,其不能穿透if var e=5; //var 定义,可以穿透if f=6; //定义,可以穿透 if (true) { console.log(d); console.log(e); console.log(f); g=10; var h=11; let t=13;//定义为块变量,其不能穿透if } } console.log(h,g,f) console.log(t)
结果以下
switch (expression) { case label_1: statements_1 [break;] case label_2: statements_2 [break;] ... default: statements_def [break;] }
let a=3 switch (a) { case 1: console.log(1) break; case 2: console.log(2) break; case 3: console.log(3) break; default: console.log(4) break; }
结果以下
switch的穿透效果,直到遇见break为止。
let a=3 switch (a) { case 1: console.log(1) case 2: console.log(2) case 3: console.log(3) default: console.log(4) }
结果以下
//C风格for循环
for ([initialExpression];[condition];[incrementExpression]) { statement }
arr=[10,20,30] for (let x=0;x<arr.length;x++){ console.log('i',arr[x]) } console.log('+++++++++++++++++') for (let j=0;j<arr.length;j++,j++) { //注意,此处是逗号(i++,i++) console.log('j',arr[j]) } // for (z=0;z<arr.length;) { // 此处是死循环,由于没有增长条件 // console.log(arr[z]) // } for (let a=0,b=200;a<arr.length;a++,b++) { // 多条件操做 console.log(a,arr[a],b); } for ( let z in arr) { //此处获取到的是索引 console.log(z,arr[z]) } for (let w of arr) { //此处获取到的是值 console.log(w) } let obj={'a':1,'b':2,'c':3} for (let x in obj) { //使用for循环处理对key的访问 console.log('obj',x) } // for (let y of obj) { //此处不能实现,由于其不能迭代对象 // console.log(y) // }
结果以下
注意:for in 循环返回的是索引或者key,须要间接访问到值。
数组反正返回的是索引,C风格for循环操做较为便利
对象使用for in 能够遍历其key,但不能使用for of 迭代对象,缘由是of后面必须是一个迭代器,可类比python中的for in。
while 循环通常适用于死循环,while循环是先判断,do...while循环是先执行,后判断。
while (condition){ statement }
do { statement } while(condition)
先进入循环,而后判断,为真就继续循环
let x=10; while (x--){ console.log(x) }
结果以下
let x=10; do { console.log(x) }while(x--)
结果以下
break 结束当前循环,直接退出这个循环体
continue 中断当前循环,直接进入下一次循环,同一个循环中的某一个跳过练习
打印9*9乘法口诀
for (i=1;i<10;i++) { line=" " for (j=1;j<=i;j++){ line += `${j}*${i} = ${i*j} ` if (i==j) console.log(line); } }
函数: 函数也是对象
格式以下
function 函数名(参数列表) { 函数体; return 返回值; }
示例以下
function add(x,y){ return x+y; } console.log(add(4,5))
结果以下
使用表达式来定义函数,表达式中的函数名能够省略,若是这个函数名不省略,也只能用于该函数的内部。
const add =function _add(x,y) { return x+y; } console.log(_add(4,5))
结果以下
const add =function _add(x) { if (x==1){ return x; } return _add(x-1)+x //递归调用,该函数只能在其内部被调用 } console.log(add(10))
结果以下
const add =function (x,y) { //匿名函数 return x+y; } console.log(add(4,5))
console.log(show) function show(){ //函数能够提高做用域 console.log('show') } console.log(add) var add=function(){ //函数表达式则不能提高做用域 return 1; }
结果以下
函数,匿名函数,函数表达式的差别
函数和匿名函数,本质上都是同样的,都是函数对象,只不过函数有本身的标识符--函数名。匿名函数须要借助其余标识符而已。
区别在于,函数会声明提高,函数表达式不会。
高阶函数:参数为函数或返回值为函数的函数称为高阶函数
function a(){ console.log('a') return function b(){ console.log('b') return 'b' //函数必须有返回值,不然,返回为undefined } } console.log(a()) //调用外层函数 console.log(a()()) //因为a返回值函数,所以可使用括号来进行相关的调用操做
结果以下
let counter=function() { let i=0; function _fun(){ return ++i; } return _fun } c=counter() console.log(c()) console.log(c()) console.log(c()) console.log(c())
结果以下
实现map函数的功能,传入一个函数,传入一个值,输出一个值处理后的状况,如输入1,2,3,4,输出为1 4 9 16 及平方
const map1= function (fn,arr){ newarry=[]; for (i in arr){ newarry[i]=fn(arr[i]); } return newarry; } const sq = function(x){ return x*x; } console.log(map1(sq,[1,2,3,4]))
箭头函数就是匿名函数,它是一种更加精简的格式
箭头函数参数
若是一个函数没有参数,则使用()
若是只有一个参数,参数列表能够省略小括号
多个参数不能省略小括号,且使用逗号间隔
箭头函数返回值
若是函数体部分有多行,就须要使用{},若是有返回值则使用return。
若是只有一行语句,能够同时省略大括号和return
只有一条return语句,不能省略大括号,有return必须有大括号
若是只有一条非return语句,加上大括号,函数无返回值
将上述实例中的函数修改成箭头函数
const map1= (fn,arr) => { newarry=[]; for (i in arr){ newarry[i]=fn(arr[i]); } return newarry; } const sq = (x) => x*x; console.log(map1(sq,[1,2,3,4]))
结果以下
const map1= (fn,arr) => { newarry=[]; for (i in arr){ newarry[i]=fn(arr[i]); } return newarry; } let new1 = map1((function (x) {return x*x}),[1,2,3,4]) //函数 let new2=map1((x)=> {return x*x},[1,2,3,4] ) //去除function ,将后面的变为(x) => {return x}形式 let new3 =map1((x)=> x*x,[1,2,3,4]) //若只有一个返回值,则能够省略{},但{} 和return是同时存在,所以能够写成以下 let new4 =map1( x => x*x,[1,2,3,4]) //若是只有一个参数,则能够省略() console.log(new1) console.log(new2) console.log(new3) console.log(new4)
结果以下
const add = (x,y) => x+y; console.log('add',add(4,5)) const add1 = (x,y=5) => x+y; //支持默认参数 console.log('add1',add1(4)) const add2 = (x=6,y) => x+y; console.log('add2',add2(1)) //此处默认会将x=6代替为x=1,而y的值为undefined其传入的值为add2(1,undefined) console.log('add2',add2(1,10)) console.log('add2',add2(y=10,z=20)) //此处的结果为30,其不关心形式参数,此处为add2(10,20) console.log('add2',add2(a=1000,b=3000,c=4000)) //多传递参数没错,只匹配前面的
结果以下
JS 基本参数总结
1 JS 中并无python中的关键字传参
2 JS 只是再作参数位置的对应
3 JS 并不限制默认参数的位置
4 JS 多传递参数没影响,其只是作位置的匹配操做
const add = (...args) => { // 可变参数 ,默认结果为列表 result=0; console.log(args); for (let x in args) { result += args[x]; } return result; } console.log(add(1,2,3,4,5))
和python 相似,JS提供了参数解构,依然使用了...符号来解构。
const add =(...args) => { console.log(args) } add(1,2,3,4) l1=[1,2,3,4] add(l1) //参数解构 console.log(...l1) add(...l1)
结果以下
函数的全部参数都会被保存在一个arguments的键值对字典对象中。
(function (p1,...args) { console.log(p1); console.log(args); console.log('---------------'); console.log(arguments,typeof(arguments)); for (let x of arguments) console.log(x); })('abcd',1,2,3,4,5) //此处是调用操做
结果以下
全局对象
console.log(arguments)
结果以下
在函数外,其指的是全局的,在函数内,其是函数中的参数
基本表达式和python差很少
function * inc(){ //使用* 来定义生成器 let i=0; while (1) yield (++i); } g=inc() //实例化生成器 console.log(g.next().value,g.next()) //执行生成器调用 console.log(g.next().value) console.log(g.next().value) console.log(g.next().value,g.next())
结果以下
每次调用next()方法返回一个对象,这个对象包含两个属性: value和done,value属性表示本次yield表达式的返回值,done属性为布尔值,done是false表示后续还有yield语句执行,若是执行完成或者return后,none为true。
function * inc(){ let i=0; while (true) { yield ++i; if (i>3) return i; } } g= inc() console.log(g.next()) console.log(g.next()) console.log(g.next()) console.log(g.next()) console.log(g.next())
结果以下
JS 使用大括号构成语句块
ES6 以前语句块是没有做用域的,从ES6开始支持块做用域,let只能在块做用域中可见。
function hello(){ let a=1; var b=2; c=3 } let d=100 if (1) { let d=4; //局部和下一级有效,除非被覆盖掉 var e=5 f=6 if (true) { console.log(d) console.log(e) console.log(f) console.log('____________________') g=10 //只要不是函数,都没问题 var h=11 //只要是函数,都没问题 } } //console.log(a) //不可见 //console.log(b) //不可见 //console.log(c) //不可见 console.log(d) //不可见 let 突破不了块做用域,但外界共享 console.log(e) //var可见 console.log(f) //隐式声明,可见 console.log(g) //可见 console.log(h) //可见
结果以下
块做用域只对let有效,对var和隐式声明等特性无效 函数中var 和 let 都突破不了 块做用域向下是穿透的,除非覆盖问题