JavaScript基础
第一章 JS基础语法
1、js定义
JS是基于对象和事件 ,运行在客户端 的、解释性 的脚本/编程语言
2、js组成部分
-
ES(ECMAScript) 语法规范
-
DOM (document Object Model) 文档对象模型---操作节点
-
BOM (Browser Object Model) 浏览器对象模型

3、JS的书写位置
- 厚朴培训\各阶段\JavaScript\2023.12.13\01-JS的书写位置.html
①行内
xml
<!-- 行内 写在开始标签内 少用 -->
<button onclick="alert('aaa')">
行内js
</button>
②内部js,写在script标签内
xml
<!-- 内部js--写在body 一定要放在要控制的节点下面 -->
<script>
js代码
</script>
<!-- 内部js--写在head 要获取节点一定要写加载函数 -->
<script>
window.onload = function() {
js代码
}
</script>
③外部js,要写一个js后缀的文件,用script标签引入
xml
<!-- 外部js写在head内,要获取节点一定要写加载函数 -->
<!-- 外部js,在body内引入,要写一个js后缀的文件,用script标签引入 -->
<!-- 要放在要控制的节点下面 常用 -->
<script src="js路径"></script>
4、变量
4.1 定义
用来存储数据的容器
4.2 声明和赋值
- 用var关键字声明,可以先声明后赋值,也可以同时声明和赋值,还可以同时声明多个变量用逗号隔开
javascript
ES6新增了 let const 关键字
let : 声明变量 (存数据的容器,里面的数据可以修改)
const:声明常量(存数据的容器,声明的同时必须赋值里面的数据不可以再重新赋值,
常量里存储的引用类型可以扩展属性和方法的,如果不希望它扩展可以用Object.freeze(对象)来冻结
const obj = Object.freeze({ a: 1 })
obj.b = 2 // b属性没有添加到对象中
console.log(obj);// { a: 1 }
暂时性死区
let 和const 声明的变量/常量 都必须先声明后使用,声明之前的区域被称为暂时性死区
原因:let、const声明的变量\常量 都没有变量、常量的声明提升
④同一个作用域内不可以重复声明
let a = 5;// 全局的作用域
const x = 10
function fn() {
let a = 5 // 局部作用域
}
if (1) {
let a = 10; //块级作用域
}
for (let i = 1; i <= 5; i++) { // i 是父级作用域
let i = 55 // i 是子级作用域
console.log(i);
}
console.log(i);
fn()
4.3 取名规范
- 由数字、字母、下划线(_)、美元符号($)来组成
- 不能以数字开头,不能用关键字、保留字
- 注意大小写
4.4 作用域/分类
全局变量:
- 声明在函数外,在js中都可以用,始终保存在内存中,用var声明的全局变量也是window的属性
局部变量
- 声明在函数内,只能在该函数内使用
- 调用函数时生效,未调用函数或函数调用完毕该变量销毁
5、数据类型
5.1 分类
① 值类型/简单数据类型/原始数据类型(6个)
- null 空
- undefined 未定义(变量的初始值)
- number 数字(整数、浮点数、NaN)
- boolean 布尔(true 真,false 假)
- string 字符串(凡是用引号引起来的内容)
- symbol 独一无二的值
②引用类型/复杂数据类型(2个)
- object 对象
- function 函数
两种类型的区别
scss
(1)值类型存在栈中 引用类型存在堆中
(2)读取
值类型直接从栈中读取 引用类型先从栈中读取地址 在根据地址去堆中找内容
(3)赋值
值类型,直接将内容赋值给新变量 赋值完之后新旧两个变量互相不影响
引用类型 新增加了一个指针 将值和地址都赋值给新变量 赋值完新旧两个变量指向同一个内容 互相影响
(4)传参
实参值类型,直接将内容赋值给新变量 赋值完之后新旧两个变量互相不影响
实参引用类型 将地址赋值给了形参 赋值完之后 形参和实参指向同一个内容 即新增了一个指针 相互影响
5.2 检测 用typeof数据变量名/数据
结果的数据类型都是字符串,具体有7种:
'undefined' 未定义 'number' 数字 'boolean' 布尔 'string' 字符串
'symbol' 独一无二的值 'object' 对象 'function' 函数
5.3 转换
- 厚朴培训\各阶段\JavaScript\2023.12.13\04-数据类型.html
分为强制转换和弱类型/隐式转换(浏览器自动转换的)
弱类型/隐式转换(浏览器自动转换的)
arduino
//减乘除运算遇到纯数字的字符串会将其转换成数字再计算
//加法里将布尔值、null等转换为数字
//"+"任意一边有字符串就会做字符串拼接
强制转换
csharp
// 转换成字符串
//1、String(数据)
//2、数据.toString()
//转换成布尔值
// 规律: null、undefined、NaN、0、false、空字符串('')返回false,其余为true
//Boolean(数据)
// 转换成数字型(重点)
// 1、Number(数据)
规律:
null、false、空字符串('')、空格字符串(' ')返回0
true 返回1
数字、纯数字的字符串返回数字本身
其余返回NaN
// 2、parseInt(数据) 取整
规律:
整数、浮点数、纯数字的字符串、以数字开头的字符串 都返回整数部分
其余返回NaN
// 3、parseFloat(数据) 取浮点数
规律:
整数、纯数字的字符串、以数字开头的字符串 返回浮点数
其余返回NaN
5.4 ES6新增的数据类型
①Symbol
②Set
③Map
5.5 ES6新增的迭代器/遍历器
js
1、定义/作用
给可迭代的对象提供统一的访问接口,有iterator接口/方法的数据都可以用for...of来遍历
2、迭代器对象
①它本身是一个对象,里面有next方法,next方法又会返回一个结果对象
②结果对象里有两个属性,value表示依次取出的值,done是个布尔值,表示迭代是否结束
3、封装迭代器函数
function makeIterator(arr) {
let nextIndex = 0; //存储下标
return { //迭代器对象
next() {
return nextIndex < arr.length ?
{ value: arr[nextIndex++], done: false }
:
{ value: undefined, done: true }
}
}
}
4、可迭代的对象
看有没有迭代器接口即有没有[Symbol.iterator]接口/方法
默认可迭代的对象:array对象、set对象、map对象、字符串对象
数组 可以用for、for...in、for...of来遍历
普通对象 只能用for...in来遍历,用for...of会报错,因为它没有迭代器接口,不是可迭代的对象
let people = {
name: 'lele',
[Symbol.iterator]() {
return makeIterator(Object.keys(people)); //for...of迭代返回的是属性名
// return makeIterator(Object.values(people)); //for...of迭代返回的是属性值
}
}
5、让一个普通对象变成可迭代对象,能用for...of遍历,给这个普通对象加迭代器接口即可
让所有的普通对象都能用for...of遍历,给所有的普通对象加迭代器接口即在Object的原型
对象上添加迭代器接口
6、封装一个判断某个数据是不是可迭代的函数
function isIterable(obj){
return typeof obj[Symbol.iterator] === 'function';
}
7、用class创建一个类,该类的实例对象都是可以迭代的,for...of遍历时返回键值对,且有判断对象实例是否可以迭代
class fun {
// 构造函数
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例共享的方法--原型上的方法
// 1、迭代器接口
[Symbol.iterator]() {
return this.makeIterator(Object.entries(this)); //返回键值对
// return makeIterator(Object.keys(this)); //for...of迭代返回的是属性名
// return makeIterator(Object.values(people)); //for...of迭代返回的是属性值
}
// 2、判断实例是否可迭代
isIterable() {
return typeof this[Symbol.iterator] === 'function';
}
// 3、迭代器函数
makeIterator(arr) {
let nextIndex = 0; //存储下标
return { //迭代器对象
next() {
return nextIndex < arr.length ?
{ value: arr[nextIndex++], done: false }
:
{ value: undefined, done: true }
}
}
}
}
5.6 生成器
js
// 1、定义/作用
// 生成器是一个返回值为迭代器的函数
// 2、写法
// function和函数名中加 * ,函数体内用yield关键字,
// 每次调用next方法执行到一个yield位置就暂停
// 在执行过程中遇到return 就会结束迭代,return的值会作为value,done的值为true
function * generator() {
yield 1;
yield 2;
yield 3;
}
let ite = generator(); //变量ite里存的是迭代器
console.log(ite.next()); //{value:1,done:false}
console.log(ite.next()); //{value:2,done:false}
console.log(ite.next()); //{value:3,done:false}
console.log(ite.next()); //{value:undefined,done:false}
// 3、优化迭代器
class fun {
// 构造函数
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例共享的方法--原型上的方法
// 1、迭代器接口--加*变成生成器
*[Symbol.iterator]() {
for(let key of Object.entries(this)) {
yield key;
}
// Object.entries(this); //返回键值对
// Object.keys(this) //返回的是属性名
// Object.values(people)//返回的是属性值
}
// 2、判断实例是否可迭代
isIterable() {
return typeof this[Symbol.iterator] === 'function';
}
// 3、迭代器函数
makeIterator(arr) {
let nextIndex = 0; //存储下标
return { //迭代器对象
next() {
return nextIndex < arr.length ?
{ value: arr[nextIndex++], done: false }
:
{ value: undefined, done: true }
}
}
}
}
6、运算符(js基础第二天)
6.1 算术运算符
css
+、-、*、/、%(取余、模)、++(自加)、--(自减)
要点:
+ 左右任意一边有字符串,+做字符串拼接,返回一个字符串
-、*、/、%(取余、模) 有隐式转换,数字取余的结果一定是一个非负整数
a++ 等价于 a = a + a,a-- 等价于 a = a - 1;
++、-- 在前表示先自加/减,后赋值
++、-- 在前表示先赋值,后自加/减
js中浮点数的计算会出现误差,可以用toFixed(位数)来保留几位小数,保留是会自动四舍五入且转换为纯数字的字符串

6.2 比较运算符
javascript
>、<、>=、<=、==(相等)、!=(不相等)、===(全等)、!==(不全等)
要点:
①比较时会做弱类型转换
②undefined、null、NaN 和 0 比较都是 false
③undefined 和 null,== 为 true,=== 为 false
④NaN == NaN 为false
⑤==只比较值,会做隐式转换,===比较值和类型
⑥比较运算符返回的结果一定是布尔值
6.3 逻辑运算符
scss
&&(且/与) ||(或) !(非/取反)
要点:
①&& 一假则假,全真才真---两边都是真,结果才是真,任意一边为假,结果就为假
①|| 一真则真,全假才假---两边都是假,结果才是假,任意一边为真,结果就为真
③取反返回的结果一定是布尔值
6.4 赋值运算符
css
= 右边赋值给左边
+= a+=5; 等同于 a = a + 5;
-= a-=5; 等同于 a = a - 5;
*= a*=5; 等同于 a = a * 5;
/= a/=5; 等同于 a = a / 5;
%= a%=5; 等同于 a = a % 5;
6.5 运算符优先级
diff
括号一元乘除余,加减比较等不等,先且后或再赋值
()
++ -- !
* / %
+ -
> < >= <=
== === != !==
&&
||
=
第二章 程序结构
1、定义
又叫流程控制,是指代码执行的顺序
2、分类
2.1 顺序结构
代码从上往下依次执行,绝大多数都是该结构
2.2 分支/选择结构 if switch
二选一
arduino
①if...else
if(条件) {
条件为真执行的代码
}else{
条件为假执行的代码
}
②三元运算符/条件运算符? : 适用于执行的代码只有1行
条件 ? 条件为真执行的代码:条件为假执行的代码
多选一
arduino
①if...else if...else
if(条件1) {
条件1为真执行的代码
}else if(条件2){
条件2为假执行的代码
}else if(条件3){
条件3为假执行的代码
}
....
else {
以上条件都为假执行的代码
}
②switch
switch(表达式) {
case 值1 :
表达式 === 值1为true时执行的代码;
break;
case 值2 :
表达式 === 值2为true时执行的代码;
break;
case 值3 :
表达式 === 值3为true时执行的代码;
break;
....
default:
表达式和以上三个值都不相等执行的代码
break;
}
javascript
isNaN(数据)判断数据是不是一个非数字,时非数字返回true,不是返回false,一般与分支结构搭配使用
例如:isNaN(5) //false 5是一个非数字,对吗? //不对
isNaN('a') //true a是一个非数字,对吗? //对
3、循环结构 for for...in while do...while
js
//定义
在满足条件的情况下,进行重复的操作
//优点
解决重复操作,减少代码编写量,使代码结构清晰,增强代码的可读性
//分类
①for
语法结构:
for(初始条件;判断条件;迭代条件){
重复执行的代码
}
初始条件:从哪里开始
判断条件:到哪里结束--不满足判断条件时结束
迭代条件:下一次从哪里开始
②for...in 遍历对象
for(var key in 对象名) {
}
//for in的遍历,变量修改无效即不能更改下一次迭代的变量的值
③while 不能确定循环的次数时用
语法结构:
初始条件;
while(判断条件){
重复执行的代码;
迭代条件;
}
使用场景:不能确定循环的次数时用while
能用for循环实现的需求都能用while实现,能用while实现的需求for循环不一定能实现
④do...while 先执行一次,再判断,适用至少要执行一次的不确定循环的次数的场景
语法结构:
初始条件;
do{
重复的执行代码;
迭代条件
}
while(判断条件)
⑤跳转语句
break 结束循环,可以用在循环、switch判断、函数
continue 跳过本次循环,后面继续,只能用于循环
//嵌套
for、while、do...while 可以相互嵌套,一般只用两层,称为双层循环
外层循环的变量走一个,内层循环的变量从头到尾走一遍
断点调试

第三章 对象
1、定义
由属性 和方法 组成的无序 的键值对集合----本质 存数据的容器
- 属性:特征
- 方法:能做什么
2、内置对象
- js封装好的,可以直接使用的对象,常用的内置对象有:Array--数组、Date--日期、Math--处理数学任务、String--字符串
2.1 Array--数组
(1)定义
用单独的变量名来存一系列数据的容器,里面的内容叫元素,可以是任意的数据类型
(2)创建
-
new Array() new调用构造函数
-
\] 字面量---语法糖 常用
-
数组名[下标] 下标是从0开始----单个
-
一次性读取数组中多个 元素----循环/遍历
kotlin
法1:因为数组是内置对象,可以用for...in来遍历,break、continue依然可用
可以根据需求控制下标来读取对应的元素,若下标对应的元素不存在,默认值是undefined
法2:因为数组有length属性,可以用for来遍历
(4)长度属性
数组名.length 表示数组中元素的个数,从1开始,可读可写
(5)数组分类
- 密集数组:元素之间无间隔---每个下标对应的元素都有数据 [1,2,9,5,7] for和for...in遍历一样
- 稀疏数组:元素间有间隔---有的下标对应的元素没有数据 [1,,,,,,4,5] for会遍历每个元素,没有数据的元素返回undefined,for...in只读取有数据的元素
(6)数组的方法
javascript
// 1、会改变原数组的方法--7个
(1)增
// 法1:加在末尾 数组名.push(要加的元素1个或多个,用逗号隔开,依次添加) 返回数组的新长度
//法2:加在开头 数组名.unshift(要加的元素1个或多个,用逗号隔开,依次添加) 返回数组的新长度
// 法3:加在指定的位置 数组名.splice(下标,0,要加的元素1个或多个用逗号隔开依次添加) 返回1个空数组
(2)删
// 法1:删末尾 数组名.pop() 返回被删除的元素
// 法2:删开头 数组名.shift() 返回被删除的元素
// 法3:删指定的位置的 数组名.splice(下标,删除的个数) 返回1个数组,里面的元素是被删除的元素
(3)改
// 方法1:数组名[下标] = 新的值
// 方法2:数组名.splice(下标,要改写的个数,改写的新值) 返回1个数组,里面的元素是被改写的元素
(4)倒序 返回倒序后的数组
数组.reverse()
(5)排序
①数组名.sort(); 按照0-9,a-z的顺序,先对首位进行排序,首位相同对第二位排序,以此类推
②数组名.sort(function(a,b){return a-b}); 对纯数字的数组从小到大
数组名.sort(function(a,b){return b-a}); 对纯数字的数组从大到小
// 2、不会改变原数组的方法--5个
(1)合并
数组名1.concat(数组名2,数组名3...) 返回一个新数组,里面的元素是和并的数组,注意顺序
(2)拼接
拼接 数组名.join('分隔符') 返回一个字符串 分隔符不写默认是逗号
(3)截取
数组名.slice(开始的下标,结束的下标) 返回一个新数组,里面的元素就是按照下标截取的内容,包前不包后
(4)查找 是===判断,注意数据类型,不会进行弱类型转换
数组名.indexOf(要找的元素,开始找的下标) 参数2选写,默认是0,如果找到了返回找到的该元素的下标,没找到返回-1
(5)从末尾往前查找 是===判断,注意数据类型,不会进行弱类型转换
数组名.lastIndexOf(要找的元素,开始找的下标) 参数2选写,默认是数组的length-1,如果找到了返回找到的该元素的下标,没找到返回-1
3、静态方法 Array构造函数的方法
(1)Array.isArray(数据)
判断括号里的数据是不是数组,如果是返回true,不是返回false,一般和分支结构搭配使用
(2)Array.from(数据)
将数据生成一个数组,如果数据是有length属性如字符串或可迭代时会将数据分割为数组的元素,否则返回空数组
(3)Array.of(参1,参2,参3...)
生成一个数组,将每个参数做为数组的元素,不传参返回空数组
kotlin
4、实参为函数的方法,该实参函数称为回调函数,该方法称为主函数
语法结构(1-5):
①数组名.方法名(callbackFn,thisVal)--参1(是回调函数)必须写,参2(this的指向)选写
②callbackFn:可以是具名函数的函数名,也可以是匿名函数,参1是数组的每个元素,参2是每个元素的索引,参3是数组对象选写
③thisVal:没传,this 指向 window;传了实参,this 指向 该实参,如果实参是值类型会变成包装类;如果传入的实参是undefined和null,this指向window
④作用:将数组中的每一项都执行一次回调函数,类似for/for...in 但不能用跳转语句break和contiue
1、数组名.forEach(callbackFn,thisVal)
返回值:undefined
2、数组名.map(callbackFn,thisVal)
返回值:新数组(注意map的回调函数里一定要写return)
3、数组名.filter(callbackFn,thisVal) 过滤
返回值:新数组(里面的元素只能是满足条件的,而map的返回值和原数组的长度一致,不满足条件的项会返回undefined)
4、some方法同forEach,区别是some的返回值是布尔值,数组的元素都不满足条件返回false,任意一个满足条件返回true
5、every方法同forEach,区别是every的返回值是布尔值,都满足条件返回true,任意一个条件不满足返回false
语法结构(6-7):
①数组名.方法名(callbackFn,initVal) 参1(是回调函数)必须写,参2(是初始值)选写
②作用:将数组中的每一项都执行一次回调函数,返回计算后的值
③callbackFn:可以是具名函数的函数名,也可以是匿名函数。参1是初始值必写,参2是数组的每个元素必写,参3是每个元素的索引选写,参4是数组对象选写
④initVal:没传,是数组的第1个元素,传了就用传的实参
6、数组名.reduce(callbackFn,initVal)
7、数组名.reduceRight(callbackFn,initVal)
reduceRight从右往左去数组中每一项计算,返回计算后的值
sql
拓展
数组名.filter(Boolean); 传入Boolean函数作为参数,将数组中的每个元素作为参数进行求值,空字符串在转换为布尔值时会被视为false,而其他非空字符串会被视为true
(7)扩展运算符
js
// 1、扩展运算符
// 定义/作用:将数组或对象里的内容扩展出来为一个序列
// 可以用于合并数组
//可以将数组和可遍历的对象装换成真正的数组
//数组的浅拷贝
let arr = [1, 2, 3, [4, 5]]//数组的浅拷贝
let arrC = [...arr]
function fn() {//可以将数组和可遍历的对象装换成真正的数组
console.log(arguments);
let arr = [...arguments]
console.log(arr);
}
fn(7, 8, 9)
(8)代理---ES6新增
javascript
// 1、定义
// 代理(proxy)是指在目标对象前架设一层拦截,外界访问目标对象的信息是代理对象的过滤和修改过的
// 2、语法
// ①创建代理对象
// Proxy是构造函数,new调用实例化代理对象
// 传两个参数,第1个参数是目标对象,第2个参数是拦截对象
// ②拦截读取的函数 get方法
// ③拦截设置的函数 set方法
// 场景:房主要卖房,找中介帮忙,买房的人要通过中介来买房
// 目标对象 代理对象 外界
let owner = {
name:'lele',
address:'山湖间五栋2单元301',
size:'100m²',
price:120,
phone:13546816940
}
let p1 = new Proxy(owner,{
get(target,key){
if(key == 'price'){
return owner[key]+=5;
}else if(key == 'phone'){
return '我们来联系房主';
}else if(key == 'name'){
return '张大帅';
}else{
return owner[key];
}
},
set(owner,key,val){
// if(key == 'price' && val < 130 && val >110){
// owner[key] = val;
// }
return false;
}
})
// 外界
p1.price = 125;
console.log(p1.price);
console.log(p1.price);
// console.log(p1.phone);
2.2 String--字符串
(1)定义
用引号引起来的文本
(2)创建
- new String() new调用构造函数,创建的数据类型是Object
- ' '或" " 字面量---语法糖 常用,创建的数据类型是String
(3)读取元素
-
字符串名[下标] 下标是从0开始----单个
-
一次性读取字符串中多个 字符----循环/遍历
javascript
法1:new String 创建的是字符串,可以用for...in来遍历,break、continue依然可用
可以根据需求控制下标来读取对应的元素,若下标对应的元素不存在,默认值是undefined
法2:因为字符串有length属性,可以用for来遍历


(4)长度属性
数组名.length 表示字符串中字符的个数,从1开始,只可读,一个汉字、字母、空格、数字、字符都占1个长度
(5)方法
scss
字符串具有稳定性,所有的方法都不会改变原字符串
1、改大小写,只对字母有效,整体改写 //常用于搜索内容大小写转换---不区分大小写/模糊搜索
① 字符串名.toUpperCase() 改为大写
② 字符串名.toLowerCase() 改为小写
2、截取字符/字符串 重点掌握①②
①字符串名.charAt(索引) 返回索引对应的字符,如没有该索引返回undefined 截取单个字符
②字符串名.slice(开始索引,结束索引) 返回字符串,包前不包后,参数2不写,默认到字符串的length结束
③字符串名.substr(开始索引,结束索引) 返回字符串,包前不包后,参数2不写,默认到字符串的length结束
④字符串名.substring(开始索引,结束索引) 返回字符串,包前不包后,参数2不写,默认到字符串的length结束
3、查找字符 返回索引或-1 严格区分大小写
①查找
字符串.indexOf(要找的字符串/字符,开始找的下标) 参数2选写,默认是0,如果找到了返回找到的该字符串/字符的下标,没找到返回-1
②从末尾往前查找
字符串.lastIndexOf(要找的字符串/字符,开始找的下标) 参数2选写,默认是字符串的length-1,如果找到了返回找到的该字符串/字符的下标,没找到返回-1
4、重复
字符串名.repeat(次数)
5、将字符串分割为数组
字符串名.split('分割符') //分割符不写默认将字符串整体作为数组的1个元素,写了分割符以该字符切割
例如:var str = 'd g sd'; str.split('');//['a','g','sd']
6、去除首尾空格
字符串名.trim()
(6)正则
less
1、定义
匹配模式用于匹配字符串
2、创建
①字面量 /正则内容/修饰符 常用 修饰符:i不区分大小写 g全局匹配
②new RegExp(正则内容)
3、匹配字符串
正则.test(字符串) 匹配成功 返回true 反之返回false
字符串.search(正则) 匹配成功 返回下标>=0的整数 反之返回-1
字符串.replace(/正则/g,用来替换的内容) 将匹配正则的内容替换为新内容 g表示全局匹配即全部替换
'a1b2c3'.replace(/\d/g,'k'); 返回'akbkck'
4、常用字符
① ^ 开头
② $ 结尾
③ | 二选一 x | y 匹配x或y
④ [] 多选一 连续范围加- 不包含该范围[]里面加^
[abc]匹配a或b或c
[a-z]匹配任意一个小写字母
[A-Z]匹配任意一个大写字母
[0-9]匹配0-9的任意数字
[^0-9]不匹配0-9的任意数字
⑤ \d 等价[0-9] 匹配0-9的任意数字
\D 等价[^0-9] 不匹配0-9的任意数字
\w 等价[a-zA-Z0-p] 匹配a-z、A-Z、0-9的任意数字
\d 等价[^a-zA-Z0-p] 不匹配a-z、A-Z、0-9的任意数字
5、常用量词
* 任意次 >=0
+ 至少1次 >=1
? 0次或1次 ==0 || ==1
{n} n次 ==n
{n,}至少n次 >=n
{n,m} n-m次 >=n && <=m
(7)表单验证
ini
1、表单事件
onfocus 获取焦点/光标
onblur 失去焦点/光标
onchange 域的内容改变
2、修改节点里的内容
节点.innerText = '新的文本内容'
节点.innerHML = '新的内容,文本标签都可以'
3、修改节点的样式,多条样式可以放在类名里
节点.className = '类名'
2.3 Math--处理数学任务
(1)、定义
是一个对象,用于处理各种数学任务
(2)属性
javascript
Math.PI 返回圆周率
(3)方法
scss
(1)取整
①Math.ceil(x) 上舍入,整数返回本身,正的浮点数取整加1,负的浮点数取整
②Math.floor(x) 下舍入,整数返回本身,正的浮点数取整,负的浮点数取整减1
③Math.round(x) 四舍五入,整数返回本身
正的浮点数第一位小数小于5取整,反之加一;
负的浮点数第一位小数小于5取整,反之取整减1
(2)取最大值
①MAth.max(x,y...) 返回最大值
②Math.min(x,y...) 返回最小值
(3)取绝对值
Math.abs(x) 正数和0返回本身 负数返回相反数
(4)计算n次方
Math.pow(x,n) x的n次方
(5)随机数
Math.random() 返回0-1之间的浮点数,能渠道0,不能取到1
2.4 Date--处理日期和时间
(1)定义
用于处理日期和时间的内置对象构造函数
(2)创建
javascript
①当前日期对象
var today = new Date();
②指定的日期对象---过去的或将来的 给构造函数传参
var choic = new Date('2021/10/5/17:40:20') //过去的时间
var choic = new Date('2055/10/5/17:40:20') //将来的时间
(3)方法
vbscript
set是设置,get是获取
①年 日期对象.getFullYear() 返回当前的年份,4位整数
②月 日期对象.getMonth() 返回0-11
③日 日期对象.getDate() 返回1-31的整数
④星期 日期对象.getDay() 返回0-6的整数 0指的是星期天,1是星期一,以此类推
⑤时 日期对象.getHours() 返回0-23的整数 24小时制
⑥分 日期对象.getMinutes() 返回0-59的整数
⑦秒 日期对象.getSeconds() 返回0-59的整数
⑧毫秒 日期对象.getTime() 返回较大的整数
3、自定义对象
3.1 创建(2023.12.20/01-对象.html)
javascript
1、字面量 {} {}里面放键值对,键的数据类型是字符串,值可以是任意的数据类型 创建单个对象 常用
2、new 构造函数
①new Object() 很少有
②new 自定义的构造函数名(传参) 用来创建一系列对象 常用
3.2 属性的增删改查
arduino
// 1、增
// ①对象名.属性名 = 属性值
// ②对象名['属性名'] = 属性值 属性名为数字只能用②
// 2、删
// ①delete 对象名.属性名 返回布尔值,能删返回true,如删除对象的属性(不管属性有没有),不能删返回false
// ②属性名为数字就用 delate 对象名['属性名']
//3、改写
// ①对象名.要改写的属性名 = 新的属性值 属性名为数字就只能用[]
// 原理:属性名相同,属性值不同时,后一个覆盖前一个
// 4、查看属性值 对象名.属性名 属性名为数字就只能用[] 属性不存在返回undefined
// 查看多个 用for...in遍历
3.3 方法
定义:属性值为函数的属性
查看:对象名.方法名
调用:对象名.方法名(有参数要传参)
第四章 函数
1、定义
- 为了实现特定功能 的代码块 ,可以重复调用 //函数具有较好的复用性
2、使用
2.1 声明
基本结构
js
//1、独立声明的函数
function 函数名 (参数) { 执行代码块 }
/*function 声明函数的关键字
函数名 可以选写 命名规范同变量
参数:可以选写 根据项目需求来写
执行代码块:实现特定的功能*/
//2、函数表达式
var 变量名 = function (参数) { 执行代码块 }
2.2 调用
js
//1、独立声明的函数 可以先声明后调用,也可以先调用后声明
调用:函数名(有参数要传参)
//2、函数表达式 只可以先声明后调用
调用:变量们(有参数要传参)
注意:函数一定要调用才生效,函数声明在哪里不重要,在哪里调用很重要
3、分类
(1)有无函数名
-
具名/有名函数
独立声明的函数一定要取函数名
-
匿名函数
①函数表达式
②事件触发时 = 右边的函数
一定有 = 符号
(2)有无参数
- 无参函数
scss
声明时()里没有参数
- 带参/有参函数
js
声明时()里有参数,参数及其个数取决于项目需求
①形参:声明时()里的参数,本质是变量,没传实参默认是undefined
②实参:调用时()里的参数,本质是确定的值
③传参方向:将实参传给形参
④传参顺序:一一对应(实参1传给形参1,实参2给形参2.......)
⑤传参个数:尽量保持一致(有几个形参就传几个实参)
//实参列表 arguments 是一个伪数组,typeof arguments返回'object'
//能将实参依次放在里面,读取arguments[下标],也可以用for遍历,但不能用数组的方法
//可以在函数声明内:用arguments[下标] = 新的值 来修改实参的值
(3)有无返回值
- 返回值为默认值undefined的函数
kotlin
函数声明内没有 return 关键字
- 带特定返回值的函数
kotlin
喊声声明内最后一行一定要 return 关键字
当函数的调用结果后续要进一步处理就一定要放返回值
return后默认返回一个值,要返回多个值,用数组或者对象(常用) 具体见:2023.12.25/01.html的计算两数和
4、封装
将相同的逻辑复制到函数中,不同的内容提取为参数,调用时传参
第五章 DOM操作
1、DOM基础操作
1.1 获取节点
js
1、使用js内置的方法
document.getElementById('id名') 获取一个具体的节点
document.getElementsByClassName('类名') 获取一个集合,获取具体节点 集合名[下标]
document.getElementsByTagName('标签名') 获取一个集合,获取具体节点 集合名[下标] 范围大 整个页面
父节点.getElementsByTagName('标签名') 获取一个集合,获取具体节点 集合名[下标] 范围小 父节点里面
document.getElementsByName('name名') 获取一个集合,获取具体节点 集合名[下标]
document.querySelector('css选择器') 获取一个具体的节点 是满足该css选择器的第1个节点
document.querySelectorAll('css选择器') 获取一个集合,获取具体节点 集合名[下标]
2、通过层级关系来获取
子节点.parentNode 获取父节点,要获取祖先就不断往上找即链式写法增加parentNode,最终找到document文件,再往上是null
父节点.firstElementChild 获取父节点里的第1个标签子节点
父节点.lastElementChild 获取父节点里的最后1个标签子节点
弟节点.previousElementSibling 获取兄节点
兄节点.nextElementSibling 获取弟节点
1.2 属性操作
arduino
1、获取属性值
①节点.属性名 类名用className
②节点.getAttribute('属性名') name的值只能用它获取
2、设置属性或修改属性值
①节点.属性名 = '属性值' 类名用className
②节点.setAttribute('属性名','属性值')
1.3 内容操作
ini
1、获取
①节点.innerText 只获取文本内容
②节点.innerHTML 获取标签和文本
2、设置和修改
①节点.innerText = '新的文本内容'
②节点.innerHTML = '新的标签和文本'
会覆盖原来的内容,可以赋空字符串用来清空里面的内容,要保留原来的内容在赋值时把原来的内容重新写一遍
1.4 样式操作
csharp
1、行内样式 弊端:①结构和表现未分离,不利于维护;②行内样式优先级高,类样式回不去
①单条 节点.style.样式名 = 样式值 //有'-'的样式名改为驼峰命名
②多条 节点.style = '样式名1:样式值1;样式名2:样式值2;样式名3:样式值3;.......'
2、通过类名来设置样式
①节点.className = '类名' 多个类名之间用空格隔开 如:节点.className = 'one two three'
②节点.setAttribute('class','类名') 多个类名之间用空格隔开
③节点.classList.add('类名') 添加类名 追加的效果不会覆盖
④节点.classList.remove('类名') 移除指定的类名
⑤节点.classList.toggle('类名') 切换该类名,如果有就移除,没有就添加
⑥节点.classList.replace('旧类名','新类名') 替换,用新的换旧的
⑦节点.classList.contains('类名') 节点中有没有该类名,有返回true,没有返回false
2、DOM节点操作
2.1 创建节点
ini
①document.write('完整标签'); 往文档里添加 很少用 了解
②节点.innerHTML = '完整标签'; 往节点添加子/后代标签 掌握
③document.createElement('标签名'); 创建该标签名的空标签,需要用添加的方法加到页面中才能显示 掌握
④节点.cloneNode(); 克隆该节点 掌握
()里不传参只克隆节点标签本身,传true表示克隆节点及里面的内容,克隆好的节点需要用添加的方法加到页面中才能显示
2.2 添加节点
ini
①父节点.appendChild(子节点);
②父节点.insertBefore(要插入的节点,指定节点); 要插入的节点插入后是指定节点的兄节点
2.3 删除节点
ini
(1)清空节点里的内容,节点标签本身保留
①节点.innerText = '';
②节点.innerHTML = '';
(2)删除父节点内指定子节点
父节点.removeChild(指定子节点);
(3)删除节点本身及内容
节点.remove();
2.4 替换节点
scss
父节点.replaceChild(用来替换的节点/新节点,被替换的节点/旧节点)
3、DOM事件操作
3.1 事件三要素
(1)事件源:操作的dom节点 获取节点
(2)事件内行:绑定的事件名 绑定事件
(3)处理程序:触发时间后执行的函数 执行函数
3.2 常用的事件
swift
(1)鼠标事件 11个
单击左键 onclick
双击左键 ondblclick
右键菜单 oncontextmenu
滚轴/滚动条 onscroll
移入 onmouseover
移出 onmouseout
移动 onmousemove
按下 onmousedown
松开 onmouseup
进入 onmouseenter
离开 onmouseleave
(2)键盘事件 2个
按键按下 onkeydown
按键松开 onkeyup
(3)表单事件 5个
获得焦点/光标 onfocus
失去焦点/光标 onblur
域的内容改变 onchange
重置 onreset
提交 onsubmit
(4)界面/UI事件
加载界面/图片 onload
界面大小变化 onresize
3.3 event当前时间对象
vbnet
定义:
事件触发后,储存事件相关信息的集合
写法:
事件源.事件名 = function(){
console.log(e); //e 等价于event
执行代码
}
常用属性和方法:
①事件源/DOM节点
event.target
②事件类型/事件名
event.type 返回的是事件名不带on
③鼠标位置
event.clientX 横坐标
event.clientY 纵坐标
④按键
event.key 返回按键的字符串
event.keyCode 返回按键码数字
方法:
阻止默认行为 event.preventDefault() 还可以在函数最后加return false;
阻止冒泡 event.stopPropagation
3.4 绑定事件的方式
scss
1、行内绑定事件,调用函数,注意函数必须是全局函数
<div onclick='fn()'>11</div>
2、节点.事件名 = 处理函数
①pNode.onclick = function(){执行代码} =右边是匿名函数
②pNode.onclick - fn 右边是具名函数的函数名,该函数只能是无参函数
function fn(){
执行代码
}
3、事件监听 节点.addEventListenet('事件名不带on',处理函数,布尔值选传)
事件监听的优点:
①同一个节点绑定相同事件,执行不同的处理函数时,都能执行
②用事件监听绑定的事件可以移除 节点.removeEventListener('事件名不带on',处理函数)
3.5 事件流
lua
1、定义
页面接收事件的顺序
2、分类
①事件冒泡 从内层节点往外层节点冒泡---从内往外 浏览器默认支持 阻止冒泡 event.stopPropagation()
②事件捕获 从外层级节点往内层节点捕获---从外往内 事件监听来绑定,第3个参数传true
3、DOM二级事件流---这个节点上既有冒泡又有捕获
先捕获-->目标节点-->冒泡节点
3.6 事件委托
javascript
1、定义
利用事件冒泡的原理,将事件绑定给父级(this),操作子级节点(event.target),通过冒泡触发父级节点上绑定事件
2、优点
①事件委托效率更高(运行速度快、易于维护)
开始计时:console.time('记号') 结束计时:console.timeEnd('记号') 统计代码执行花费的时间
②对于动态添加的子级节点事件依然有效
第六章 BOM操作
1、定义及组成
浏览器对象模型,核心对象是window对象,包含history、location、document
2、window的属性和方法
js
1、属性
console.log(window.innerHeight); //窗口文档高度,返回一个数字没有单位
console.log(window.innerWidth); //窗口文档宽度,返回一个数字没有单位
console.log(window.outerHeight); //窗口高度,返回一个数字没有单位
console.log(window.outerWidth); //窗口宽度,返回一个数字没有单位
console.log(window.name); //返回window的名称,没有取名默认是空字符串
console.log(window.pageXOffset); //离左上角 x的距离,返回一个数字没有单位
console.log(window.pageYOffset); //离左上角 y的距离,返回一个数字没有单位
2、方法 window的方法,可以省略window
① 三种弹窗---会阻塞进程
window.alert(111) //等价于alert(111) 警示框 只有一个确定按钮,点确定返回undefined
prompt() //输入框 有一个input框,一个确定一个取消按钮,点确定返回input里的内容,点取消返回null
confirm() //确认框 一个确定一个取消按钮,点确定返回true,点取消返回false
② 2个定时器/计时事件
setInterval(匿名函数/具名函数函数名,毫秒数) //开定时器,每隔多少毫秒就会执行一次函数---水滴石穿
clearInterval(定时器的id/变量名)
setTimeout(匿名函数/具名函数函数名,毫秒数) //开定时器,等待多少毫秒后执行一次函数---定时炸弹
clearTimeout(定时器的id/变量名)
3、this指向
this是一个关键字,谁调用this,this就指向谁
js
1、this指向window
①console.log(this); //默认情况下(直接打印this),this指向window
②fn(); //直接调用函数,等价于window.fn(),把window省略了,但仍是window调用fn函数,this指向window
③<!-- 行内绑定事件调用函数,等价于window.fn()-->
<button onclick="fn()">按钮1 行内调用</button>
④匿名函数内调用函数
btn2.onclick = function(){
fn(); //匿名函数内调用函数 等价于window.fn()
}
btn2.addEventListener('click',function(){
fn(); //匿名函数内调用函数
})
⑤定时器里的this
setInterval(function(){
console.log(this);
},1000)
⑥立即执行函数里的this
(function(){console.log(this);}())
2、this指向具体的节点
①调用具名函数的函数名
btn2.onclick = fn; //调用具名函数的函数名,this指向事件左边的对象,即具体的标签的节点
btn2.addEventListener('click',fn); //调用具名函数的函数名,this指向事件监听左边的对象
②匿名函数内直接使用this
btn2.onclick = function(){
console.log(this);
}
btn2.addEventListener('click',function(){
console.log(this);
})
③对象里的this一般指向该对象
④构造函数、原型里的this都指向具体的实例对象
function fn(){
console.log(this);
}
改变this的指向
kotlin
(1)要改变this指向的函数,call(this的新指向,实参1,实参2...)
(2)要改变this指向的函数,apply(this的新指向,[实参1,实参2...]) apply的参数2是数组
(3)要改变this指向的函数,bind(this的新指向,实参1,实参2...)() bind一定要加()调用
当内外函数里的this指向不同时,内函数要用外函数里的this指向,可以将外函数里的this指向存储到变量中,内函数用该变量即可

4、location对象
控制地址URL---统一资源定位符,包含协议、主机名/域名、端口(可省略)、路径
4.1 属性
location.host 返回主机名和端口名
location.hostname 返回主机名
location.href 返回完整地址
location.href = '完整的地址' 设置新的地址,会自动跳转到该地址的页面
4.2 方法
location.reload() 重新加载该页面/刷新
location.replace('完整地址') 将当前页面替换为完整地址对应的新页面
5、history对象
方法
①history.forward() 前进 等价于 history.go(1)
②history.back() 后退 等价于 history.go(-1)
6、document对象
既是DOM对象,也是BOM对象里的一部分
属性
①document.URL 获取当前文档的完整地址,等价于 location.href
②document.referrer 获取当前文档的来源文档的完整地址
JS高级
第一章 对象扩展
1、构造函数
kotlin
(1)用来创建对象的,首字母大写,用关键字new调用,可批量创建对象,且能看到对象的类型
(2)new调用构造函数的过程
①在构造函数内隐式创建this对象 // var this = {}; //隐式创建
②将属性和方法都赋值给this对象 //this.键 = 值;
③函数末尾隐式返回this对象 // return this; //隐式返回
④实例化对象时,将this赋值给它 new 函数名(参数1, 参数2)
(3)构造函数里的this,指向具体的实例化对象
(4)通过 原型对象.constructor 来获取 原型对象可以是显式原型也可以是隐式原型
var dog = new Anima('dog');
console.log(dog.__proto__.constructor); //Anima函数体
console.log(Anima.prototype.constructor); //Anima函数体
console.log(dog.__proto__.constructor === Anima.prototype.constructor); //true
2、原型
javascript
(1)定义
每个函数都有一个prototype的属性,它指向一个对象,称为原型对象
(2)作用
相同的属性和方法放在原型对象中,实例化对象时不会重复创建该属性和方法,会直接从原型上集成,可以节省资源
(3)写法
①构造函数名.prototype.属性名/方法名 = 属性值/函数体
②构造函数名.prototype = {
constructor:构造函数名, //将原型对象的构造函数手动指回,不设置指向Object
相同的属性和方法的键值对
}
(4)原型里的this指向具体的实例化对象
3、静态、实例成员
kotlin
1、静态成员--构造函数本身的属性和方法
使用时:构造函数名.属性名/构造函数名.方法名()
2、实例成员--构造函数内赋值给this的属性和方法 及其原型里的属性和方法
使用时:实例化对象名.属性名/实例化对象名.方法名()
4、对象实例的原型
javascript
1、定义
对象实例的原型:每个对象实例都会有__proto__的属性,它指向一个对象,称为实例的原型对象/隐式原型
2、获取
①对象实例名.__proto__ (少用,已被废弃);
②Object.getPrototypeOf(对象实例名)(多用)
3、对象实例的原型和构造函数的原型对象指向同一个对象,即它两等价的
构造函数名.prototype === Object.getPrototypeOf(对象实例名) 返回true

5、原型链
ini
1、原型链创建及查找
function 函数名1(参数) {
this.键名 = 参数;
}
var 实例1 = new 函数名1(传参);
函数名2.prototype = 实例1; //函数2的原型继承实例1
function 函数名2() {}
var 实例2 = new 函数名2();
函数名3.prototype = 实例2; //函数3的原型继承实例2
function 函数名3(参数) {
this.xing = 参数;
}
var 实例3 = new 函数名3('传参');
console.log(实例3.xing);
2、原型链从下往上查找,最早找到null
console.log(实例对象.__proto__);
6、继承
javascript
一、原型链继承
console.log('原型链继承--开始');
//父类原型的原型上,放父类实例共享的属性和方法
Fu.prototype.a = 1;
// 父类构造函数
function Fu(){}
// 子类构造函数
function Son(){}
// 核心代码:将父类实例赋值给子类的原型
Son.prototype = new Fu();
//实例化子类对象
var s1 = new Son();
// 子类实例的a属性从子类的原型上继承的,子类的原型是一个父类的实例,
// 父类实例的a属性从父类的原型上继承
console.log(s1.a); //1
s1.a = 10;
console.log(s1.a);
console.log('原型链继承--结束');
弊端:属性值是引用类型,修改一个实例上的属性后会影响原型上该属性
二、借用继承
console.log('借用继承--开始');
Fu.prototype.obj = {a:19};
// 父类构造函数
function Fu() {
this.arr = ['a','b'];
}
// 子类构造函数
function Son() {
// 核心代码:将父类构造函数的this从原来指向父类实例改为指向子类实例,
// 因为子类构造函数里的this指向子类实例的
Fu.call(this);
}
var s1 = new Son([1,2,3]);
console.log(s1.arr);
s1.arr.push(4); //修改子类实例的属性不会影响父类的属性
console.log(s1.arr); //['a','b',4]
console.log(s1.obj); //undefined
var s2 = new Son();
console.log('借用继承--结束'); //['a','b']
优点:解决了原型链继承的弊端
弊端:
①每次实例对象都会创建父类副本影响性能
②只能继承父类实例的属性和方法,不能继承父类原型上的属性和方法
三、组合继承(原型链继承+借用构造函数继承)
核心:1. 在子类的构造函数中,借用父类的构造函数并改变其this指向 例如:Fu.call(this);
2. 将父类实例赋值给子类的构造函数的原型上 例如:Son.prototype = new Fu();
3. 将子类的原型constructor属性重新赋值为子类的构造函数 例如Son.prototype.constructor = Son;
7、对象的方法
js
一、静态方法
(1)object.getownPropertyDescriptor(对象名,属性名)
作用:返回一个对象,它获取指定属性的描述
代码:
var obj = {a:1};
var res = object. getownPropertyDescriptor(obj,'a');
console. log(res);// {value: 1,writable: true, enumerable: true, configurable: true}
(2)Object.assign(目标对象,源对象1,源对象2...)
作用:所有可枚举属性的值从一个或多个源对象复制到目标对象,它将返回目标对象
代码:
var target = { a: 1, b: 2, c: 666 }
var source = { c: 3, d: 4 }
var assignObj = Object.assign(target, source);
console.log(target); //{a:1,b:2,c:3,d:4} 合并对象时目标对象会被改变
console.log(assignObj); //{a:1,b:2,c:3,d:4}
(3)Object.create('对象名')
作用:创建一个新对象
代码:
var obj = {
a: 1
}
var o = Object.create(obj);
console.log(obj);
console.log(o);
(4)Object.entries('对象名')
作用:返回一个给定对象自身可枚举属性的键值对数组
代码:
var obj = {name:"zhang",age:100,sex:"male"};
console.log(Object.entries(obj)); // [ ["name", "zhang"], ["age", 100], ["sex", "male"] ]
(5)Object.getOwnPropertyDescriptor(对象名,属性名)
作用:返回指定对象上自有属性对应的属性描述符(自有属性即直接赋予该对象的属性,不需要从原型链上进行查找的属性)
代码:
var obj = {
name: "lucy"
}
console.log(Object.getOwnPropertyDescriptor(obj, "name"));
console.log(Object.getOwnPropertyDescriptor(obj));
对象名必须写,属性名选写
(6)Object.getOwnPropertyNames(对象名)
作用:返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组
代码:
var obj = { a: 1, b: 2, c: 3 }
console.log(Object.getOwnPropertyNames(obj));
//["a","b","c"]
obj.__proto__.d = 4;
console.log(Object.getOwnPropertyNames(obj));
//["a","b","c"]
(7)Object.keys(对象名)
作用:返回一个由一个给定对象的自身可枚举属性组成的数组
var obj = {a: 1,b: 2,c: 3}
Object.keys(obj);// ["a","b","c"]
var o = Object.create(obj);
o.name = "oooo";
Object.keys(o);// ["name"]
Object.getOwnPropertyNames(对象名) 和 Object.keys(对象名) 的区别:
①使用for..in循环时:返回的是所有能通过对象访问的、可枚举的属性(包括存在于实例中的属性、存在于原型中的属性)
②Object.keys()获取对象自身所有的可枚举的属性值,不包括原型中的属性,返回一个由属性名组成的数组
③Object.getOwnPropertyNames()返回对象的所有自身属性的属性名(包括不可枚举的属性)组成的数组,会获取原型链上的属性
(8)Object.getPrototypeOf(对象名)
作用:返回指定对象的原型
代码:
var protoobj = {};
var obj = Object.create(protoobj);
console.log(Object.getPrototypeOf(obj) === protoobj);// true
console.log(Object.getPrototypeOf(obj) === obj.__proto__);// true
(9)Object.setPrototypeOf(对象名)
作用:设置一个指定的对象的原型为另一个对象或null
代码:
var obj = { a: 1 }
console.log(Object.setPrototypeOf(obj, { b: 2 }));
javascript
二、实例方法
(1)对象名.hasOwnProperty(属性名)
作用:返回一个布尔值,是指对象自身是否具有指定的属性,自己有返回true,否则返回false,不包含继承的属性
代码:
var obj = {a:1};
console. log(obj.hasownProperty('a')); //true
hasownProperty()方法会返回一个布尔值,指对象自身是否具有指定的属性
(2)对象名.isPrototypeOf(对象名)
作用:判断当前对象是否在传入的参数对象的原型链上
代码:
var MyObj = function(){};
var obj = new MyObj();
//判断Object的prototype是不是在obj的原型链中
console.log(Object.prototype.isPrototypeOf(obj)); //true
(3)对象名.propertyIsEnumerable('属性名')
作用:判断给定的属性是否被for..in遍历出来,返回布尔值
代码:
var obj = {
name:'王'
}
for(var key in obj){
console.log(key);
}
console.log(obj.propertyIsEnumerable('contructor')); //false
console.log(obj.propertyIsEnumerable('name')); //true
原因:输出了name属性,但是obj属性很多,遍历了但是没有把contructor等遍历出来
(4)对象名.toLocaleString()
作用:返回对象的字符串表示,和代码的执行环境有关
代码:
var obj = {};
console.log(obj.toLocaleString()); //[object Object]
var data = new Date();
console.log(data.toLocaleString()); //2024/1/20 17:07:43 具体的时间
(5)对象名.toString()
作用:返回对象的字符串表示
代码:
var obj = {};
var data = new Date();
console.log(obj.toString()); //[object Object]
//toLocaleString()和toString()的比较
console.log(data.toLocaleString()); //2024/1/20 17:07:43 具体的时间
console.log(data.toString()); //Sat Jan 20 2024 17:11:27 GMT+0800 (中国标准时间)
(6)对象名.valueOf()
作用:返回对象的原始值,根据对象的不同,返回的可能是字符串、数值或boolean值等
代码:
var arr = [1];
console.log(arr.valueOf());//[1]
var date = new Date();
console.log(date.valueOf());//1456638436303
// 自定义valueOf方法,可以更改返回对象的原始值
arr.valueOf = function(){return false;}
console.log(arr.valueOf()); //false
// ①没有重新定义toString与valueOf时,
// 函数会隐式转换调用默认的toString方法,会将函数的定义内容作为字符串返回。
function fn(){
return 20;
}
console.log(fn +10); //函数的原始值
// ②主动定义了toString()/vauleOf()方法时,会返回自定义的值,
// 但是其中valueOf()会比toString()后执行
function fn(){
return 30;
}
fn.toString = function(){
return 10;
}
fn.vauleOf = function(){
return 5;
}
console.log(fn +10); //20
(7)对象名.watch('属性名') 对象名.unwatch('属性名') //最好不用
作用:监视传入属性是否被赋值并在赋值时运行相关函数
第二章 JS运行过程、作用域/链、闭包
1、js运行过程
1.1 三步走
语法分析---预编译---执行
1.2 预编译
typescript
(1)当js执行前一刻会生成GO--global object对象,当函数执行的前一刻会生成AO--active对象
(2)预编译是将变量声明和函数声明进行提升
GO对象里放全局的变量(初始值undefined)和全局函数(初始值是函数体)
AO对象里放局部的变量(初始值undefined)、形参(初始值是undefined)、局部函数(初始值是函数体)
(3)同一个作用域内函数名和变量名不要重名,如果重名了,函数优先于变量
2、作用域、作用域链
作用域:执行器上下文对象集合、分为全局作用域、局部作用域、块级作用域
作用域链:作用域是一个链式的连接,查找从作用域链的顶端开始往下查找
ES5中用立即执行函数来模拟块级作用域,ES6中用let、const声明的变量/常量实现块级作用域
js
// 语法 直接调用 会立即执行{}里的代码
//推荐
(function (x) {
console.log(x);
}(10));
(function (a, b) {
console.log(a + b);
})(5, 10);
// 需求:点击li 弹出它的下标
// for + 立即执行函数--模拟块级作用域
for (var i = 0; i < LiAll.length; i++) {
(function (suo) {
LiAll[i].addEventListener('click', function () {
console.log(suo);
})
}(i))
}
3、闭包
3.1 定义
闭包是能读取其它函数内变量的函数,即在函数外读取函数内的变量需要闭包--内部函数
3.2 基本写法
scss
function wrap(){
var b = 3; //在外函数内声明一个局部变量
function inner(){ //在内函数里面对局部变量进行操作
console.log(b);
}
return inner;//将内函数的函数体作为外函数的返回值
}
var res = wrap();//调用往爱函数,它的返回值是内函数的函数体存到变量res中
res();//调用内函数的函数体
console.log(res); //内函数的函数体
4、高阶函数
4.1、定义
高阶函数是一个接收函数作为参数(回调函数的主函数)或者将函数作为返回值输出的函数(闭包里的外函数)
如:定时器、数组遍历的方法----forEach/map/filter...
第三章 深浅拷贝
1.定义
深浅拷贝是针对引用类型,一层引用类型的数据省钱拷贝后
深浅拷贝后相互都不影响
多层引用类型的数据---如对象的属性值又是一个对象或数组 二维/三维...
浅拷贝:拷贝后的对象和被拷贝的对象 相互还是影响
深拷贝:拷贝后的对象和被拷贝的对象 相互独立,不会影响彼此
2、浅拷贝
scss
(1)拷贝对象({},[])
//法一遍历
function cloneObj(){
var cloneObj=Array.isArray(obj)?[]:{};//判断是不是一个数组或者对象
for(var k in obj){
cloneObj[key] = obj[key];
}
return cloneObj;
}
//法二扩展运算符
function cloneObj(obj){
var cloneObj=Array.isArray(obj)?[...obj]:{...obj};//判断是不是一个数组或者对象
return cloneObj;
}
//法三
function cloneObj(obj){
var cloneObj=Array.isArray(obj)?[]:{};
Object.assign(clone,obj)
return clone;
}
3、 深拷贝
js
var deepClone = JSON.parse(JSON.stringify(obj));
// 深拷贝的法1:用JSON的方法
// 优点:简洁 弊端:无法拷贝函数/对象的方法 适用场景拷贝的内容里没有function
var deepClone = JSON.parse(JSON.stringify(obj));
// 深拷贝的法2:递归
// 函数功能:深拷贝
// 参数:obj 被拷贝--原对象 数据类型:数组/对象
// 返回值:拷贝后的内容
function deepClone(obj) {
// 1、判断传的实参是不是引用类型--数组、对象,如果不是就抛出错误结束函数
//!obj表示传的实参是null时也不符合参数要求
if (!obj || typeof obj != 'object') {
throw new Error('传的实参不是数组或对象,请重新传参');
}
// 2、判断传入的实参是数组还是对象,从而确定拷贝后的初始值是对象还是数组
var targetObj = Array.isArray(obj) ? [] : {};
// 3、for...in遍历依次取出每个键对应的值
for (var key in obj) {
// 4、判断属性/键是不是对象自己的属性,如果是才拷贝
if (obj.hasOwnProperty(key)) {
// 5、判断值是什么类型,如果是引用类型就要再次调用该函数克隆里面的内容
// 如果是原始类型就直接赋值给拷贝后的对象
if (typeof obj[key] == 'object' && obj[key]) { //obj[key] 排除null
targetObj[key] = deepClone(obj[key]);
} else {
targetObj[key] = obj[key];
}
}
}
// 6、返回拷贝后的对象
return targetObj;
}
//深拷贝的法3:用插件(别人封装好可以直接用的js)里的方法
①lodash.js 里的_.deepClone()里的方法
②jquery里的 $.extend(true,target,object1,[objectN]);
4、 异常处理机制
js
// try里的代码有错误会执行catch里的代码且不阻塞进程(后面的代码会继续执行) // 只适用于处理无法预测的错误
try{
可能会发生无法预测的错误的代码
}catch(e){ //当try里的代码有错误,执行了catch的代码
console.log(e); //放的是error对象
}
// finally是根据需求选写
finally{
console.log('不管执行try里面的还是执行catch里的代码,执行之后都会执行finally里的代码');
}
//throw new Error("错误的提示信息");抛出一个错误,同浏览器的报错一样会阻塞进程
第四章 事件循环
1、名词
lua
1、宿主环境:运行环境 js的宿主环境是浏览器、node.js
2、进程 CPU--工厂 进程--车间 电脑可以运行多个进程,每个进程包含多个线程
3、线程 线程--工人 浏览器是多进程的,每个标签页是一个进程
4、重绘 修改节点的颜色样式,会重新绘制该节点,比较节省性能
5、重排 也称为回流,修改节点的尺寸、大小、层级关系、数量的增加或减少
2、渲染进程--浏览器内核
2.1 主流浏览器
IE(edge) 、谷歌(chrome)、火狐(fireFox)、欧朋(opear)、苹果(safari)
2.2 内核--(渲染引擎+js引擎)
谷歌(chrome) webkit--->blink V8
2.3 包含的线程
scss
(1)GUI渲染线程:页面渲染、交互等
(2)JS引擎线程(js主线程):执行js代码
(3)事件触发线程:控制事件的触发和执行
(4)定时器触发线程:控制setInrerval和setTimeout
(5)异步http请求线程:处理ajax的请求
2.4 渲染流程
scss
(1)解析html,生成DOM树
(2)解析css,生成style树,和DOM树合并生成渲染render树
(3)布局 layout
(4)绘制 paint
(5)显示到页面
3、同步异步
arduino
1、定义
js任务分为同步任务和异步任务
同步任务:一个时间点只能执行一个任务,即上一个任务执行完毕才会执行下一个任务,会阻塞进程 如弹窗
异步任务:无需等待上一个任务执行完毕,可以同时执行下一个任务
2、使用异步的场景
需要等待的情况都要用异步任务
常见场景:定时任务、ajax请求、事件
3、js任务执行机制
栈:先入后出,后进先出
堆:先进先出,后进先出
①限制性同步任务,再执行异步任务
②同步任务按照代码书写顺序从上往下依次执行,异步任务按照结束等待状态来依次执行的
4、宏任务和微任务
异步任务分为宏任务(2个定时器)和微任务(宏任务执行过程中产生的回 promise.then())
4、执行机制
主线程将同步代码放进执行栈中执行,异步代码放进任务队列中监听,当执行栈中为空,
js主线程才会将任务队列中的代码拿进执行栈中执行,这个过程就是事件循环
4.1 任务队列
- 宏队列:事件、定时器、网络
- 微队列(类似VIP):Promise、MutationObserver(监听DOM对象变化)
5、防抖和节流函数
定义:为了限制函数的触发次数,减少浏览器性能的小号,多用于高频发的触发事件中
防抖函数:指频繁触发情况下,只有空闲足够的时间,才能执行一次函数
节流函数:一定时间内函数只执行一次
插件:underscore.js
6、ES6新增的promise对象
arduino
//1、定义、作用
// Promise是Es6新增的,用于处理异步任务层层嵌套/回调地狱的问题
// 本质是一个容器,用来存储未来才会结束的异步任务的结果
//语法上Promise是一个构造函数,用于创建一个promise对象
// 2、创建
// new Promise(回调函数)
// 3、promise的3种状态 2种变化
// 状态:pending(进行中)、fulfilled/resolved(已成功)和rejected(已失败)
// 2种变化 pending(进行中)--->fulfilled/resolved(已成功)
//pending(进行中)---->rejected(已失败)
// 状态发生变化后不可逆,也不可改
// 4、实例的方法:then、catch、 finally
// ①他们都是实例的方法,then和catch都会返回新的promise对象,支持链式写法,finally总是返回原来的值
// ②他们都是主函数,调用时里面传回调函数,成功promise的状态时调用then里的回调函数,失败是会调用catch里的
// 回调函数,无论成功还是失败会调用finally里的回调函数
// ③一旦执行了then里的回调函数,就不会执行catch里的回调函数
// 5、静态方法:resolve,reject,all,race
// 6、简化写法 用关键字 async await
// async放在函数(函数声明或函数表达式)的开头,该函数一定会返回promise对象
// await 等待 用于等待一个promise对象,只能用在有async修饰的函数内
第五章 算法
1、定义
解决问题的方案/步骤/过程/思路,使用空间复杂度(运行时占用的空间越少越好)和时间复杂度(运行花费的时间越短越好)来衡量一种算法的优劣
2、常见的排序算法
2.1 冒泡排序/泡排序/起泡排序
**核心思想:**遍历数组,比较相邻的两个元素,前一个大于后一个就交换位置
算法步骤:
①循环/遍历数组,确定循环的次数--即需要循环几轮
②循环数组,依次取出相邻的两项
③比较相邻的两项,如果前一项大于后一项就交换位置
重复②③知道数组全部拍好顺序
代码:
js
function bubbleSort(arr){
for(var i=0;i<arr.length-1;i++){ //外循环 确定循环的次数--即需要循环几轮
for(var j=0;j<arr.length-1-i;j++){ //内循环 取元素
if(arr[j]>arr[j+1]){
var tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
return arr;
}
2.2 归并排序,也称二分法排序
**核心思想:**将数组一分为二,分别对左边和右边的部分进行排序,左右二部分排序之后再合并为一个又循的数组
算法步骤:
①找到中间项,将数组一分为二
②对左边的部分进行排序,重复①
③对右边的部分进行排序,重复①
④左右二部分排序之后再合并为一个又循的数组
代码:
scss
function mergeSort(arr, start, end) {
// 递归的出口
if (start > end) {
return []
} else if (start == end) {//只剩一个
return [arr[start]]
} else if (start == end - 1) {//只剩二个,比较二个元素的大小并排行顺序
return arr[start] < arr[end] ? [arr[start], arr[end]] : [arr[end], arr[start]]
}
var mid = Math.floor((start + end) / 2);//中间相的下标 必须用下舍入
var left = mergeSort(arr, start, mid) //左边的排序
var right = mergeSort(arr, mid + 1, end)//右边的排序
var resArr = [];//最终有序的数组
while (left.length > 0 || right.length > 0) { //左边或右边还有内容
left[0] < right[0] ? resArr.push(left.shift()) : resArr.push(right.shift())
//当左边数组中没有元素,直接把右边数组里的数组拼接到最终结果的数组中resArr
if (left.length == 0) {
resArr = resArr.concat(right)
break;
} else if (right.length == 0) {//当右数组中没有元素,直接把左边数组里的数组拼接到最终结果的数组中resArr
resArr = resArr.concat(left)
break;
}
}
return resArr
}
2.3 快速/快排排序
**核心思想:**将一个数组一分为二,选一个元素作为标记,将比标记大的元素放到标记的右边,比标记小的元素放到标记的左边
算法步骤:
①找到中间项作为标记,将比标记大的元素放到标记的右边,比标记小的元素放到标记的左边
②对标记左边的部分重①直到排好顺序
③对标记右边的部分重①直到排好顺序
④左中右二部分排序之后再合并为一个又循的数组
代码:
scss
function quickSort(arr) {
// 递归的出口
if (arr.length == 0) {
return [] //数组里的元素为空的时候
}
var minIndex = Math.floor((arr.length - 1) / 2),//标记元素的下标
midArr = arr.splice(minIndex, 1), //标记元素所在的数组
left = [],
right = []
for (var i = 0; i < arr.length; i++) { //循环数组
if (arr[i] < midArr[0]) {
left.push(arr[i])//比标记小的元素放到标记的左边
} else {
right.push(arr[i])//将比标记大的元素放到标记的右边,
}
}
// 左中右二部分排序之后再合并为一个数组
return quickSort(left).concat(midArr).concat(right)
}
2.4 插入排序
**核心思想:**通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上
算法步骤:
①从第一个元素开始,该元素可以认为已经被排序;
②取出下一个元素,在已经排序的元素序列中从后向前扫描;
③如果该元素(已排序)大于新元素,将该元素移到下一位置;
④重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
⑤将新元素插入到该位置后;
⑥重复步骤2~5
代码:
css
function inserSort(arr) {
for (var i = 1; i < arr.length; i++) { //依次取出无序区域里每个元素每个元素
for (var j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {//从或往前循环有序区域的元素,如果该元素比有序区域里的元素小就要插入在前
var tmp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = tmp
}
}
return arr;
}