js 红宝书学习笔记精简版 第一至三章

注: 本文js代码均已在本地实现过,如有异常问题,请在评论区留言。ctrl+f 可搜索有效内容, 加粗为重点 蓝色字体 为重中之重

(一) 什么是js

1995 年,JavaScript 问世。
完整的 JavaScript 实是一门用来与网页交互的脚本语言,现包含以下几个部分(见图 1-1):
核心(ECMAScript) 由 ECMA-262 定义并提供核心功能。
文档对象模型(DOM):提供与网页内容交互的方法和接口。
浏览器对象模型(BOM):提供与浏览器交互的方法和接口。

在这里插入图片描述
JavaScript 的这三个部分得到了**五大 Web 浏览器(IE、Firefox、Chrome、Safari 和 Opera)**不同程度的支持。所有浏览器基本上对 ES5(ECMAScript 5)提供了完善的支持,而对 ES6(ECMAScript 6)和ES7(ECMAScript 7)的支持度也在不断提升。这些浏览器对 DOM 的支持各不相同,但对 Level 3 的支持日益趋于规范。HTML5 中收录的 BOM 会因浏览器而异,不过开发者仍然可以假定存在很大一部分公共特性。

(二) HTML 中的 JavaScript

JavaScript 是通过<script>元素插入到 HTML 页面中的。这个元素用于把 JavaScript 代码嵌入到HTML 页面中,跟其他标记混合在一起,也用于引入保存在外部文件中的 JavaScript
要包含外部 JavaScript 文件,必须将 src 属性设置为要包含文件的 URL。文件可以跟网页在同一台服务器上,也可以位于完全不同的域。
所有<script>元素会依照它们在网页中出现的次序被解释。在不使用 defer 和 async 属性的情况下,包含在<script>元素中的代码必须严格按次序解释
对不推迟执行的脚本,浏览器必须解释完位于<script>元素中的代码,然后才能继续渲染页面的剩余部分。为此,通常应该把<script>元素放到页面末尾,介于主内容之后及</body>标签之前。
src(常用)可选。表示包含要执行的代码的外部文件
type(常用)可选。代替 language,表示代码块中脚本语言的内容类型(也称 MIME 类型)。
defer 属性把脚本推迟到文档渲染完毕后再执行。推迟的脚本原则上按照它们被列出的次序执行。
async 属性表示脚本不需要等待其他脚本,同时也不阻塞文档渲染,即异步加载。异步脚本不能保证按照它们在页面中出现的次序执行。
crossorigin:配置相关请求的CORS(跨源资源共享)设置。默认不使用CORS。crossorigin="anonymous"配置文件请求不必设置凭据标志。crossorigin="use-credentials"设置凭据标志,意味着出站请求会包含凭据。//jsonp跨域相关
<noscript>元素,可以指定在浏览器不支持脚本时显示的内容。如果浏览器支持并启用脚本,则<noscript>元素中的任何内容都不会被渲染。

(三) 语言基础

JavaScript无论是变量、函数名还是操作符,都区分大小写

1 语法

严格区分大小写

1.1 标识符

就是变量、函数、属性或函数参数的名称。关键字、保留字、true、false 和 null 不能作为标识符。标识符组成规则:
  第一个字符必须是一个字母、下划线(_)或美元符号($)
  剩下的其他字符可以是字母、下划线、美元符号或数字
ECMAScript 标识符使用驼峰大小写形式,即第一个单词的首字母小写,后面每个单词的首字母大写(驼峰原则)

1.2 注释

分为单行注释和块注释

//单行注释以两个斜杠字符开头,在vs code中,快捷键为  ctrl + / 如:
// 单行注释 
//块注释以一个斜杠和一个星号(/*)开头,以它们的反向组合(*/)结尾,在vs code中,快捷键为  ctrl + shift + / 如:
/* 这是多行
注释 */
1.2 严格模式
//现代浏览器使用较少
"use strict";   	//在脚本开头加上这一行, 对整个脚本启用严格模式
function doSomething() {   	//把这个预处理指令放到函数体开头,单独指定一个函数在严格模式下执行
 "use strict";
 // 函数体
}
1.3 js语句

ECMAScript 中的语句以分号结尾

let sum = a + b // 没有分号也有效,但不推荐
let diff = a - b; // **加分号有效,推荐**

加分号有助于防止省略造成的问题便于开发者通过删除空行来压缩代码有助于在某些情况下提升性能

2 关键字

关键字有特殊用途不能用作标识符或属性名

//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
//为将来保留的所有词汇 
/*这些词汇不能用作标识符,但现在还可以用作对象的属性名。一般来说,最好还是不要使用关键字和保留字作为标识符和属性名,以确保兼容过去和未来的 ECMAScript 版本*/
enum
严格模式下保留:
implements package public
interface protected static
let private
模块代码中保留:
await

3 变量

ECMAScript 变量是松散类型的,意思是变量可以用于保存任何类型的数据
var、const 和 let可以声明变量, var 在ECMAScript 的所有版本中都可以使用,而 const 和 let 只能在 ECMAScript 6 及更晚的版本中使用。(但是条件允许es6,尽量还是用let,而不是var)

3.1 var声明

不初始化的情况下,var变量会保存一个特殊值 undefinedvar 还可以实现变量初始化,因此可以同时定义变量并设置它的值不同数据类型初始化的变量可以用一条语句来声明

var message; //要定义变量,可以使用 var 操作符(注意 var 是一个关键字),后跟变量名(即标识符,如前所述)
message = 100;
message = 'hi';//注: 个人理解 这种提升方式是有害的, 所以现在尽量都用let 去定义变量了

var声明提升把所有变量声明都拉到函数作用域的顶部。反复多次使用 var 声明同一个变量也没有问题。

3.2 let声明

let 声明的范围是 块作用域, 而 var 声明的范围是 函数作用域。块作用域是函数作用域的子集。

if (true) {
 var name = 'Matt'; console.log(name); // Matt
 var name
}
console.log(name); // Matt 
if (true) {
 let age = 26;console.log(age); // 26
 var age; // SyntaxError let声明过的变量,再次声明同一个变量报错
 let age; // SyntaxError 声明同一个变量报错
}
console.log(age); // ReferenceError: age 没有定义 // 它的作用域仅限于该块内部

let 与 var 的另一个重要的区别,就是 let 声明的变量不会在作用域中被提升

// 暂时性死区
console.log(name); // undefinedname 会被提升
var name = 'Matt';
console.log(age); //  age 不会被提升    ReferenceError:age 没有定义
let age = 26; 

在 let 声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出 ReferenceError。

//window 对象的属性
var name = 'Matt';console.log(window.name); // 'Matt'
let age = 26;console.log(window.age); // undefined

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

<script>
var name = 'Nicholas'; let age = 26;
</script>
<script>
// 假设脚本不确定页面中是否已经声明了同名变量   那它可以假设还没有声明过
var name = 'Matt';
// 这里没问题,因为可以被作为一个提升声明来处理   不需要检查之前是否声明过同名变量
let age = 36;
// 如果 age 之前声明过,这里会报错
</script>

var 可以进行条件声明 在使用 var 声明变量时,由于声明会被提升,JavaScript 引擎会自动将多余的声明在作用域顶部合并为一个声明。
let 不可以进行条件声明因为 let 的作用域是块,所以不可能检查前面是否已经使用 let 声明过同名变量,同时也就不可能在没有声明的情况下声明它。
因为var的声明提升导致for (var i = 0; i < 5; ++i){ setTimeout(() => console.log(i), 0)} 得出来的i值都是同一个值5;
let块级作用域,导致for (let i = 0; i < 5; ++i){ setTimeout(() => console.log(i), 0)} 得出来的i值是正常的0,1,2,3,4。

3.3 const 声明

const 的行为与 let 基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且不能修改 const 声明的变量

const age = 26;	age = 36; // TypeError: 不允许给常量赋值
const name = 'Matt';  const name = 'Nicholas'; // SyntaxError // const 也不允许重复声明
const name = 'Matt';  if (true) {const name = 'Nicholas';}	console.log(name); // Matt 	// const 声明的作用域也是块

const 声明的限制只适用于指向的变量的引用。换句话说,如果 const 变量引用的是一个对象,那么修改这个对象内部的属性并不违反 const 的限制。

const person = {};	person.name = 'Matt'; // ok 
3.4 声明风格及最佳实践

1. 不使用 var;
2. const 优先,let 次之

4 数据类型

ECMAScript 有 6 种简单数据类型(也称为原始类型): 字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。 Symbol(符号)是 ECMAScript 6 新增的。还有一种复杂数据类型叫 Object(对象)**。Object 是一种无序名值对的集合。

4.1 typeof 操作符

typeof 确定任意变量的数据类型。

let message = "some string";
console.log(typeof message); // "string"
console.log(typeof 95); // "number" 

注: 3种引用数据类型:对象(Object)、数组(Array)、函数(Function) 。严格来讲,函数和数组在 ECMAScript 中被认为是对象,并不代表一种数据类型。可是,函数也都有自己特殊的属性。为此, 被广泛的称为3种引用数据类型,就有必要通过 typeof 操作符来区分函数和其他对象。

4.2 Undefined 类型

Undefined 类型只有一个值,就是特殊值 undefined。当使用 var 或 let 声明了变量但没有初始化时,就相当于给变量赋予了 undefined 值。

let message;  //等价于 let message = undefined; 
console.log(message == undefined); // true 
console.log(message);  // undefined
console.log(age); // 包含 undefined 值的变量跟未定义变量是有区别的, 此处未定义变量  会报错。 

注:增加这个特殊值的目的就是为了正式明确空对象指针(null)和未初始化变量的区别。

4.3 Null 类型

Null 类型同样只有一个值,即特殊值 null。逻辑上讲,null 值表示一个空对象指针,这也是给typeof 传一个 null 会返回"object"的原因。

let car = null;		console.log(typeof car); // "object" 

undefined 值是由 null 值派生而来的,因此 ECMA-262 将它们定义为表面上相等,如下面的例子所示:

console.log(null == undefined); // true
console.log(null === undefined); // false  但不是完全相等

用等于操作符==比较 null 和 undefined 始终返回 true。但要注意,== 操作符会为了比较而转换它的操作数。===为全等。

.4.4 Boolean 类型

Boolean(布尔值)类型有两个字面值:truefalse
这两个布尔值不同于数值,因此 true 不等于 1,false 不等于 0。布尔值是区分大小写的,因此 True 和 False(及其他大小混写形式)是有效的标识符,但不是布尔值。

let found = true;
let lost = false; 
let message = "Hello world!";
let messageAsBoolean = Boolean(message);  //true   Boolean(一个假值) == false 
//if 等流控制语句会自动执行其他类型值到布尔值的转换
4.5 Number 类型

Number 类型使用 IEEE 754 格式表示整数浮点值(在某些语言中也叫双精度值)。不同的数值类型相应地也有不同的数值字面量格式。

let intNum = 55; // 十进制整数
/*于八进制字面量,第一个数字必须是零(0),然后是相应的八进制数字(数值 0~7)。
如果字面量中包含的数字超出了应有的范围,就会忽略前缀的零,后面的数字序列会被当成十进制数*/
let octalNum1 = 070; // 八进制的 56
let octalNum2 = 079; // 无效的八进制值,当成 79 处理
let octalNum3 = 08; // 无效的八进制值,当成 8 处理
//数值前缀 0x(区分大小写),然后是十六进制数字(0~9 以及 A~F)。十六进制数字中的字母大小写均可
let hexNum1 = 0xA; // 十六进制 10
let hexNum2 = 0x1f; // 十六进制 31

使用八进制和十六进制格式创建的数值在所有数学操作中都被视为十进制数值。
注: 由于 JavaScript 保存数值的方式,实际中可能存在正零(+0)和负零(-0)。正零和负零在所有情况下都被认为是等同的。

  1. 浮点值
    要定义浮点值,数值中必须包含小数点,而且小数点后面必须至少有一个数字。虽然小数点前面不是必须有整数,但推荐加上。
let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 = .1; // 有效,但不推荐

因为存储浮点值使用的内存空间是存储整数值的两倍,所以 ECMAScript 总是想方设法把值转换为整数。在小数点后面没有数字或为.0这一类的情况下,数值就会变成整数。

let floatNum1 = 1.; // 小数点后面没有数字,当成整数 1 处理
let floatNum2 = 10.0; // 小数点后面是零,当成整数 10 处理

对于非常大或非常小的数值,浮点值可以用科学记数法来表示。科学记数法用于表示一个应该乘以10 的给定次幂的数值。ECMAScript 中科学记数法的格式要求是一个数值(整数或浮点数)后跟一个大写或小写的字母 e,再加上一个要乘的 10 的多少次幂。精确度最高可达 17 位小数, 比如:

let floatNum = 3.125e7; // 等于 31250000 

但在算术计算中远不如整数精确。例如,0.1 加 0.2 得到的不是 0.3,而是 0.300 000 000 000 000 04。
2. 值的范围
ECMAScript 可以表示的最小数值保存在 Number.MIN_VALUE 中,多数浏览器中是 5e-324;最大数值保存在Number.MAX_VALUE 中,多数浏览器中是 1.797 693 134 862 315 7e+308。如果某个数值超出了 JavaScript 可以表示的范围,那么这个数值会被自动转换为一个特殊的 Infinity(无穷)值。任何无法表示的负数以-Infinity(负无穷大)表示,任何无法表示的正数以 Infinity(正无穷大)表示。
3. NaN
有一个特殊的数值叫 NaN,意思是“不是数值”(Not a Number),用于表示本来要返回数值的操作失败了(而不是抛出错误)。用 0 除任意数值在其他语言中通常都会导致错误,从而中止代码执行。但在 ECMAScript 中,0、+0 或-0 相除会返回 NaN。

console.log(0/0); // NaN
console.log(-0/+0); // NaN
如果分子是非 0 值,分母是有符号 0 或无符号 0,则会返回 Infinity 或-Infinity:
console.log(5/0); // Infinity
console.log(5/-0); // -Infinity
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false,10 是数值
console.log(isNaN("10")); // false,可以转换为数值 10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值 1
  1. 数值转换
    有 3 个函数可以将非数值转换为数值:Number()、parseInt()和 parseFloat()。
    Number()是转型函数,可用于任何数据类型。
布尔值,true 转换为 1,false 转换为 0。
数值,直接返回数值。
null,返回 0。
undefined,返回 NaN。
字符串,应用以下规则。
	如果字符串包含数值字符,包括数值字符前面带加、减号的情况,则转换为一个十进制数值。因此,Number("1")返回 1,Number("123")返回 123,Number("011")返回 11(忽略前面的零)。
	如果字符串包含有效的浮点值格式如"1.1",则会转换为相应的浮点值(同样,忽略前面的零)。
	如果字符串包含有效的十六进制格式如"0xf",则会转换为与该十六进制值对应的十进制整数值。
	如果是空字符串(不包含字符),则返回 0。
	如果字符串包含除上述情况之外的其他字符,则返回 NaN。
后两个函数主要用于将字符串转换为数值。
对象,调用 valueOf()方法,并按照上述规则转换返回的值。如果转换结果是 NaN,则调用toString()方法,再按照转换字符串的规则转换。

**parseInt()函数更专注于字符串是否包含数值模式。**字符串最前面的空格会被忽略,从第一个非空格字符开始转换。如果第一个字符不是数值字符、加号或减号,parseInt()立即返回 NaN。parseInt()第二个参数,按几进制解析。

let num1 = parseInt("1234blue"); // 1234
let num2 = parseInt(""); // NaN
let num3 = parseInt("0xA"); // 10,解释为十六进制整数
let num4 = parseInt(22.5); // 22
let num5 = parseInt("70"); // 70,解释为十进制值
let num6 = parseInt("0xf"); // 15,解释为十六进制整数
let num1 = parseInt("10", 2); // 2,按二进制解析
let num2 = parseInt("10", 8); // 8,按八进制解析
let num3 = parseInt("10", 10); // 10,按十进制解析
let num1 = parseInt("AF", 16); // 175
let num2 = parseInt("AF"); // NaN 

待完成

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这货可能是个前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值