JavaScript高级程序设计读后感(一)之零碎知识点查漏补缺
1-script延迟脚本defer及异步脚本async,区别及应用场景
- defer和async在读取下载时是一样的,相对于html解析来说都是异步的。
- 区别是下载完后执行时间。
- defer:立即下载,延迟执行。是最接近我们对脚本加载和执行要求的,要在所有元素解析完成之后,
DOMContentLoaded
事件触发之前完成。但最好只包含一个。 - async:立即下载,立即执行。不管声明顺序如何,只要加载完就会立即执行。用处不大,因为它完全不考虑依赖,不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的
defer:脚本代码依赖于页面中的DOM元素(文档是否解析完毕),或者被其他脚本文件依赖。
async:脚本并不关心页面中的DOM元素(文档是否解析完毕),并且也不会被其他脚本文件依赖。
2-未声明的变量,未初始化变量
- 未声明的变量,只能进行typeof操作符检测其数据类型,而delete操作本身不会导致错误,但并没有意义,且严格模式下会抛异常
- 未声明的变量赋值,在非严格模式下为全局变量,而严格模式下抛异常
- 未初始化变量执行typeof操作会返回undefined,而未声明的变量执行typeof操作同样会返回undefined
3-Number parseInt 字符串转数值 ,进制转换
Number:可以看出在字符串转数字时,能够识别十六进制和十进制,而在进制转换时,并不能很准确的识别是二进制还是八进制,因此提供了Number.toString(radix)方法。
// 转数值
Number('0x34') // 52(十六进制数)
Number('0111') // 111(十进制数)
Number('00001111') // 1111(十进制数)
// 进制转换
Number(0x34) // 52(十六进制数)
Number(0111) // 73(八进制数)
Number(111) // 111(十进制数)
Number(00001111) // 585(八进制数)
22.toString(16) // '16'(十六进制数)
22..toString(8) // '26'(八进制数)
22..toString(2) // '10110'(二进制数)
parseInt: 使用该方法解析二进制及八进制字符串时,ECMAScript3和5 存在分歧,
ECMAScript3中,'070'呗认为是八进制,因此转换后为十进制的56,
ECMAScript5中,该方法已经不具备解析八进制的能力,会忽略字符串的前导0,被解析为70,
为消除以上问题,该方法提供了第二个参数,即转化时使用的进制:
// 转数值 & 进制转换
parseInt('0x34') // 52(十六进制数)
parseInt('00001111') // 1111(十进制数)
parseInt('070') // 70(十进制数)
parseInt(070) // 56(八进制数)
parseInt('70',16) // 112(十六进制数)
parseInt('70',10) // 70(十进制数)
parseInt('70',8) // 56(八进制数)
parseInt('70',2) // NaN
parseInt('070',2) // 0(二进制数)
4-undefined && null 区别
undefined | null | |
---|---|---|
转数值 | NaN | 0 |
typeof | 'undefined' | 'object' |
if语句 | 被自动转为false | 被自动转为false |
应用场景 | 变量声明未赋值时,就等于undefined | 一个表示"无"的对象 |
函数定义形参未传实参,该参数等于undefined | 作为对象原型链的终点 | |
对象还未赋值的属性,该属性的值为undefined | ||
函数没有返回值时,默认返回undefined。 |
5-操作符
一元操作符: ++ / --
- 前置递增递减,变量的值都是在包含它们的语句被求值之前执行
- 后置递增递减,变量的值都是在包含它们的语句被求值之后执行
一元加和减操作符: + / -
- 一元加操作符以一个加号(+)表示,放在数值前面,对数值不会产生任何影响。放在非数值前,会像Number()转型函数一样进行转化。
- 一元减操作符以一个减号(-)表示,放在数值前面,该值会变成负数。放在非数值前,会像Number()转型函数一样进行转化。得到的数值转为负数。
let num1 = 2;
let num2 = 20;
let num3 = --num1 + num2; // 21
//let num3 = num1-- + num2; // 22
let num4 = num1 + num2; // 21
let s1 = "01";
let s2 = "1.1";
let s3 = "z";
let b = false;
let f = 1.1;
let o = {
valueOf() {
return -1;
}
};
s1 = -s1; // -1
s2 = -s2; // -1.1
s3 = -s3; // NaN
b = -b; // 0
f = -f; // -1.1
o = -o; // 1
6-Label语句
在 JavaScript 中,使用 label 语句可以为一行语句添加标签,以便在复杂结构中,设置跳转目标。语法格式:label : states
label 为任意合法的标识符,但不能使用保留字。然后使用冒号分隔签名与标签语句。
多与 break 语句配合使用,主要应用在循环结构、多分支结构中,或者嵌套的 switch 结构
。且需要退出非当前层结构,以便跳出内层嵌套体。break label;
,break 与label之间不能包含换行符,否则会解析为两个句子。如果没有设置标签名,则表示跳出当前最内层结构。
var num = 0;
outer: for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (i == 5 && j == 5) {
break outer;
// break ;
// continue outer; // 跳出本次循环,开始下一次循环,效果同break
}
num++;
}
}
console.log('break label:' + num); // 55
console.log('break:' + num); // 95
console.log('continue label:' + num); // 95
7-with语句
用于设置代码在特定对象中的作用域,也就是将 statement 中的变量作用域添加到 expression 中。语法:with (expression) { statement }
with语句中查询变量顺序: 是否是 with语句中的局部变量
-> 是否是 expression中的变量
->查找更高作用域范围
// eg1:
var sMessage = "hello";
function toUpperCase(){
console.log('word');
}
with(sMessage) {
console.log(toUpperCase()); //输出 "HELLO"
}
// eg2:
var obj = {
a: 'aa',
b: 'bb',
c: 'cc',
}
with(obj) {
var a = a
var b = b
var c = c
}
/**
* 等同于
var a = obj.a
var b = obj.b
var c = obj.c
*/
调用 toUpperCase() 时,解释程序将检查该方法是否是当前作用域函数。如果不是,将检查伪对象 sMessage,看它是否为该对象的方法。 输出 "HELLO",因为解释程序找到了字符串 "hello" 的 toUpperCase() 方法。
提示:with 语句是运行缓慢的代码块,会导致性能下降,同时也会给调试代码造成困难,因此在开发大型应用程序时,不建议使用with语句 。
with语句会创建新的变量对象,起到延长作用域链的作用,另外try catch中的错误对象,也会被添加到变量对象中,起到延长作用域链的作用。
8-垃圾回收机制简述
垃圾回收:JS代码运行,需要操作系统或者运行时环境分配内存空间,来存储变量及它的值。当某些变量不在参与运行时,就需要系统回收被占用的内存空间,称为垃圾回收
,而Javascript具有自动垃圾回收机制(GC:Garbage Collecation)
内存泄漏:不再用到的变量所占内存没有及时释放,导致程序运行中,内存越占越大,极端情况下可导致系统崩溃、服务器宕机。
目前各大浏览器通常用采用的垃圾回收有两种方法:标记清除
、引用计数
。
标记清除
- JS中最常用的垃圾回收方式。当变量进入执行环境时,就标记这个变量为
“进入环境”
。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”
。 - 垃圾收集器在运行时会给存储在内存中的所有变量都加上标记。然后去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
- JS中最常用的垃圾回收方式。当变量进入执行环境时,就标记这个变量为
引用计数
另一种不太常见的垃圾回收策略是引用计数,跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就
+1
。相反,如果该引用的变量又取得了另外一个值,则这个值的引用次数就-1
。当引用次数为0时,则说明没有办法再访问到这个值,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。而引用计数有个最大的问题: 循环引用,如对象A有一个属性指向对象B,而对象B也有一个属性指向对象A。obj1和obj2通过各自的属性相互引用;也就是说这两个对象的引用次数都为2。
在采用标记清除的策略时,由于函数执行之后,这两个对象都离开了作用域,因此这种相互引用不是个问题。
在采用引用计数的策略时,函数执行完成之后,obj1和obj2还将会继续存在,因为他们的引用次数永远不会是0。如果该函数被多次调用,就会导致大量的内存得不到回收。
function func() {
let obj1 = {};
let obj2 = {};
obj1.a = obj2; // obj1 引用 obj2
obj2.a = obj1; // obj2 引用 obj1
}
因此大部分浏览器都是以标记清除来实现垃圾回收机制,而IE老版本中有一部分对象并不是原生JavaScript对象。例如,其BOM和DOM中的对象就是使用C++以COM(Component Object Model,组件对象)对象的形式实现的,而COM对象的垃圾回收器就是采用的引用计数的策略。因此,即使IE的JS引擎使用标记清除的策略来实现的,但JS访问的COM对象依然是基于引用计数的策略的。换句话说,只要IE中涉及COM对象,就会存在循环引用的问题。
解决: 未避免, 最好是在不使用时,手动断开二者的引用关联,垃圾收集器下次运行时,就可以删除这些值并回收对应的内存
// 循环引用
var ele = document.getElementById('app');
var myObj = {};
myObj.node = ele;
ele.style = myObj;
// 手动断开二者的引用关联
myObj.node = null;
ele.style = null;
IE9把DOM和BOM对象都转换成真正的JS对象,这样就避免了两种垃圾收集算法并存导致的问题,也消除了常见的内存泄漏现象。
避免内存泄漏
- 清空数组优化:arr = []虽然可以清空数组,同时又创建了一个新数组 ,而
arr.length = 0
也能达到清空数组的目的,同时能实现数组重用,减少内存垃圾的产生。 - 循环优化:在循环中的函数表达式,能复用最好放到循环外面。
- 意外的全局变量:局部变量未声明,会变成一个全局变量,在页面关闭之前不会被释放,若非必要尽量声明使用局部变量。
- 被遗忘的定时器和回调函数:定时器任务执行完毕后,需要清除定时器。
- 闭包:闭包可以维持函数内局部变量,使其得不到释放。
9-函数内部属性 arguments
虽然arguments的主要用途是保存函数的参数,但这个对象还有一个callee
属性,该属性是一个指针,指向拥有这个arguments对象的函数
,表示对函数对象本身的引用。
// 阶乘函数递归,使用arguments.callee 与函数名解耦
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1);
}
}
console.log(factorial(5)); // 120
// 使用新的引用替换阶乘方法, 仍可以使用原函数体,实现解耦
let trueFactorial = factorial;
factorial = function() {
return 0;
};
console.log(trueFactorial(5)); // 120
console.log(factorial(5)); // 0
ECMAScript5规范化了另一个函数对象的属性,caller
,该属性保存着调用当前函数的函数引用,如果是在全局作用域下调用当前函数,则它的值为null。
为了实现更松散的耦合,也可以通过arguments.callee.caller
来访问相同的信息。
function outer() {
inner();
}
function inner() {
console.log(inner.caller); // [Function: outer]
console.log(arguments.callee.caller); // [Function: outer]
}
outer();
10-严格模式
通过严格模式,可以在函数内部选择进行较为严格的全局或局部的错误条件检测,好处就是可以提早知道代码中存在的错误,及时捕获一些可能导致编程错误的ECMAScript行为
选择进入严格模式,可以使用严格模式的编译指示
,实际就是一个不会赋给任何变量的字符串
“use strict”
,如果你没有控制页面中所有脚本的权力,建议只在需要测试的特定函数中开启严格模式。
未声明的变量赋值,str = "hello world",非严格模式会意外创建全局变量,严格模式抛出ReferenceError;
删除变量,var str = 'hello';delete str;非严格模式会默认返回false,严格模式抛出ReferenceError;
为对象的只读属性赋值会抛出TypeError;
为对象不可配置的属性使用delete会抛出TypeError;
为不可扩展的对象添加属性会抛出TypeError;
函数的参数重名,非严格模式通过参数名只能访问第二个参数,要访问第一个参数需要使用arguments,严格模式抛出SyntaxError;
修改命名参数的值,非严格模式下修改会映射到arguments中,严格模式下修改不会映射到arguments中
function get(foo){
"use strict";
foo = 'bar';
console.log(foo); // bar
console.log(arguments[0]); // 非严格 bar 严格 Hi
}
get('Hi')
不支持八进制字面量,报错
不允许使用with语句,视为语法错误
不能访问arguments.callee,arguments.caller,不能为函数的caller属性赋值。
在eval()中创建变量,在外部访问不到任何eval()中创建的任何变量或函数。
function doSomething(){
eval("var x = 10");
console.log(x); // 非严格 打印10 ,严格模式抛出 ReferenceError
}
- this指向问题,非严格模式下,使用函数的apply()或者call()方法时,null或undefined值会被转换为全局对象,而在严格模式下,函数的this值始终是指定的值,无论指定的是什么值
var color = 'red';
function displayColor(){
console.log(this.color);
}
// 非严格访问全局打印 red,
// 严格模式TypeError: Cannot read properties of null (reading 'color')
displayColor.call(null);
JavaScript高级程序设计读后感(一)之零碎知识点查漏补缺的更多相关文章
- JavaScript高级程序设计读后感(一)
一.什么是JavaScript? 本质? 历史? 表单验证发展成为一门语言 局限性?
- JS知识点查漏补缺
知识点1: 判断语句中遇到NaN即为 False 只需要注意遇到False即为False即可 使用join(),toString()皆可以将数组转化为字符串 二者的相同点在于都可以转化数组为字符串 二 ...
- java异常与spring事务关系的知识点查漏补缺
一.基础概念 java的异常结构图 从图中可知 Throwable是所有异常的根,java.lang.Throwable Error是错误,java.lang.Error Exception是异常,j ...
- java知识点查漏补缺-- 2020512
jvm: jdbc statement: JDBC statement中的PReparedStatement的占位符对应着即将与之对应当值,并且一个占位符只能对应一个值,如果能对应多个就会引起混淆.s ...
- JavaScript高级程序设计(第4版)知识点总结
介绍 JavaScript高级程序设计 第四版,在第三版的基础上添加了ES6相关的内容.如let.const关键字,Fetch API.工作者线程.模块.Promise 等.适合具有一定编程经验的 W ...
- javascript高级程序设计第二章知识点提炼
这是我整理的javascript高级程序设计第二章的脑图,内容也是非常浅显与简单.希望您看了我的博客能够给我一些意见或者建议.
- 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介
前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...
- 《JavaScript高级程序设计》读书笔记--前言
起因 web编程过程使用javascript时感觉很吃力,效率很低.根本原因在于对javascript整个知识体系不熟,看来需要找些书脑补一下,同时欢迎众网友监督. 大神推荐书籍 看了博客大神们推荐的 ...
- 1 《JavaScript高级程序设计》学习笔记(1)
欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 首先,我将从<JavaScript高级程序设计>这本JavaScript学习者必看的经典教 ...
随机推荐
- 洛谷5038 [SCOI2012]奇怪的游戏(二分+网络流+判断奇偶)
寒假的时候就听过这个题.但是一直没有写. qwq 首先,我们发现题目中的图是个网格图,然后每次可以将相邻两个格子加一. 很容易就想到是黑白染色.那么每次操作,就相当于同时操作一个白点,一个黑点. 我们 ...
- MC-BE基岩版服务器搭建与日常维护
有部分内容被csdn和谐,强烈建议移步我的个人博客以获得更好的排版和阅读体验: xzajyjs.cn. 目录 环境搭建 开始部署 日常维护 服务器的白名单机制 定时备份 服务器升级 服务器模组安装 搭 ...
- 初学python写个自娱自乐的小游戏
一.摘要 当编写完后的代码执行第一次后达到了目标的预期效果,内心有些许满足,但是当突发情况产生后,程序便不能正常运行,于是准备从简单的版本开始出发,综合考虑使用者的需求,和使用过程中会遇到的问题,一步 ...
- 【UE4 C++】Print、Delay、ConsoleCommand
基于UKismetSystemLibrary PrintString /** * Prints a string to the log, and optionally, to the screen * ...
- Java:内部类小记
Java:内部类小记 对 Java 中的 内部类,做一个微不足道的小小小小记 首先:内部类是指在一个外部类的内部再定义一个类.内部类作为外部类的一个成员,并且依附于外部类而存在的. 成员内部类 成员内 ...
- IC封装的热特性
ΘJA是结到周围环境的热阻,单位是°C/W.周围环境通常被看作热"地"点.ΘJA取决于IC封装.电路板.空气流通.辐射和系统特性,通常辐射的影响可以忽略.ΘJA专指自然条件下(没有 ...
- 为什么用于开关电源的开关管一般用MOS管而不是三极管
区别: 1.MOS管损耗比三极管小,导通后压降理论上为0. 2.MOS管为电压驱动型,只需要给电压即可,意思是即便串入一个100K的电阻,只要电压够,MOS管还是能够导通. 3.MOS管的温度特性要比 ...
- stm32直流电机驱动与测速
stm32直流电机驱动与测速 说实话就现在的市场应用中stm32已经占到了绝对住到的地位,51已经成为过去式,32的功能更加强大,虽然相应的难度有所增加,但是依然阻止不了大家学习32的脚步,不说大话了 ...
- Netty:Netty的介绍以及它的核心组件(二)—— ChannelFuture与回调
Callback 回调 一个 Callback(回调)就是一个方法,一个提供给另一个的方法的引用. 这让另一个方法可以在适当的时候回过头来调用这个 callback 方法.Callback 在很多编程 ...
- uvm_subscriber
subscriber是消费,用户的意思 uvm_subscriber主要作为coverage的收集方式之一 uvm_subscriber的代码非常简单,继承于uvm_component,再加上一个an ...