前言:
因为我目前是一名大二学生,因此可能有些内容是站在学生角度理解的,因此如有不当,还请各位前辈指点。
写此文是想梳理一下JS的知识,以及一些易混淆的内容,顺便进行回顾,因为确实有一段时间没真正地在JS上花精力了,同时我也将我的JS经历写在了文章最后。
文章目录
- 0.JS的Debug
- 1.数据类型具体取值+Undefined+Null
- 2.===与NaN问题
- 3.浮点数底层误差问题
- 4.同一数组可存不同类型
- 5.严格检查模式
- 6.转义符 \ 的另一种用途
- 7.随机数Math.random()取值问题
- 8.全局变量与局部变量
- 9.多行字符串与模板字符串
- 10.slice()与substring()
- 11.Number(),parseInt()和parseFloat()汇总
- 12.forEach()函数
- 13.闭包
0.JS的Debug
浏览器中自带原生的JS Debug功能,非常方便
1.数据类型具体取值+Undefined+Null
【基本数据类型】:
- 数字(Number)
(1)整数:123
(2)浮点数:123.1
(3)科学计数法1.123e3
(4)负数:-99
(5)NaN:不是一个数(但本身归属于数字类型)
(6)Infinity:无穷大的结果 - 字符串(String)
(1)单引号:‘abc’
(2)双引号:“abc” - 布尔值(Boolean)
(1)true
(2)false - 未定义值(Undefined)
- 空值(Null)
【引用数据类型】:
对象:(注:JS中所有事物都是对象,此处分类是按引用型数据类型进行分类后的对象,可理解为对象的子集)
- 字符串对象(String)
- 数组对象(Array)
- 日期对象(Date)
- 数值对象(Math)
2.===与NaN问题
1.尽量不要使用==比较,因为==只比较值,不要求类型一致,判断相等,尽量用===
2.NaN与任何数都不相等,包括它与自己
3.只能通过 isNaN() 的方式,判断某变量结果是否为NaN
3.浮点数底层误差问题
(1/3) 不等于(1 - 2/3)
此问题涉及计算机底层硬件中,运算器的三个寄存器(现代计算机可能已不是三个了),ACC累加器、MQ乘商寄存器、X操作数寄存器,它们与算术逻辑单元共同完成运算。对于浮点数,它们的计算都是有限精度,无法达到绝对精度,存储器和寄存器内部能存的精度都是有限的,因此导致上述问题。(注:这里如果解释的不当,还请前辈指正)同样,相似的精度问题例子还有:sinx,它在计算机底层是这样得出的结果:
计算机也不能直接求解开放x:
那该如何比较上述类似结果的浮点数呢?
可用显示容许误差法:允许一定范围的误差
4.同一数组可存不同类型
1.JS中同一数组可存不同类型:
2.为保证可读性,数组尽量用[ ](少用new Array()),而对象尽量用{ }3.取数组下标溢出时,结果为undefined,(在对象操作中,也是如此,访问对象不存在的属性时,结果也为undefined)
5.严格检查模式
在<script>标签内的第一行,加上’use strict’,从而开启严格检查,严格检查可以预防因JavaScript的随意性而导致产生的一些问题
(注:如果’use strict’本身标了红色波浪线,那么需要设置IDEA支持ES6的语法)
图中,a标红,鼠标悬浮上去也会提示错误信息
同时在console中报错
删去后,a不再标红
6.转义符 \ 的另一种用途
平时也可在浏览器的Console中,随手测试不熟练的Unicode和ASCII。
7.随机数Math.random()取值问题
- Math.random():[0, 1)
- Math.random()*m:[0, m)
- Math.random()*m+n:[n, m+n)
- Math.random()*m-n:[-n, m-n)
- Math.random()*m-m:[-m, 0)
8.全局变量与局部变量
全局变量:有两种表示方法:
1.在函数外定义的变量(必须用var关键字定义才可,let与const则仍是局部变量,只不过是作用域较大的局部变量,这个结论可以利用全局变量一定属于window对象这个特性测试出来);
2.在函数内但没有使用 var 关键字声明的变量。
表示法1例子:
表示法2例子:
注:1)全局变量有全局作用域: 网页中所有脚本和函数均可使用。
2)全局变量在 HTML 中都属于window对象。
3)全局变量可以覆盖 window 对象的变量或者函数。
局部变量:在函数内使用 var 关键字或 let 关键字声明的变量。(在ES6中,用let关键字定义局部变量)
例子:
9.多行字符串与模板字符串
都是利用符号:` `
多行字符串:
模板字符串:
而且,JS中的字符串与Java中的字符串一样都是不可变的,测试如下:
10.slice()与substring()
slice(start, end) :[start, end)
substring(from, to):[start, end)
但不同的是,slice()可支持参数取负数,如-1表示最后一个下标
11.Number(),parseInt()和parseFloat()汇总
12.forEach()函数
将数组中的每个元素映射给forEach()函数中的参数函数,逐一调用。
(我在大二上学期做游戏开发的时候,正是用的这个函数,首先用一个数组接收用户输入的方向键,例如单纯的正上向,或者是复合的左上方向,把键码用数组收容,并用forEach函数不断遍历存方向键的数组中的每个元素传入这个函数的参数函数,从而进一步完成模型位置的更新)
13.闭包
(这里放一个菜鸟教程里的经典例子)
但我认为这样会更好理解(这是菜鸟教程上一个大佬的评论):
因为闭包会持有父方法的局部变量并且不会随父方法销毁而销毁, 所以这个counter其实就是来自于第一次function执行时创建的变量,这个function自运行一遍之后,其实最后赋值给add的是return counter += 1 这段代码。
所以后面每次调用add() 其实都是在调用return counter += 1
变量 add 指定了函数自我调用的返回字值。
自我调用函数只执行一次。设置计数器为 0。并返回函数表达式。
add变量可以作为一个函数使用。非常棒的部分是它可以访问函数上一层作用域的计数器。
这个叫作 JavaScript 闭包。它使得函数拥有私有变量变成可能。
计数器受匿名函数的作用域保护,只能通过 add 方法修改。
闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。
因为闭包会持有父方法的局部变量并且不会随父方法销毁而销毁,所以直观的说就是形成一个不销毁的栈环境。
以下是个人回忆,和本文正文没什么直接关系,大家可以忽略,我在大学的学习经历比较丰富,涉猎了很多的方向,以下是JS方面的部分经历,很想等以后能写个完整的大学技术经历回忆录hhh。
我的JS经历:
(1)在大一时学完H5与C3后,自学了JS,在网上挑选了十几个网页中局部区域的优秀JS效果,做了一次整合。
(2)大二上学期初,开了JS课,一星期内(自学php,ajax+构思+编码,现在回想…主要当时赶时间不然还能做的更好)原创独立(其实我还带了三个女生,她们只负责差不多10%的工作量,主要是负责给我加油hhh,)开发了一个全栈项目,类似一个论坛或社区,发帖子,收藏管理,个人帖子管理,账户管理等功能都做全了,其中对JS的应用也算是有了实践性的了解。
(3)大二上学期末,因为JS课和计算机图形学课都有课程设计,而我担心两个都做的话分散精力,于是在网上找到了这两种技术的结合体Three.js,这算是一个OpenGL与JS的结合库,这个库国内的交流很少,很多问题都搜不到,于是我一边在仅有的资源下学习,一边又去看Github上学习别人的项目(资源其实也是少的可怜),最后硬是做出了一个3D游戏,关于Three.js我在之前写过一篇文章
经历了这次Three.js游戏开发后,有算是进一步了解了JS的另一个领域
(4)这次的文章,则是我在学习JavaWeb后,又再此回过头来,学了一遍JS,于是有了这个JS专栏。