JavaScript高级程序设计学习笔记(一)

最近为了补js的基础,开坑javascript高程,这书基础部分写得很详细很好读,搭配着MDN进行学习理解。
闲下来的时间记录一下边读边做的笔记,大多是以前编程的时候没注意过的基础知识点。

第一章

JavaScript的完整实现包括以下三个部分:
1、核心(ECMAScript),提供核心语言功能。
2、文档对象模型(DOM),提供访问和操作网页内容的方法和接口。
3、浏览器对象模型(BOM),提供与浏览器交互的方法和接口。

第二章

script标签
延迟脚本:定义defer属性,表明脚本在执行时不会影响页面的构造,也就是脚本会被延迟到整个页面都解析完毕再运行。

<head>
<script type="text/javascript" defer="defer" src="e1.js"></script>
<script type="text/javascript" defer src="e2.js"></script>
</head>

HTML5中规范以上两个脚本按先后顺序执行,但现实中不一定会按照顺序执行(因此最好只包含一个延迟脚本)。
异步脚本:定义async属性,告诉浏览器立即下载文件,与defer不同,标记为async的脚本并不保证按照先后顺序执行。

<head>
<script type="text/javascript" async src="e1.js"></script>
<script type="text/javascript" async src="e2.js"></script>
</head>

由于第二个脚本文件可能会在第一个脚本文件之前执行,所以应当确保两者互不依赖。指定async属性是为了不让页面等待脚本的下载,从而异步地去加载页面其他内容,建议异步脚本不要在加载期间修改DOM。
(异步脚本一定会在页面的load事件前执行)

第三章

语法

严格模式
在脚本顶部添加"use strict",其实是一个编译指示,用于告诉JavaScript引擎切换到严格模式。

语句
1、分号结尾!(以前python的后遗症,经常忘加分号,这会导致代码压缩错误)
2、对于控制语句,推荐用{ }代码块,让编码易读,且意图清晰!

变量

var操作符
用var定义的变量会成为定义该变量作用域中的局部变量,比如说在函数中定义了一个变量,那么该变量将在退出函数时被销毁。(之前以为是全局使用的,跟let搞混了)
在声明和定义时var可以省略,用于定义全局变量,但不是推荐做法,避免造成不必要的混乱。

数据类型

typeof操作符
注意 typeof 它不是个函数,是个操作符!

typeof 1 // 'number'
typeof '1' // 'string'
typeof true // 'boolean'
typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
typeof undefined // 'undefined'
typeof b // b 没有声明,但是还会显示 undefined
typeof Symbol() // 'symbol'
//Symbol是ES6的新类型,类似于一种标识唯一性的ID,第三版的书上没有

PS:书上说null是object类型,但没说为什么,这里引用一篇博客里说到的:

这是因为在 JS 的最初版本中,使用的是 32 位系统,为了性能考虑,使用低位存储了变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。虽然现在的内部类型判断代码已经改变了,但是对于这个 Bug 却是一直流传下来。

undefined类型
未被初始化的变量,会被自动赋予undefined值;而对未声明的变量,typeof会返回undefined而不会报错。
这提醒我们最好初始化变量的时候能够赋予明确的值,这样易于区分被检测的变量是未被声明,还是未被初始化(这样规范的话,undefined就代表变量未被声明)。

boolean类型
Boolean()函数,需要注意0和NaN(Number类型)会被转换为false。

number类型
注意十进制、八进制和十六进制的表示。

var intNum=55; // 十进制的55
var octalNum=072; // 八进制的58
var hexNum=0x2f; // 十六进制的47

面试的经典问题:0.1+0.2!=0.3
原因:
因为 JS 采用 IEEE 754 双精度版本(64位),并且只要采用 IEEE 754 的语言都有该问题。
我们都知道计算机表示十进制是采用二进制表示的,所以 0.1 在二进制表示为

// (0011) 表示循环
0.1 = 2^-4 * 1.10011(0011)

小数算二进制和整数不同。乘法计算时,只计算小数位,得到第一个进位就是最高位。所以我们得出 0.1 = 2^-4 * 1.10011(0011),那么 0.2 的演算只需要去掉第一步乘法,所以得出 0.2 = 2^-3 * 1.10011(0011)。
回来继续说 IEEE 754 双精度。六十四位中符号位占一位,整数位占十一位,其余五十二位都为小数位。因为 0.1 和 0.2 都是无限循环的二进制了,所以在小数位末尾处需要判断是否进位(就和十进制的四舍五入一样)。
所以 0.1的二进制表示(0.1 = 2^-4 * 1.10011(0011)) 进位后就变成了 2^-4 * 1.10011(0011 * 12次)010,同理可得0.2的二进制表示。
把这两个二进制加起来得到 2^-2 * 1.0011(0011 * 11次)0100 , 这个值再换算成十进制就是 0.30000000000000004。

// 计算过程
0.00011001100110011001100110011001100110011001100110011010
0.0011001100110011001100110011001100110011001100110011010

// 相加得
0.01001100110011001100110011001100110011001100110011001110
// 转换为IEEE 754的64位表示(小数位保留52位)
0.01(整数位)0011001100110011001100110011001100110011001100110011(52位后面舍去,因为四舍五入要进位)10->
0.01(整数位)0011001100110011001100110011001100110011001100110100->
0.30000000000000004
//PS:数得我眼睛快花了

number类型的数值范围
小于Number.MIN_VALUE->-Infinity<-Number.NEGATIVE_INFINITY
大于Number.MAX_VALUE->Infinity<-Number.POSITIVE_INFINITY

NaN(Not a Number)的判断
isNaN(),判断是否“非数值”,如果不能转换为数值,返回true。

数值转换三个函数
把非数值转换为数值可以用:
Number()、parseInt()、parseFloat()
注意字符串会去掉前导零。

转换为字符串
toString()方法,在调用数值的toString()方法时,可以传入输出数值的基数,默认转换为十进制格式。

object类型
object实例的属性和方法:

constructor(),构造函数

hasOwnProperty(propertyName),检查属性在当前对象实例中是否存在

isPropertyOf(object),检查传入对象是否当前对象的原型

propertyIsEnumerable(propertyName),检查属性是不是可用for-in语句枚举

toLocaleString(),返回对象的字符串表示,该字符串与执行环境的地区对应(没太懂,MDN上举了时区和人民币格式的例子)

toString(),返回对象的字符串表示

valueOf(),返回对象的字符串、数值或布尔值表示

注意:propertyName要用字符串形式传入(“propertyName”)。

操作符

位操作符
注意一下按位非

var num1 = 25;
var num2 = ~num1; // -26

返回数值的反码,也就是操作数的负值-1。

右移分为有符号右移(>>)和无符号右移(>>>),区别是有符号右移用符号位来填充空位,无符号右移用0来填充空位。

布尔操作符
两个逻辑非(!!)效果和Boolean()方法一样

逻辑与和逻辑或的短路性质

乘性操作符

Infinity*0 // NaN
Infinity*1 // Infinity
Infinity*-1 // -Infinity

除性操作符

Infinity/Infinity // NaN
非零有限数除以0 // Infinity或者-Infinity

关系操作符
有意思的现象:

var result1 = NaN <3; // false
var result2 = NaN >=3; // false

相等操作符

相等(==)会进行类型转换(强制转型)再进行比较
全等(===)在两个操作数未经转换就相等的情况下返回true

语句

了解label语句与break和continue语句的联合使用。

严格模式下不允许使用with语句。

switch语句在比较值时,使用的是全等操作符,因此不会发生类型转换。

函数

arguments的理解:数组形式(并不是Array的实例)
通过接受参数的个数不同,可以让函数分别实现不同的功能:

function doSomething(){
    if(arguments.length==0){
        do1();
    }else if(arguments.length==1){
        do2();
    }else if(arguments.length==2){
        do3();
    }else{
        do4();
    }
}

ECMAScript中的所有参数传递的都是值,所以不可能通过引用传参

函数名字相同时,该名字属于后定义的函数(也就是ECMAScript函数不能实现重载,因为函数没有签名,参数由包含零或多个值的数组来表示)。
尽管如此,通过检查传入函数中参数的类型和数量,来作出不同反应,还是可以模仿函数方法的重载的。

总结

第三章对类型转换讲解得非常详细,我也结合了MDN文档进行补充和了解,以前的粗犷学习路线导致自己有很多知识漏洞,还要继续查漏补缺!

接下来针对第四(变量、作用域和内存问题)和第五章(引用类型)进行学习。

PS:把高程当小说读还是不错的,我其实先看了比较感兴趣的第十五章(Canvas绘图),有OpenGL的基础,看起来饶有兴趣!

如果对你产生了帮助,请点个赞给我吧!感谢观看!

发布了5 篇原创文章 · 获赞 7 · 访问量 856

猜你喜欢

转载自blog.csdn.net/qq_40340478/article/details/105283931