JS高级程序设计——阅读笔记一


本系列博客主要是面向自己创作,实属自己的读书笔记,注重记录一些重点,并摘录引用一些大佬对于部分知识点的解释,帮助自己翻阅和理解,一定要配合原著食用。

第二章 HTML中的JavaScript

2.1

在使用行内JS代码时,注意代码中不能存在字符串</script>,如果一定要使用,可以使用转义字符\
使用了src属性的<script>元素不应该在标签内包含其他任何的JS代码
关于<script>的跨域,也就是我们常说的JSONP戳这里
关于<script>标签的deferasync属性戳这里

2.1.1 标签位置

把所有的JS文件引入都放在<head>中会极大的延长首屏渲染的时间,记得将所有JS引用放在<body>元素中的页面内容后。

2.1.2 推迟执行脚本

<script>元素的defer属性表示这个JS可以推迟执行
defer属性只对外部脚本文件有效
defer会在DOMContentLoaded之前执行,但是并不一定会按照从上至下的顺序

2.1.3 异步执行脚本

<script>元素的async属性表示这个JS可以推迟执行
async属性不保证执行顺序
异步脚本保证在load事件前执行
异步脚本不应该在加载期间修改DOM

2.1.4 动态加载脚本

使用DOM API动态创建script标签加载js文件对浏览器预加载器是不可见的,所以会打乱资源获取队列的优先级,可能会产生严重的性能影响
问题:原生HTML的标签就已经有多种属性来控制外部脚本的加载,那么像react.lazy等API又有什么区别和优势呢?(可以出一篇博客分析)

2.1.5 XHTML

已经退出历史舞台了,不做了解,省些篇幅。

2.2 行内代码与外部文件

选择外部文件存放JS代码的原因如下:

  • 可维护性
  • 缓存
  • 适应未来

2.3文档模式

混杂模式和标准模式共有四种形式,分别是:

IE5:以混杂模式渲染页面(IE5的默认模式就是混杂模式)。IE8及更高版本中的新功能都无法使用。

IE7:以IE7标准模式渲染页面。IE8及更高版本中的新功能都无法使用。

IE8:以IE8标准模式渲染页面。IE8中的新功能都可以使用,因此可以使用Selector
API、更多CSS2级选择符和某些CSS3功能,还有一些HTML5功能。不过IE9中的新功能无法使用。

IE9:以IE9标准模式渲染页面。IE9中的新功能都能使用,比如ECMAScript5、完整的CSS3以及更多HTML5功能。这个文档模式是最高级的模式。

现在IE浏览器已经下架了,说明它真的不好用

2.4 noscript元素

现在浏览器绝大多数都是支持JS的,无需过多了解

第三章 语言基础

其实绝大部分编程语言的语言基础是相通的,如果掌握一门编程语言就可以快速的了解其他

3.1 语法

这篇文章总结的比较好,传送门

3.2 关键字与保留字

ECMA-262第6版(es6)规定的所有关键字

break       do          in            typeof
case        else        instanceof    var
catch       export      new           void
class       extends     return        while
const       finally     super         with
continue    for         switch        yield
debugger    function    this
default     if          throw
delete      import      try

ECMA-262第6版为将来保留的所有词汇

始终保留:
 
enum
 
 
严格模式下保留:
 
implements  package     public
interface   protected   static
let         private
 
 
模块代码中保留:
 
await

3.3 变量

var

对于ES6的松散类型,虽然是松散的,针对简单的脚本进行快速开发也许是比较好的选择,但是针对大型需求一定要注意类型的区分,后续有TS对于大型项目的可维护性提升很大。

变量提升会把var声明的变量拉到作用域顶部。

let

我自己在编程的时候就喜欢使用let,正是因为他和var的区别,var声明的范围是函数作用域,而let声明是具有块作用域的

暂时性死区

这个概念其实我有点模糊了,所以再来总结一下
let声明的变量不会再作用域中被提升
let声明之前的执行瞬间被称为“暂时性死区”,在此阶段引用任何后面才声明的变量都会抛出ReferenceError

let在全局作用域中声明的变量不会成为window对象的属性(var声明的变量则会)

条件声明是反模式?

这里有一句话需要了解,为什么说条件声明是一种反模式,他会让程序变得更难以理解?

反模式是软件开发中被认为是坏编程实践的某些模式。

与设计模式不同的是,设计模式是解决常见问题的常用方法,这些常见问题已经正式化,通常被认为是一种良好的开发实践,而反模式则是相反的,是不可取的。

例如,在面向对象编程中,其思想是将软件分成称为对象的小部分。面向对象编程中的反模式是一个执行许多功能的上帝对象,这些功能可以更好地分为不同的对象。

class GodObject {
    function PerformInitialization() {}
    function ReadFromFile() {}
    function WriteToFile() {}
    function DisplayToScreen() {}
    function PerformCalculation() {}
    function ValidateInput() {}
    // and so on... //
}

上面的示例有一个执行所有操作的对象。在面向对象编程中,最好对不同的对象有明确的职责,以使代码更少地耦合,最终更易于维护:

class FileInputOutput {
    function ReadFromFile() {}
    function WriteToFile() {}
}

class UserInputOutput {
    function DisplayToScreen() {}
    function ValidateInput() {}
}

class Logic {
    function PerformInitialization() {}
    function PerformCalculation() {}
}

归根结底,开发具有常用模式(设计模式)的软件有很好的方法,但也有开发和实现软件的方法,这些方法会导致问题。被认为是不好的软件开发实践的模式是反模式。

那么实际上,这里提到的条件声明就应对文章中提到的情况,由于条件声明的变量被限制在块级作用域内,因此后续的赋值就类似全局赋值一般不可取,例如

try{
        console.log(age);//如果age没有声明过就会报错
    }
catch(error) {
        let age;//这里就是一个条件声明
    }
age = 25;
const

是我用的最多的一个声明变量的关键字了,它在声明变量的时候必须同时初始化变量。
const变量如果声明了一个对象,那么改变对象内部属性并不违反const的限制。

声明风格和最佳实践

  • 不适用var
  • const优先,let次之

3.4 数据类型

typeof

typeof返回的是一组字符串:

console.log(typeof 42);
// expected output: "number"

console.log(typeof 'blubber');
// expected output: "string"

console.log(typeof true);
// expected output: "boolean"

console.log(typeof undeclaredVariable);
// expected output: "undefined"

值得注意的是,undefined类型是为了明确空对象指针null和未初始化变量的区别。

Null

在定义将来要保存对象值的变量时,建议使用null来初始化,不要使用其他值。
任何时候,只要变量要保存对象,而当时有没有哪个对象可保存,就要用null来填充该变量。

Boolean

在这里插入图片描述
注意使用!!进行boolean转换时效率要高于使用Boolean()方法

Number
浮点值

存储浮点值使用的内存空间是存储整数值的两倍
永远不要测试某个特定的浮点值
因为浮点值的精确度最高可达17位小数

if(a + b == 0.3) {
    console.log('you got 0.3');
}

如果a=0.1,b=0.2,那么两数之和为0.30000000000000004,不是0.3,所以会发生问题

值的范围
方法或属性解释
Number.MIN_VALUEES6可以表示的最小值
Number.MAX_VALUEES6可以表示的最大值
Infinity超过Number.MAX_VALUE的值
isFinite()确定一个值是不是有限大
数值转换

Number() 转string时必须全部为数字才能转为有效数字
转换规则:

  1. 布尔值,true 转换为1,false 转换为0。
  2. 数值,直接返回。
  3. null,返回0。
  4. undefined,返回NaN。
  5. 字符串,应用以下规则。
  6. 如果字符串包含数值字符,包括数值字符前面带加、减号的情况,则转换为一个十进制数值。因此,Number(“1”)返回1,Number(“123”)返回123,Number(“011”)返回11(忽略前面
  7. 如果字符串包含有效的浮点值格式如"1.1",则会转换为相应的浮点值(同样,忽略前面的零)。
  8. 如果字符串包含有效的十六进制格式如"0xf",则会转换为与该十六进制值对应的十进制整数。
  9. 如果是空字符串(不包含字符),则返回0。
  10. 如果字符串包含除上述情况之外的其他字符,则返回NaN。
  11. 对象,调用valueOf()方法,并按照上述规则转换返回的值。如果转换结果是NaN,则调用toString()方法,再按照转换字符串的规则转换。

parseInt() 必须以数字开头,从第一个非空字符开始转换,如第一个字符不是数值,+,-,立即返回NaN。碰到字符串尾,非数值字符结束。第二个参数表示几进制,es5不具备解析八进制的功能
paeseFloat()只解析十进制

string类型

把一个 Number 对象转换为一个字符串,并返回数字的字符串表示。

var number = new Number(1337);
document.write (number.toString())
模板字符串

模板字面量是允许嵌入表达式的字符串字面量。
插值表达式:${}

// 普通字符串
`In JavaScript '\n' is a line-feed.`
 
// 多行字符串
`In JavaScript this is
not legal.`
 
// 字符串中嵌入变量
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`   // Hello Bob, how are you today?

模板字符串甚至可以调用函数
高能的是,以前从来没有了解过一种用法叫做标签模板

doSomething`my name is ${name}`

定义一个函数来解析传入的模板字符串。标签函数的第一个参数包含一个字符串值的数组,其余的参数与表达式相关。比如上面那个my name is ${name},那么第一个参数就是[‘my name is’, ‘’ ,’’] ,后面两个参数是${name}前后的空值。模板字符串中插入的变量如果多一个,那么就增加一个参数。

Symbol类型

简单理解就是表示独一无二的值

Symbol 值通过Symbol()函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的
Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

let sym=Symbol()
let otherSym=Symbol()
smy == otherSmy	//false

let fooSmybol=Symbol('foo')

Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。

Object类型

通过对象字面量表达式定义对象时,实际上不会调用Object函数。
理解arguments

JS中的参数在内部是用一个数组来表示的。函数接收到的始终是这个数组。
在函数体内能够通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。

function sayHi (name,message) {

    alert("Hello " + arguments[0] + "," + arguments[1]);

};

等价于

function sayHi (name, message) {

    alert("Hello " + name + "," + message);

};

几个需要注意的方法:

  1. Constructor 构造函数,创建当前对象的函数
  2. hasOwnProperty(propertyName) 判断当前实例对象(不是原型)上是否存在给定的属性
  3. isProtyotypeOf(object) 判断当前对象是否为另一个对象的原型
  4. propertyIsEnumerable(propertyName) 判断给定的属性是否可被for-in语句枚举

3.5 操作符

一元操作符

前缀版:
变量的值会在语句被求值前改变
后缀版:
递增递减在语句被求值后才改变

类型隐式转换
+号
[]+{}
"[object Object]"
{}+[]
"a"+[]
"a"
"a"+{}
"a[object Object]"
1+[]
"1"
1+{}
"1[object Obje
0
1+'0'
"10"
null+1
1
null+"q"
"nullq"
undefined+1
NaN
undefined+"b"
"undefinedb"
NaN+1
NaN
NaN+"c"
"NaNc"
==号
undefined==null
true
null==1
false
null==0
false
undefined==1
false
undefined==0
false
[1]==1
true
var a={1:1}
undefined
a==1
false
位操作符

位操作符使用较少,特此记录
详见ECMAscript位操作符

布尔操作符

非 !

  1. 如果操作数是对象,则返回false。
  2. 如果操作数是空字符串,则返回true。
  3. 如果操作数是非空字符串,则返回false。
  4. 如果操作数是数值0,则返回true。
  5. 如果操作数是非0 数值(包括Infinity),则返回false。
  6. 如果操作数是null,则返回true。
  7. 如果操作数是NaN,则返回true。
  8. 如果操作数是undefined,则返回true

与 &&

  1. 如果第一个操作数是对象,则返回第二个操作数。
  2. 如果第二个操作数是对象,则只有第一个操作数求值为true 才会返回该对象。
  3. 如果两个操作数都是对象,则返回第二个操作数。
  4. 如果有一个操作数是null,则返回null。
  5. 如果有一个操作数是NaN,则返回NaN。
  6. 如果有一个操作数是undefined,则返回undefined。
  7. 逻辑与操作符是一种短路操作符,意思就是如果第一个操作数决定了结果,那么永远不会对第二个
  8. 操作数求值。对逻辑与操作符来说,如果第一个操作数是false,那么无论第二个操作数是什么值,结果也不可能等于true。

或 ||

  1. 如果第一个操作数是对象,则返回第一个操作数。
  2. 如果第一个操作数求值为false,则返回第二个操作数。
  3. 如果两个操作数都是对象,则返回第一个操作数。
  4. 如果两个操作数都是null,则返回null。
  5. 如果两个操作数都是NaN,则返回NaN。
  6. 如果两个操作数都是undefined,则返回undefined。
  7. 同样与逻辑与类似,逻辑或操作符也具有短路的特性。只不过对逻辑或而言,第一个操作数求值为true,第二个操作数就不会再被求值了。
关系操作符

小于(<)、大于(>)、小于等于(<=)和大于等于(>=),
用法跟数学课上学的一样。这几个操作符都返回布尔值

  • 如果操作数都是数值,则执行数值比较。
  • 如果操作数都是字符串,则逐个比较字符串中对应字符的编码。
  • 如果有任一操作数是数值,则将另一个操作数转换为数值,执行数值比较。
  • 如果有任一操作数是对象,则调用其valueOf()方法,取得结果后再根据前面的规则执行比较。
  • 如果没有valueOf()操作符,则调用toString()方法,取得结果后再根据前面的规则执行比较。
  • 如果有任一操作数是布尔值,则将其转换为数值再执行比较。

在使用关系操作符比较两个字符串时,会发生一个有趣的现象。很多人认为小于意味着“字母顺序靠前”,而大于意味着“字母顺序靠后”,实际上不是这么回事。对字符串而言,关系操作符会比较字符串中对应字符的ASC编码,而这些编码是数值。比较完之后,会返回布尔值。问题的关键在于,大写字母的编码都小于小写字母的编码

相等操作符
  1. 相等,不相等 ==
    先转换再比较
  2. 全等,不全等 ===
    仅比较不转换
链判断运算符和Null判断运算符

项目中使用较多,这篇文章讲述较为细致:传送门

语句

在这里插入图片描述

for-in

迭代语句,枚举对象的非符号键属性

for(const kk in window){
	console.log(kk)
}

ECMAScript 中对象的属性是无序的,因此 for-in 语句不能保证返回对象属性的顺序。
如对象值为null,undefined。for-in抛出错误,或不在执行循环体
如果for-in 循环要迭代的变量是null 或undefined,则不执行循环体。

for-of

迭代语句,用于遍历可迭代对象的元素

for (const el of [2,4,6,8]) {
	document.write(el);
}
  • for…of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象的集合.但是不能遍历对象,因为没有迭代器对象.与forEach()不同的是,它可以正确响应break、continue和return语句
  • for-of循环不支持普通对象,但如果你想迭代一个对象的属性,你可以用for-in循环(这也是它的本职工作)或内建的Object.keys()方法
for-await-of

支持生成promise的异步可迭代对象
几乎没有用过,这篇文章讲解的比较详尽异步迭代器传送门

小结

本次阅读大概有这些内容是自己感觉有些不扎实或者需要注意的,经常查阅新知识的同时,对于旧知识的重复学习也有助于自己对一些细节的把控,而且领悟的程度是不同,细心的掌握基础知识对于以后业务工作上能够减少自己纰漏的出现至关重要!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值