主要是介绍了ES5的语法,后面补充了ES6的不同之处
JavaScript三部分
核心(ECMAScript)
语言的基本组成部分
文档对象模型(DOM)
把页面映射成多层节点结构 XML 扩展HTML
提供访问和操作网页内容的方法和接口
浏览器对象模型(BOM)
与浏览器交互的方法和接口
< script>
async:下载脚本,外部脚本文件有效,不保证执行顺序
charset:src属性指定的字符集
defer:延迟到文档完全被解析后执行,外部脚本文件有效
src:包含执行代码的外部文件
type:脚本语言内容类型,默认值text/javascript
放在HTML文件底部
直接嵌入或包含外部文件
直接嵌入要指定type属性
\ 一对出现,函数内部出现记得用转义符号<\/script>
包含外部文件要指定src属性,\中不包含额外代码
\
放在\
基本概念(只记录了一些跟我印象中不同的点)
区分大小写
var创建变量是局部变量,省略后是全局变量
使用var和function声明的变量不可删除,因为被标记成不可配置了
delete不能删除全局变量,但是可以删除window对象上定义的属性
delete操作符跟直接释放内存无关,是断开引用间接完成的,对象的属性和数组成员才可以删除
这样的删除仍然占据内存空间,要设置null才能释放
除法操作不会自动向下取整
1/2==0.5(js)
1/2==0(java)
1.0/2.0==0.5(java)
- 数据类型
- Undefined
声明未初始化
typeof() - Null
- Boolean
true false 字面值 全小写
其他类型的空值、0、NaN、null、undefined转换后都是false - Number
NaN Number() parseInt() parseFloat() - String
转义字符\
不可变
toString() - object
new 跟Java蛮像的P35一些函数
typeof 返回数据类型 object null注意返回
- 操作符(意外跟C很像)
一元操作符自增自减前置后置
位操作符
~非&与|或^异或>>右移<<左移 >>>无符号右移
==会强制转换 ===不会强制转换
?: - 语句
if do-while while for for-in
label标识特定位置 break continue with设置作用域
switch - 函数
function 参数不限制个数和类型 通过argument对象访问元素
参数传递都是值传递
没有重载,后面覆盖 - 引用
instanceof - 作用域
没有块级作用域,if for语句中初始化变量在语句执行完之后依旧存在于语句外部执行环境
var是添加到最近的环境,没有就是添加到全局环境 - 垃圾收集
标记清除
引用类型
object类型
用new创建;对象字面量
很像字典,都是花括号里属性名:属性值
assign 静态方法将一个或者多个源对象中所有可枚举的自有属性复制到目标对象,并返回修改后的目标对象,当复制引用类型的属性时是浅拷贝,原型链上的属性和不可枚举的属性不能被复制Array类型
每一项可以保存任何类型的数据,动态调整数组大小
Array(数字)表示数组项目数量
Array(其他类型参数)创建包含那个值的只有一项的数组
方括号[]索引
isArray()
toString() 每个值的字符串形式,以逗号分隔
valueOf()
join()分隔符 转换成字符串
push() pop() stack
shift()移除第一个 unshift()前端添加 list queue
reverse()翻转
sort()比较字符串 默认UTF-16 码元值升序排序 小心15<5,从字符串上看 定义compare函数作为参数传入sort() 就地排序 不会复制
concat() 拼接字符串和多个数组的每一项 在内部元素为引用类型时是浅拷贝!
slice() 返回[开始索引,结束索引)中间的项,负数则用数组长度加上该数来确定位置 在内部元素为引用类型时是浅拷贝!
splice()- 删除 第一项位置,删除项数
- 插入 起始位置,删除项数,插入的项
- 替换 起始位置,删除项数,插入的项
indexOf() lastIndexOf() includes() find()查找位置,没找到返回-1
迭代方法 都不会改变原数组
every() some() filter() forEach() map()
reduce() reduceRight()
map()映射的一个小技巧,使用const arr=new Array(n).fill(0).map((_,i)=>i)让数组插入从0到n-1
也可以
const arr = […Array(n).keys()]
String类型
增删改查 都不是在原本字符串上修改,会创建新的副本
+或者concat()会创建新的字符串副本
slice() [开始索引,结束索引)前参数小于后参数否则返回空(负数加上字符串长度)
substr() [开始索引,开始索引+索引长度)
substring()[开始索引,结束索引)负数会看做0,参数可以任意顺序
trim()、trimLeft()、trimRight()删除字符串前后空格符,中间不删
repeat(n) 返回重复n次的拼接成果
padStart()、padEnd()复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件
toLowerCase()、 toUpperCase()
chatAt()返回给定索引位置的字符
indexOf()返回给定字符的索引位置,没有-1
startWith() 返回是否包含的布尔值
includes() 返回是否包含的布尔值
split()把字符串按照指定的分割符,拆分成数组中的每一项
match()返回正则表达式匹配后分割的数组 search()返回第一个匹配项第一个字符索引 replace(a,b) 把字符串中的a替换成b返回Date类型
RegExp类型 每一次要创建新的实例
g全局i不分大小写m多行
exec()- function类型
function 函数名(参数){语句;}
var 函数名=function(参数){语句;};
一个函数可以有多个名字
没有重载
arguments callee用于解除代码和函数名的耦合
this 先局部再全局
call() apply()
基本包装类型
Boolean Number String
不能添加属性和方法
charAt() charCodeAt() slice() substr() substring() indexOf() trim() toLowerCase() toUpperCase() match() search() replace() split() localeCompare() fromCharCode()
全局对象
URI编码方法
eval() 解析器 接受要执行的JS字符串
window对象
Math对象
类型转换时的小坑
Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true
隐式转换有自动转布尔值,自动转换字符串(+运算符),自动转换数值(除+运算符)
面向对象
创建对象的方式
使用对象字面量:
这是最简单和最常见的方式,直接在代码中定义对象。例如:1
2
3
4
5
6
7
8
9
10
11var person = {
name: 'John',
age: 30,
greet: function() {
console.log('Hello, my name is ' + this.name + ' and I am ' + this.age + ' years old.');
}
};
// 访问属性和调用方法
console.log(person.name); // 输出:John
person.greet(); // 输出:Hello, my name is John and I am 30 years old.使用构造函数:
构造函数允许你创建一个对象模板,然后通过 new 关键字调用构造函数,创建对象的实例。构造函数使用 this 关键字来指向新创建的对象。使用 this 关键字来创建属性或方法时,这些属性和方法会在使用 new 关键字创建对象时自动创建和声明,并绑定到实例对象上.new主要是先创建一个新的对象obj,将对象与构建函数通过原型链连接起来(_proto_指向。prototype),将构建函数中的this绑定到新建的对象obj上,根据构建函数返回类型作判断,如果是原始值则被忽略,如果是返回对象,需要正常处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
console.log('Hello, my name is ' + this.name + ' and I am ' + this.age + ' years old.');
};
// 创建实例
var person1 = new Person('Alice', 25);
var person2 = new Person('Bob', 30);
// 访问属性和调用方法
console.log(person1.name); // 输出:Alice
person2.greet(); // 输出:Hello, my name is Bob and I am 30 years old.使用工厂函数:
工厂函数是一种创建对象的函数,它类似于构造函数,但是不使用 new 关键字。它直接返回一个新的对象实例。例如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17function createPerson(name, age) {
return {
name: name,
age: age,
greet: function() {
console.log('Hello, my name is ' + this.name + ' and I am ' + this.age + ' years old.');
}
};
}
// 创建对象实例
var person1 = createPerson('Alice', 25);
var person2 = createPerson('Bob', 30);
// 访问属性和调用方法
console.log(person1.name); // 输出:Alice
person2.greet(); // 输出:Hello, my name is Bob and I am 30 years old.使用 ES6 中的类:
在 ES6(ECMAScript 2015)以及之后的版本中,引入了类的概念,可以更方便地创建对象。类的语法更类似于其他面向对象语言。例如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log('Hello, my name is ' + this.name + ' and I am ' + this.age + ' years old.');
}
}
// 创建实例
var person1 = new Person('Alice', 25);
var person2 = new Person('Bob', 30);
// 访问属性和调用方法
console.log(person1.name); // 输出:Alice
person2.greet(); // 输出:Hello, my name is Bob and I am 30 years old.使用 Object.create():
Object.create() 方法允许你基于一个现有的对象创建一个新的对象,可以指定新对象的原型。例如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17var personProto = {
greet: function() {
console.log('Hello, my name is ' + this.name + ' and I am ' + this.age + ' years old.');
}
};
var person1 = Object.create(personProto);
person1.name = 'Alice';
person1.age = 25;
var person2 = Object.create(personProto);
person2.name = 'Bob';
person2.age = 30;
// 访问属性和调用方法
console.log(person1.name); // 输出:Alice
person2.greet(); // 输出:Hello, my name is Bob and I am 30 years old.
对象有属性和方法
使用Object.defineProperty()来修改属性特性
- 数据属性
- Configurable
能否修改或删除属性特性 - Enumerable
能否for-in循环 - Writable
能否修改属性值 - Value
读写值
- Configurable
- 访问器属性
- Configurable
能否修改或删除属性特性 - Enumerable
能否for-in循环 - Get
读取 - Set
写入
使用Object.defineProperties()定义多个属性
- Configurable
工厂模式 在函数里面新创建一个对象
构造函数模式 把函数当做构造函数,在外部直接new对象
原型模式 一个函数有prototype属性,其他实例共享prototype里面的属性和函数,先找对象实例本身属性,再找原型对象的属性,实例和原型之间的连接是指针
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例都包含一个指向原型对象的内部指针
hasOwnProperty()
in
constructor()
可以随时为原型添加属性和方法,但不要重写
构造函数和原型模式的组合
动态原型模式 在构造函数里初始化原型函数
寄生构造函数 要用new的工厂模式
稳妥构造函数 不能用this
实现继承 原型链
搜索属性会沿着原型链往上
通过原型链实现继承的时候,不能使用对象字面量创建原型方法,因为会重写原型链
在每一个创建的子类对象上使用超类对象的call或者apply方法进行所有对象初始化
寄生组合式继承是最完美的继承方式
不必为指定子类型的原型而调用超类型的构造函数
函数表达式
- 函数声明:function 函数名(){}
函数声明可以置于调用语句之后 函数表达式:var 变量名=function(){};
此为匿名函数
要先赋值才可以调用
编写递归函数,函数内部用argument.callee代替函数名
函数第一次调用创建一个执行环境和作用域链,并把作用域连赋值给一个特殊的内部属性scope,然后初始化活动对象,外部,外部的外部,知道作用域链终点全局执行环境匿名函数
function(){}
如果是单独写匿名函数,要在外面加一个括号(function(){}),赋值/回调/返回时不加括号
然后单独要运行要在后面再加一个括号(function(){})(),这样可以模拟私有作用域
闭包,在另一个函数内部定义的函数会将外部函数的活动对象添加到它的作用域
闭包结构:
- 一个函数,里面有一些变量和另一个函数
- 外部函数里面的函数使用了外部函数的变量
- 外部函数最后把它里面的那个函数用return抛出去
闭包作用:
- 在函数外部可以读取函数内部的变量,创建私有变量
- 让这些变量的值始终保持在内存中,延长变量的生命周期
闭包只能取得包含函数中任何变量的最后一个值
解决方法是再嵌套一层函数,形成一个闭包
注意this的指向问题,可能闭包函数是在window作用域下执行的,this就不是指向外部函数而是window
内存泄漏问题,闭包引用外层对象,写一个变量保存对象副本,结束闭包后把对象置为null
多次声明同一变量,会对后续声明视而不见
在匿名函数中定义的任何变量都会在执行结束时被销毁
(function(){作用域})
1 | //因为var不是块级作用域,而setTimeout是会等当前作用域的函数调用栈清空了,才开始执行,所以for里面i会先加到6,才执行5个setTimeout,最后导致输出都是6 |
- setTimeout()
BOM
window对象
全局作用域中声明的变量和函数收拾window对象的属性和方法
尝试访问未声明的变量会抛出错误,但是可以查询window对象判断未声明的对象是否存在
窗口关系和框架
top对象指向最外层框架即浏览器窗口
parent对象指向当前框架的直接上层框架
没有框架的情况下parent=top=window
窗口位置和大小
moveTo(x,y)移动到实际位置
moveBy(x,y)移动量
resizeTo(x,y)设置大小
resizeBy(x,y)新的和原来的差
导航和打开窗口
window.open()
参数:URL,窗口目标,特性字符串,新页面是否取代浏览器中当前加载页的布尔值
window.setTimeout()执行代码和等待时间
clearTimeout()取消超时调用
setInterval()间隔时间重复执行
clearInterval()location对象
既是window的属性也是document的属性
location.search访问URL里面的内容
location.assign()传递URL
location.reload()无参重载/有参服务器重载navigator
plugins
registerContentHandler()screen对象
- history对象
DOM
把HTML或者XML文档描绘成多层节点结构
- Node类型
nodeType, nodeName, nodeValue, childNodes, NodeList, ownerDocument
appendChild(), insertBefore(),replaceChild(), cloneNode()(注意区别这里深复制是复制节点和子节点树,浅复制是只复制节点本身), normalize() - Document类型
window对象的一个属性,可以当做全局对象来访问
documentElement指向\
body指向\
title, URL, domain, referrer
getElementById()
getElementByTagName()返回的是同一个tag集合
HTMLCollection.namedItem()
HTMLCollection.getElementByNamed()
特殊集合P258
write(), writeln(), open(), close() - Element
attributes属性 get set remove
querySelector()接受CSS选择符
HTML5
getElementByClassName()
classList属性 add() contains() remove() toggle()
document.activeElement focus()
HTMLDocument属性
readyState
compatMode
head
charset
data-自定义数据属性
innerHTML
outerHTML
scrollIntoView()
简单描述一下就是一棵DOM树有节点和元素,还有自己对应的属性,可以创建节点然后添加到树里面,还可以直接设置元素的style属性
可以直接查询包含某些类或者ID的元素
遍历
NodeIterator
TreeWalker
事件
事件捕获阶段(capture phase)
处于目标阶段(target phase)
事件冒泡阶段(bubbling phase)
addEventListener(eventType, handler, useCapture)
removeEventListener(eventType, handler, useCapture)
useCapture是一个boolean用于指定是否在捕获阶段进行处理,一般设置为false在冒泡过程中执行处理函数,与IE浏览器保持一致
ES6语法
- 变量声明
let const var
可以创建块作用域
经常用const声明数组,并不是定义常量数组,定义的是对数组的常量引用,仍然可以更改数组元素 - 剩余…
…参数 动态参数
…variable
…数组 拆解数组 - apply(this,array) call(this,arg)
- 解构赋值
左侧定义了要取出的值
剩余属性位于末尾结束解构模式 - 箭头函数
去掉function,直接(参数)=>{}
不能用作方法
function定义的函数this随上下文变化而变化
箭头函数this始终指向定义函数的环境 - promise
Promise 构造函数是 JavaScript 中用于创建 Promise 对象的内置构造函数,接受一个函数作为参数,该函数是同步的并且会被立即执行,所以我们称之为起始函数。起始函数包含两个参数 resolve 和 reject,起始函数执行成功时,它应该调用 resolve 函数并传递成功的结果。当起始函数执行失败时,它应该调用 reject 函数并传递失败的原因。
then:用于处理 Promise 成功状态的回调函数。
catch:用于处理 Promise 失败状态的回调函数。
finally:无论 Promise 是成功还是失败,都会执行的回调函数。 - for in和 for of
数组遍历用for of,对象遍历用for in
for…in 语句以任意顺序迭代对象的可枚举属性。
for…of 语句遍历可迭代对象定义要迭代的数据。
可以for([key,value] of map) map类型
set类型
运行时 runtime
JavaScript是一门解释执行语言。这意味着源代码在执行前,无需编译为二进制文件。JavaScript引擎以一段程序的形式存在,负责将源代码翻译为机器码,并通过 CPU来执行翻译后的机器码
对比Java是先编译后执行的,能够将代码语法错误立即反馈给你。在JavaScript 中,只有当引擎尝试执行到有问题的那行代码时,才知道哪里出了问题。
在 Web 开发中,引擎并不会被开发者直接使用到。JavaScript 引擎是运行在一个环境中的,这个环境提供了代码在执行时能够利用的附加特性。
对比Java,Java 运行时环境(JRE)提供了访问所支持类库的方式,并且扮演了程序与操作系统之间的桥梁的角色。
JavaScript 运行时是指 JavaScript 代码执行的环境。Web 浏览器和 Node.js 是两种常见的 JavaScript 运行环境。
web浏览器
Node.js
事件循环机制
JavaScript 代码是在单一线程中执行的
JavaScript 代码分为立即调用代码和事件回调代码
事件循环机制是处理回调的机制。创建回调时,通常把它与一个特定事件关联起来。当特定事件发生时,运行时环境会将相关回调推入一个所谓的事件处理队列。事件循环机制会持续监控队列,并且按照先来后到的顺序执行其中的回调。
同步任务进入主线程,即主执行栈,异步任务进入任务/回调队列,主线程内的任务执行完毕为空,会去任务/回调队列读取对应的任务,推入主线程执行
微任务:一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前 Promise.then
执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中
当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完
async函数返回一个promise对象,await命令后面是一个 Promise对象,返回该对象的结果。如果不是 Promise对象,就直接返回对应的值,然后await会阻塞后面的代码(加入微任务队列)
v8
执行环境
this 关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象
函数中的this也只能在运行时才能最终确定运行环境
箭头函数再编译时就绑定了this指向
apply、call、bind
三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window
三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入
bind是返回永久改变this指向的函数,apply、call 则是立即执行,临时改变this指向一次
1 | Function.prototype.myBind = function (context) { |
原型
每个对象的proto都是指向它的构造函数的原型对象prototype的
构造函数是一个函数对象,是通过 Function构造器产生的,proto指向它的构造函数Function的原型对象prototype
原型对象本身是一个普通对象,而普通对象的构造函数都是Object,proto指向它的构造函数Object的原型对象prototype
Object的原型对象proto属性指向null,null是原型链的顶端
- 一切对象都是继承自Object对象,Object 对象直接继承根源对象null
- 一切的函数对象(包括 Object 对象),都是继承自 Function 对象
- Object 对象直接继承自 Function 对象
- Function对象的proto会指向自己的原型对象,最终还是继承自Object对象
ajax和axios
实现 Ajax异步交互需要服务器逻辑进行配合,需要完成以下步骤:
创建 Ajax的核心对象 XMLHttpRequest对象
通过 XMLHttpRequest 对象的 open() 方法与服务端建立连接
构建请求所需的数据内容,并通过XMLHttpRequest 对象的 send() 方法发送给服务器端
通过 XMLHttpRequest 对象提供的 onreadystatechange 事件监听服务器端你的通信状态
接受并处理服务端向客户端响应的数据结果
将处理结果更新到 HTML页面中
axios是通过Promise实现对ajax技术的一种封装
正则表达式
https://blog.csdn.net/weixin_52148548/article/details/123233957
ACM模式
- js node
1 | const rl = require("readline").createInterface({ input: process.stdin}); |
1 | const readline = require('readline'); |
一些奇怪的小问题
- 嵌套数组的声明问题
data = Array.from({length}, () => []);和data = new Array(length).map(() => []);和data = new Array(length).fill(0).map(() => []);
当使用 data = Array.from({length}, () => []); 时,它直接通过 Array.from 方法生成了一个长度为 length 的数组,并使用提供的映射函数 () => [] 来填充每个元素为一个空数组。这确保了每个元素都是独立的空数组。
在 data = new Array(length).map(() => []); 中,首先创建了一个长度为 length 的数组,但是数组中的元素都是 undefined。然后使用 map 方法对每个元素进行映射,但由于初始数组中的元素都是 undefined,map 方法对其不会执行任何操作。因此,最终的数组可能包含 undefined 元素,而不是独立的空数组。
对于 data = new Array(length).fill(0).map(() => []);,它首先使用 fill(0) 方法将数组填充为 0,以确保每个元素都有一个初始值。然后使用 map 方法对每个元素进行映射,将其转换为一个空数组。这确保了每个元素都是独立的空数组,并且所有元素都有一个初始值 0。