计算机编程基础
- 计算机语言,总的来说分为三类:机器语言、汇编语言、高级语言。
- 标记语言(HTML)被读取的,编程语言有逻辑&行为能力。
JavaScript&基础使用
- JS 是运行在客户端的脚本语言(Script:脚本;所谓“脚本语言”(script language),指的是它不具备开发操作系统的能力,而是只用来编写控制其他大型应用程序(比如浏览器)的“脚本”;脚本语言不需要编译;由js解释器解释&执行;也可以基于node.js做服务器端的编程;
- JavaScript 也是一种嵌入式(embedded)语言
- 渲染引擎(内核),解析HTML和CSS;
- JS引擎,解释JS代码
- ECMAScript(规定JS的编程语法和基础核心知识)+DOM(文档对象模型)+BOM(浏览器对象模型)
- 常用输入输出语句
变量
:存放数据的容器;声明: var 变量名;赋值;初始化。
备注:
- 赋值和输入可以直接结合。将输入内容赋值给某变量。
- 在console.log(),每条指令的结果都会被输出一下。如有错误,下面的 内容也不再执行。
- 不声明直接赋值( XX= QQQ),会将该变量XX变为全局变量。
- 命名规范:严格区分大小写。驼峰命名:myFirstName
数据类型
:把数据分成所需内存大小不同的数据,充分利用存储空间;JS是弱类型、动态语言。
备注:
- JS的变量数据类型是在程序运行过程中,根据赋的值确定的。不需要提前申明,使用中也可以改变。
- 八进制:数字前0开头,前导0后面有数字8和9,则该数值被视为十进制;所以现在一般:八进制:有前缀0o或0O的数值,或者有前导0、且只用到0-7的八个阿拉伯数字的数值。
- 十六进制: 0x开头 显示为蓝色
- 小数点前的数字多于21位 或 小数点后的零多于5个 时,JavaScript 会自动将数值转为科学计数法表示。
- +0和-0 ,一般情况下都等价,唯一区别的场合:+0或-0当作分母,返回的值是不相等的,分别为+Infinity ,-Infinity(不会报错)。
- isFinite方法返回一个布尔值,表示某个值是否为正常的数值。
- isNaN():判断是否为非数字。使用isNaN之前,最好判断一下数据类型。它只对数值有效。
- NaN,一个特殊数值,属于Number,它不等于任何值,包括它本身;和其他数比大小也不行。
- 0乘以Infinity,返回NaN;0除以Infinity,返回0;Infinity除以0,返回Infinity。
- Infinity加上或乘以Infinity,返回的还是Infinity。Infinity加上或乘以Infinity,返回的还是Infinity。
- 字符串类型:推荐使用单引号,有就近原则,所以嵌套时:外单内双 显示为黑色;字符串内部的单个字符无法改变和增删。但可以查找
- 转义字符 用 ** 开头,换行 \n
- 字符串+任意类型 = 字符串;在 **‘ ’**之外拼接变量 “引引加加”
- undefined 未定义类型。undefined+字符串 = undefined字符串 ; undefined+数字 = NaN ;相当于NaN;
- null 空值 null+字符串 = null字符串; unll+数字 =数字;是Object类型 相当于0 ;
- typeof 输出变量类型。未定义变量使用typeof判断 可以不报错而返回 “undefined”(此特性可用于判断语句)
- Instanceof 可区分 数组和对象 instance(实例)
- 数据类型转换。
- 转换为字符串。1、变量.toString 、2、 String(变量)3、变量+‘’(空字符串)【隐式转换&重点使用】
- 转换为数字型。1、parseInt(‘数值’,进制)、parseFloat(‘’) 2、Number(变量)3、算数运算(- * /) 【隐式转换】比如 *1
- 对象是最复杂的数据类型,又可以分成三个子类型:狭义的对象(object、数组(array)、函数(function)
- 空数组([])和空对象({})对应的布尔值,都是true。
- 数值正向溢出时,返回infinity;负向溢出时,返回0。
- 对象 属性的读取:1、点运算符读取(常用于英文开头的属性);2、方括号运算符读取(*数值键名只能用方括号读取,不用加引号;英文键名要加引号
- 查看一个对象本身的所有属性,可以使用Object.keys方法。
- 删除delete 一个不存在的属性,delete不报错,而且返回true;只有一种情况,delete命令会返回false,那就是该属性存在,且不得删除;delete命令只能删除对象本身的属性,无法删除继承的属性
- in 运算符:属性是否存在(包括自身&继承的属性);hasOwnProperty方法 判断是否为自己的属性。
- for…in 循环 遍历对象的全部属性(包括 自身&继承 可遍历 的属性);只想遍历对象自身的属性时,使用for…in的时候,应该结合使用hasOwnProperty方法,在循环内部判断一下。
- with语句 操作同一个对象的多个属性时,提供一些书写的方便。
with区块内部有变量的赋值操作,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量 。
with区块没有改变作用域,它的内部依然是当前作用域。这造成了with语句的一个很大的弊病,就是绑定对象不明确。
建议不要使用with语句,可以考虑用一个临时变量代替with。(所以一般还是不用的吧)
函数
- 声明函数的方法:1、function命 2、函数表达 3、function构造函数
function声明:结尾的大括号后面不用加分号。函数表达式:需要在语句的结尾(大括号外面)加上分号,表示语句结束。除此之外,两者近似等价。
构造函数法:只有最后一个参数会被当做函数体,如果只有一个参数,该参数就是函数体。不直观,几乎无人使用。 - 函数名提升:function命令声明的时候提升,所以不管在什么位置声明都不会报错。函数表达式声明时不能提升。
- name属性:返回函数/函数表达式的名字
- length属性:函数定义之中的参数个数。
- **toString()**方法:返回一个字符串,内容是函数的源码(包括注释)。若是 原生的函数,返回function (){[native code]}。
变相实现多行字符串:
- 作用域:函数自己的作用域,是其声明时所在的作用域,与其运行时所在的作用域无关。
很容易犯错的一点是,如果函数A调用函数B,却没考虑到函数B不会引用函数A的内部变量。 - 参数:如果一定要省略靠前的参数,只有显式传入undefined。如
f(undefined,1)
- 传值传递&传址传递 原始类型的值(数值、字符串、布尔值),传递方式是传值传递,在函数内部修改不会影响原始值。复合类型的值(数组、对象、其他函数),传递方式是传址传递,在函数内部修改参数,会影响原始值。
如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。重新赋值就会指向另一个地址,原值不受影响。 - 如果有同名的参数,则取最后出现的那个值。
- arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
正常模式下,arguments对象可以在运行时修改。
严格模式下,arguments对象与函数参数不具有联动关系。'use strict';
通过arguments对象的length属性,可以判断函数调用时到底带几个参数。(实际的) - 闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包最大的特点,就是它可以“记住”诞生的环境,比如f2记住了它诞生的环境f1,所以从f2可以得到f1的内部变量。
闭包的最大用处有两个,一个是可以读取外层函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。
外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题
- 立即调用的函数表达式(IIFE)
(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();
第一种更好,完全避免了污染全局变量。
目的有两个:一是不必为函数命名,避免了污染全局变量;
二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
数组
- 数组是一种特殊的对象,它的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2…)
- 数组的键名其实也是字符串。之所以可以用数值读取,是因为非字符串的键名会被转为字符串。
- 数组成员读取:只能用方括号arr[0]表示,点读取不能跟数字。
- 数组的length属性,返回数组的成员数量。数组的数字键不需要连续,length属性的值总是比最大的那个整数键大1。另外,这也表明数组是一种动态的数据结构,可以随时增减数组的成员。
手动设置length长度:清空数组的一个有效方法,就是将length属性设为0。设置Length大于或小于当前元素:多的被删掉,少的补上空(读取时返回undefined);设置不合法(如负数)会报错。
如果数组的键名是添加超出范围的数值(如负数或Math.pow(2, 32)),该键名会自动转为字符串(因此还是能取到值的,键名都会转成字符串)。但length
返回值不会因此改变*(不会将其计入长度)*。 - in 运算符 适用于对象&数组,某个键名是否存在。
- for in 遍历对象&数组,但在遍历数组时,会遍历数字键&非数字键,所以不建议使用。遍历数组:1、可使用
for/while
循环。(想要逆向遍历,可以先读length,再l–循环)2、forEach方法,xx.forEach。 - 数组的空位:空位(表示没元素),取值是undefined,length属性不过滤空位;使用forEach/for…in遍历时,空位会被跳过。但如果某个位置(有元素,值)是undefined,那么遍历时不会被跳过。
- 类似数组的对象 ,键名是非负数,且有length属性的对象,是array-like object,但它实际上也不是数组,因为它的length属性不是动态的,不会随着成员变化而变化。(实际自己给它设置了一个length属性,只能说类似,但区别还是蛮大的吧。)
典型的“类似数组的对象”是函数的arguments
对象,以及大多数 DOM 元素集,还有字符串。
如何使用数组的方法?
1、使用slice方法,将其转化为数组:var arr = Array.prototype.slice.call(arrayLike);
2、使用call()方法,把数组的方法放到对象上面。
例:在字符串对象中调用forEach方法。
运算符
- 不要直接判断两个浮点数是否相等。
1 === 1.0 // true
浮点数不是精确的值,所以运算中要特别小心- 单独使用时,前自增和后自增效果一样。在表达式中,后自增返回原值,后自增。
- = 是赋值。== 默认转换数据类型 后进行比较。=== 全等 要求数据类型也一样
- && 与 || 或 !非
- 逻辑中断(短路操作):&& 左真返右,左假返左;|| 左真返左,左假返右
console.log(123 || num++ ) 先算左边,直接输出123 nums是0不影响。
- 逻辑中断(短路操作):&& 左真返右,左假返左;|| 左真返左,左假返右
- JavaScript 语言本身,虽然是一种解释型语言,但是在现代浏览器中,JavaScript 都是编译后运行
- 变量提升:JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。最终,所有的变量的声明语句,都会被提升到代码的头部。
-->
只有在行首,才会被当成单行注释,否则会当作正常的运算。
- 对于var命令来说,JavaScript 的区块
{ }
不构成单独的作用域(scope) - switch语句内部采用的是“严格相等运算符”
- do…while语句后面的分号注意不要省略。
- 标签(label),相当于定位符,用于跳转到程序的任意位置。标签通常与break语句和continue语句配合使用,跳出特定的循环。
算数运算符
加法运算符
-
重载(overload):运算子的不同,导致了不同的语法行为。 其他算数运算符不会发生。
要注意和这个规则区别:一个运算子是字符串,另一个运算子是非字符串,这时非字符串会转成字符串,再连接在一起。
运算次序是从左往右。所以,对于上面重载的例子,实际是先 ‘3’+4=‘34’;3+4=7;之后再运算得出最终结果。两条规律并不冲突 -
对象的相加:先转换称原始类型的值:
obj.valueOf().toString()
对象的valueof()
方法总是返回对象自身。toString
方法默认返回[object Object]
。(先执行valueOf方法,如有需要,再toString,特例如下)
可以自己定义valueOf或者toString方法,得到想要的结果。
余数运算符
- 运算结果的正负号由第一个运算子的正负号决定。为了得到负数的正确余数值,可以先使用绝对值函数
Math.abs()
。
例:判断-5是否为奇数
function isOdd(n) {
return Math.abs(n % 2) === 1;
}
isOdd(-5) // true
自增和自减运算符
- 运算的副作用:运算之后,变量的值发生变化。只有自增和自减会有。
数值运算符、负数值运算符
- 是一元运算符(只需要一个操作数)
- 功能:将任何值转换为数值(与Number函数作用相同),负数值得到的值与原值正负相反。连用2个,等同于数值运算符。但 -(-x) 中圆括号不可少,否则变为自减运算符。
指数运算符
- 前一个运算子是底数,后一个运算子是指数
- 指数运算符是右结合的。多个指数运算符连用时,先进行最右边的运算。
比较运算符
- 比较运算符用于比较两个值(各种类型的值)的大小,然后返回一个布尔值,表示是否满足指定的条件。
- 对于两个对象的比较,严格相等运算符(===)比较的是地址,而大于或小于运算符比较的是值。
- undefined和null与自身相等(==)。(所以肯定也严格相等)
undefined == null // true
互相比较也是 true 。- 如要比较是否相等,建议使用严格相等运算符(
===
),而不是(==
)。 - “严格不相等运算符”(!==)的算法:先求严格相等运算符的结果,然后返回相反值。
易混淆:
'true' == true // false
// 等同于 Number('true') === Number(true)
// 等同于 NaN === 1
' \t\r\n ' == 0 // true
布尔运算符
取反运算符
- 不管什么类型的值,取反运算后都会转为布尔值。
undefined、null、false、0、NaN、空字符串('')
取反后为true,其他值都为false。 - 连续做两次取反运算,等于将其转为对应的布尔值,与
Boolean
函数作用相同。两次取反就是将一个值转为布尔值的简便写法。还有一种方法,三元表达式(expression ? true : false
)。
且运算符 &&
- 用于多个表达式的求值。规则是:
如果第一个运算子的布尔值为true,则返回第二个运算子的值(注意是值,不是布尔值);如果第一个运算子的布尔值为false,则直接返回第一个运算子的值,且不再对第二个运算子求值。 - 短路机制可用于取代 if 结构。但表述不够清晰,还是不要用比较好。
- 多个且运算符连用时,返回第一个布尔值为false的表达式的值。若全为true,返回最后一个表达式的值。
或运算符 ||
- 用于多个表达式的求值。规则是:
如果第一个运算子的布尔值为true,则返回第一个运算子的值,且不再对第二个运算子求值;如果第一个运算子的布尔值为false,则返回第二个运算子的值。 - 也有短路机制。
- 多个或运算符连用时,返回第一个布尔值为true的表达式的值。若全为false,则返回最后一个表达式的值。
- 或运算符常用于为一个变量设置默认值。好处是:提前定义,防止因为未定义Undefined?
三元条件运算符
- 是 JavaScript 语言唯一一个需要三个运算子的运算符。
- 如果第一个表达式的布尔值为true,则返回第二个表达式的值,否则返回第三个表达式的值。
- 与if…else的语句表达效果相同。唯一区别是:三元表达式有返回值。
console.log(true ? 'T' : 'F');
而不能用if…else。
在这种场合比if…else方便许多。
二进制位运算符
二进制或运算符
- 逐位比较两个运算子,0 0 才返 0
- 位运算只对(32位范围内的)整数有效,遇到小数时,会将小数部分舍去,只保留整数部分。
与运算符
- 1 1才返1
否运算符
- 一个数与自身的取反值相加,等于-1
- 对一个整数连续两次二进制否运算,得到它自身。
- 对一个小数连续进行两次二进制否运算,能达到取整效果。这是所有取整方法中最快的一种。
异或运算符
- 两个二进制位不同时返回1,相同时返回0
- 特殊运用 :连续对两个数a和b进行三次异或运算,
a^=b; b^=a; a^=b
;,可以互换它们的值。互换两个变量的值的最快方法。
- 将十进制数转换为二进制之后,逐位比较。最后得一个二进制结果,再转成十进制输出。*
- 也可用于取整 与0 异或。
左移运算符 <<
- 表示将一个数的二进制值向左移动指定的位数,尾部补0,即乘以2的指定次方。
- 向左移动的时候,最高位的符号位是一起移动的。
- 左移 0 位, 等同于 取整。
右移运算符 >>
- 表示将一个数的二进制值向右移动指定的位数。如果是正数,头部全部补0;如果是负数,头部全部补1。
- 右移运算符基本上相当于除以2的指定次方(最高位即符号位参与移动)。
- 右移运算可以模拟 2 的整除运算。(右移几位,除以2的几次方,不过看起来好像没啥用?)
头部补零的右移运算符 >>>
- 与右移运算符的区别:不考虑符号位,头部全部补0。所以,总是得到正数。
- 用处:
什么时候需要看呢?不知道……
开关作用
- 位运算符可以用作设置对象属性的开关。
不太懂…是不是类似实际使用中的setting,它之间也有一些逻辑关系,比如,如果打开了设置xxx,其子项才可以选择,或者,但打开xxx,xxx之后,xxx也默认打开了?
其他运算符
void
- 作用是执行一个表达式,但不返回任何值,或者说返回undefined。
- void运算符的优先性很高,如果不使用括号,容易造成错误的结果。
- 主要用途是浏览器的书签工具(Bookmarklet),以及在超级链接中插入代码防止网页跳转。例子如下:
逗号运算符
- 对两个表达式求值,并返回后一个表达式的值。
- 一个用途是,在返回一个值之前,进行一些辅助操作。
例子:
左结合与右结合
- 大多数运算符是“左结合”。
- 少数运算符是“右结合”,其中最主要的是赋值运算符(=)和三元条件运算符(?:)、指数运算符(**)。
语法
数据类型转换
强制转换
- 主要指使用
Number()
、String()
和Boolean()
三个函数,手动将各种类型的值,分别转换成数字、字符串或者布尔值。 - Number函数
- 将字符串转为数值时,number函数要比parseInt函数严格很多。基本上,只要有一个字符无法转成数值,整个字符串就会被转为NaN。
parseInt逐个解析字符,而Number函数整体转换字符串的类型。
parseInt和Number函数都会自动过滤一个字符串前导和后缀的空格。- - Number方法的参数是对象时,将返回NaN,除非是包含单个数值的数组。
- 如果toString方法返回的不是原始类型的值,结果就会报错。
- 将字符串转为数值时,number函数要比parseInt函数严格很多。基本上,只要有一个字符无法转成数值,整个字符串就会被转为NaN。
- String()
- String方法背后的转换规则,与Number方法基本相同,只是互换了valueOf方法和toString方法的执行顺序。先toString(),再valueOf()
- 如果toString法和valueOf方法,返回的都是对象,就会报错。
- Boolean()
- *转换规则:除了以
undefined/null/0(包含-0和+0/NaN/''(空字符串)
的转换结果为false,false自身不变;其他的值全部为true。 - 所有对象(包括空对象)的转换结果都是true,甚至连false对应的布尔对象**new Boolean(false)**也是true。(出于性能的考虑)
- *转换规则:除了以
- 自动转换
- 以强制转换为基础。自动转换:用户不可见。
1.不同类型的数据互相运算。(如:字符串+数字)
2.对非布尔值类型的数据求布尔值。
3.对非数值类型的值使用一元运算符(即+和-),会把运算子转为数值。 - 具有不确定性(有时想求和,结果输出一个字符串了),而且不易除错。 如果可以,就直接用上面3个函数,进行显式转换
- 以强制转换为基础。自动转换:用户不可见。
错误处理机制
error实例对象
- message:错误提示信息;name:错误名称(非标准属性);stack:错误的堆栈(非标准属性)
原生错误类型
- Error的六个派生对象
- SyntaxError 对象:解析代码时发生的语法错误;语法解析阶段就能发现。
- ReferenceError 对象:引用一个不存在的变量 或者 将一个值分配给无法分配的对象
- RangeError 对象:一个值超出有效范围时发生的错误。主要:数组长度为负、Number对象的方法参数超出范围,以及数堆栈超过最大值。
- TypeError 对象:变量或参数不是预期类型时发生的错误。如对原始类型的值用new命令;调用对象不存在的方法。
- URIError 对象:表示 URI 相关函数的参数不正确。
- EvalError 对象:表示eval函数没有被正确执行。(已不再使用的)
也可以自己自定义错误,不过不太懂= =感觉和JAVA有点像。
throw语句
- 手动中断程序执行,抛出一个错误。
- 可以抛出任何类型的值。
- 对于 JavaScript 引擎来说,遇到throw语句,程序就中止了。
try…catch结构
- 允许对错误进行处理,选择是否往下执行。
- try…catch结构可以嵌套。
- 在catch代码中加入判断语句,可以捕捉不同类型的错误。
- 在最后添加一个
finally
代码块,表示不管是否出现错误,都必需在最后运行的语句。
如果只有try-finally,没有catch语句,一旦发生错误,代码就会中断执行,中断前,执行finally语句,再提示报错信息。
那如果又有catch,又有finally,catch后会再抛出错误,顺序是什么样呢?
- catch会把该显示的显示掉。相当于依次进行。
- catch和finally里都有return,以后一个为准。 return后面的代码不执行。
- catch里遇到throw(没有嵌套的话),直接执行finally。
或者说finally后面的也不会被执行吗?
console.log
- 如果第一个参数是格式字符串(使用了格式占位符),console.log方法将依次用后面的参数替换占位符,然后再进行输出.
console.log(' %s + %s = %s', 1, 1, 2)
// 1 + 1 = 2
上面代码中,console.log方法的第一个参数有三个占位符(%s),第二、三、四个参数会在显示时,依次替换掉这个三个占位符。
- log方法是写入标准输出(stdout),warn方法和error方法是写入标准错误(stderr)。
- console.table(): 对于某些复合类型的数据,console.table方法可以将其转为表格显示。
- console.count() :用于计数,输出它被调用了多少次。参数也可以是字符串形式。
- console.dir(),console.dirxml():dir方法用来对一个对象进行检查(inspect),并以易于阅读和打印的格式显示。dirxml方法主要用于以目录树的形式,显示 DOM 节点。
- console.assert():程序运行过程中,进行条件判断,如果不满足条件,就显示一个错误,但不会中断程序执行。这样就相当于提示用户,内部状态不正确。
- console.time(),console.timeEnd():time方法表示计时开始,timeEnd方法表示计时结束。它们的参数是计时器的名称。可以算出一个操作所花费的准确时间。
- console.group(),console.groupEnd(),console.groupCollapsed():将显示的信息分组。一组内的信息可以用鼠标折叠或展开。group:默认展开;groupcollapsed:默认折叠;
- console.trace显示当前执行的代码在堆栈中的调用路径。
- console.clear():清除当前控制台的所有输出,将光标回置到第一行。如果用户选中了控制台的“Preserve log”选项,console.clear方法将不起作用。
一些重点:
-
控制台命令行API,暂时没怎么使用到,所以暂时省略一下。
-
圆括号里,只能是表达式。 { } 大括号里,可能是表达式或语句。表达 对象 时:({ foo: 123 })
-
圆括号不是运算符,而是一种语法结构。它一共有两种用法:一种是把表达式放在圆括号之中(表示表达式的组合),提升运算的优先级;另一种是跟在函数的后面,作用是调用函数。
-
函数放在圆括号之中,会返回函数本身。
-
表示区块起首的大括号,不要另起一行。
-
所有的++运算符都可以用+= 1代替。
-
switch…case结构可以用对象结构代替。(改写,有点复杂,搞不懂)
-debugger 语句:在代码里加,设置断点。没有除错工具,JS引擎自动跳过。
什么意思呢,chrome界面遇到这个不是会停止运行吗?自带除错工具?在vscode里写的时候,不报错(因为没有除错工具?)
一些问题:
为啥捏……= =
Number函数将字符串转为数值的规则 是什么呢?如何得出来的
取整的话,取反或者异或 都可以,哪个速度比较快呢?说是说 取反是最快的= =不知道为啥。
二进制转十进制:?减去1后取反,再加上负号