JAVASCRIPT
推荐vscode进行编写,推荐相关插件安装如下:
- live server
代码解析与变量提升
console.log(web)
var web = 'test'
//浏览器输出undefined,原因:在代码解析的时候会把var web(变量定义)提前
var web;
console.og(web);
web = 'test';
//例子2
funtion test(){
if(false){
var web = 'test'
}
console.log(web) //输出undefined
}
//上述例子经过代码解析后等于
funtion test(){
var web;
if(false){
web = 'test'
}
console.log(web) //输出undefined
}
严格模式
//test.js
funciton test(){
a = 123
}
//test.html
<script src="test.js">
var a = 111;
test();
console.log(a) //输出结果为123 ,全局参数污染
</script>
//test1.html
<script src="test.js">
"use strict" //严格模式,变量必须声明,否则报错,当前作用域以及子作用域受影响
var a = 111;
test();
console.log(a)
</script>
冻结变量
const host = {
url:'https://www.baidu.com',
port:443
}
host.port = 80
console.log(host)//输出 {url: "https://www.baidu.com", port: 80}
//冻结变量host
const host = {
url:'https://www.baidu.com',
port:443
}
Object.freeze(host) //冻结变量
host.port = 80
console.log(host) //输出{url: "https://www.baidu.com", port: 443}
NULL与Undefined
let config = null //初始化引用类型 等于 let config = {} 转成数值为0
let url = undefined //初始化基础类型 等于 let url = '' 当变量被定义了未赋值时,为undefined 转成数值为NAN
短路运算的妙用
let a = 6
let b = 0
let f = b || a
console.log(f) //输出6,原因:会把为真的值赋值给f
//例子1
let sex = prompt('请输入性别:')
let result = sex || '女'
console.log(result)
switch注意事项
let error = "notice";
switch (error){
case "notice":
console.log('提示消息') //没有写break,将会继续往下执行,直到碰到break后停止
case "warning":
console.log("提示或警告消息")
break
case "error":
default:
console.log('错误消息')
}
/*
最终控制台输出
test.js:4 提示消息
test.js:6 提示或警告消息
*/
区分数组与对象
/*
使用typeof判断类型输出都是object
应该使用 instanceof
*/
let a = [];
let b = {};
console.log(a instanceof Array)
字符串
拼接新语法
let name = 'chestnut'
let age = 20
console.log('我的名字叫:'+name+',我今年:'+age+'岁。')
console.log(`我的名字叫:${name},我今年:${age}岁。`) //使用${}进行变量读取
函数
//去掉字符串
str= 'a b'
console.log(str.trim().length);
//获取指定字符
str= 'abcdsdfeow';
console.log(str[0]);
console.log(str.charAt(0))
let str = '123;sdifds;34r?';
/*
字符串截取 :
slice()
substring()
substr()
*/
/*
字符串查找 :
str.indexOf():返回具体位置,若为-1则找不到,从左边开始查找
str.lastindexOf():返回具体位置 ,从右边开始查找
str.includes():返回布尔类型
str.startsWith():是否以某字符开头,区分大小写,返回布尔类型
str.endsWith():是否以某字符结尾
*/
/*
字符串替换:
str.relace()
*/
/*
字符串重复:
str.repeat()
*/
布尔类型
隐式转换原理
let array = [1,2,4]
let num = 2
console.log(array == true) //输出为false ,因为会把array转成数值为NAN,执行Number(array),布尔true转成数值为1
console.log(num == true)//输出为false ,2不等于1
if(num) //num为true,此运行结果是将num转成布尔类型,即Boolean(num) = true
布尔类型转换
let number = 0;
console.log(typeof(number)) //输出为number
number = !!number; //转换成布尔类型
number = Boolean(number)//转换成布尔类型
NAN类型
console.log(Number('dsafd')) //输出NaN(not a number)
console.log(Number('dfo') == NaN) //输出false,原因 NaN无法与NaN进行判断
//可使用以下方法进行判断
console.log(Number.isNaN(1/'adfads'))
console.log(Object.is(1/'asfd',NaN))
标签模板
let name = 'chestnut'
let age = 20
let str = tag`我的名字叫:${name},我今年:${age}岁。`;
console.log(str);
function tag(strings,...vars){ //不知道有多少参数,使用...收集所有的参数形成数组
console.log(strings); //输出数组 ["我的名字叫:", ",我今年:", "岁。"]
console.log(vars) //输出数组['chestnut',20]
console.log(name); //输出chestnut
console.log(age); //输出20
return strings.map((str,key) =>{
return str +=vars[key]?vars[key]:'yeah!!!'; //使用tag标签可对字符串做二次处理
})
}
Date类型
获取时间戳
const date = new Date('2021-10-12 11:30:34')
console.log(date *1)
console.log(Number(date))
console.log(date.valueOf())
console.log(date.getTime())
计算脚本执行时间
//第一种
const date = Date.now()
for(let i =0;i<=2000000;i++){
}
const end = Date.now()
console.log((end-date)/1000+'s')
//输出:5 0.003s
//第二种方式
console.time('sign') //自定义标志
for(let i =0;i<=2000000;i++){
}
console.timeEnd('sign')
//输出: sign: 2.48583984375 ms
日期格式封装
const date =Date.now()
console.log(getDate(new Date(date),'YYYY-MM-DD HH:mm:ss'))
function getDate(date,format){
const config = {
YYYY : date.getFullYear(),
MM: date.getMonth()+1,
DD: date.getDate(),
HH: date.getHours(),
mm: date.getMinutes(),
ss: date.getSeconds()
}
for(const key in config){
format = format.replace(key,config[key])
}
return format;
}
- 第三方库推荐momentjs(日期处理库)
数组
- 可使用console.log()与console.table()进行查看
//数组转字符串
let a = 'adf23';
console.log(Array.from(a));
let obj = {
0:'test1',
1:'test2'
}
console.log(Array.from(obj))//失败,使用from方法必须包含length属性
let obj1 = {
0:'test1',
1:'test2',
length:2
}
console.log(Array.from(obj1))//转换成功
展开语法
let a = [123,234,34]
let b = [23,45]
let c = [...a,...b] //将a的值和b的值展开
console.log(c) //最终得到[123, 234, 34, 23, 45]
//不定参数传参
function sum(...num){
let result = 0;
for(let i of num){
result += i
}
return result;
}
console.log(sum(1,49,23,47))
let list = document.querySelectorAll('div')
console.log(list) //节点对象
let _list = [...list] //转成数组
_list.map(item => {
console.log(item)
})
解构语法
- …放在变量位置时,吸收,放在值的位置时,是展开
//结构常见用法
let [age,name] = [20,'ella']
console.log(age)
console.log(name)
let [...arr] = 'sdfae'
console.log(arr)
let [_age,...arrs] = [20,'ella','play games']
console.log(arrs)
查找元素
- indexof:返回查找元素下标,若找不到返回-1
- includes:返回布尔值
- 新增find,findIndex用法见下列案例
let arr = [{name:'aaa',age:18},{name:'bbb',age:20},{name:'ccc',age:30}]
let result = arr.find(function(item){
return item.name == 'aaa'
})
console.log(result)//返回{name:'aaa',age:18}
let result_index = arr.findIndex(function(item){
return item.name == 'aaa'
})
console.log(result_index)//返回0 ,对应下标
排序(sort)
let arr = [{name:'aaa',age:18},{name:'bbb',age:20},{name:'ccc',age:30}]
arr = arr.sort(function(a,b){
return a.age - b.age //a - b < 0 ,从小到大排列
})
console.table(arr)
arr = arr.sort(function(a,b){
return b.age - a.age //b - a < 0 ,从大到小排列
})
console.table(arr)
//原理
循环
- for in:获取索引
- for of:获取数组的值
- forEach:可遍历dom对象
- every:当返回false,直接中断循环
- some:当返回true,直接中断循环
let list = [{'title':'abc','value':1},{'title':'adasf','value':2}]
//for in...
for(let item in list){
console.log(item) //输出下标0,1
}
//for of
for(let time of list){
console.log(item) //输出下标对应值 {title: "abc", value: 1} ,{title: "adasf", value: 2}
}
//forEach可遍历dom节点
let list = document.querySelectorAll('div')
list.forEach(function(item){
item.addEventListener('click',function(){
console.log(this.classList);
this.classList.toggle('disable') //classList:类名列表;toggle:如果有则去除,没有则添加类名
})
})
//every循环
let arr = [{name:'bbb',age:20},{name:'aaa',age:17},{name:'ccc',age:30}]
const flag = arr.every(function(item,index,arr){ //item:值,index:下标,arr:原数组
console.log(item);
return item.age > 18; //可更改条件查看控制台打印,返回false中断循环
});
if(flag){
console.log('所有朋友都成年')
}
else{
console.log('有人未成年')
}
//some循环
let arr = [{name:'bbb',age:20},{name:'aaa',age:17},{name:'ccc',age:30}]
const flag = arr.some(function(item,index,arr){//item:值,index:下标,arr:原数组
console.log(item);
return item.name === 'aaa'; //可更改条件查看控制台打印,返回true中断循环
});
if(flag){
console.log('里面有名为aaa的人')
}
else{
console.log('查无此人')
}
迭代器(Iterator)
- 只要是迭代器类型,都可以使用next()
let arr = [{name:'aaa',age:18},{name:'bbb',age:20},{name:'ccc',age:30}]
let keys = arr.keys();
console.log(arr.keys()) //输出Array Iterator {},为可迭代对象
console.log(keys.next())//value:值(索引0,1,2....),done:是否迭代完成
let arr = [{name:'aaa',age:18},{name:'bbb',age:20},{name:'ccc',age:30}]
let values = arr.values();
console.log(values) //输出Array Iterator {},为可迭代对象
console.log(values.next())//value:值(索引对应的值),done:是否完成迭代
//方法一:先执行value与done分别赋值,再判断是否可以继续迭代
while(({value,done} = values.next()) && done === false){
console.log(value);
//输出所有下标对应的值
//{name: "aaa", age: 18}
//{name: "bbb", age: 20}
//{name: "ccc", age: 30}
}
//方法二:
for(const value of values){
console.log(value)
}
let entries = arr.entries()
console.log(entries);
console.log(entries.next());//value:数组[索引,值]例如:[0,{name: "aaa", age: 18}], done:是否完成迭代
过滤
let arr = [{name:'bbb',age:20},{name:'aaa',age:17},{name:'ccc',age:30}]
const result = arr.filter(function(item,index,arr){
return item.age>18; //返回满足条件的数组
});
console.table(result);
映射
let arr = [{name:'bbb',age:20},{name:'aaa',age:17},{name:'ccc',age:30}]
const result = arr.map(function(item,index,arr){
item.name = `test-${item.name}`;
return item; //每次循环返回值为最终数组对应索引的值,可尝试return 1输出结果
});
console.table(result);
reduce方法
- 适合做数据统计
let arr = [23,21,3,1,543,23]
const _result = arr.reduce(function(pre,item,index,arr){
//pre为上一次返回的结果
//如果没有设置则默认第一次输出pre为0索引对应值,item为1索引对应值
console.log(index+'次:'+pre);
console.log(index+'次:'+item);
return 666;
});
console.log(_result);
const result = arr.reduce(function(pre,item,index,arr){
return pre += item === 23?1:0
},0);
//0为初始返回结果(pre初始值)
console.log('23总共出现:'+result+'次');
//案例1:获取最大值
let arr = [23,21,3,1,543,23]
const result = arr.reduce(function(pre,item,index,arr){
return pre > item ? pre : item;
});
console.log(`最大值为:${result}`);
//案例2:获取已成年名字
let arr = [{name:'bbb',age:20},{name:'aaa',age:17},{name:'ccc',age:30}]
const result = arr.reduce(function(pre,item,index,arr){
if(item.age>18) pre.push(item.name);
return pre;
},[]);
console.table(result);
symbol
- 用来区分唯一表示的字符串
let _a = 'aaa';
let _b = 'aaa';
console.log(_a === _b);//输出true,相等
let a = Symbol('aaa')
let b = Symbol('aaa')
console.log(a.description)
console.log(b.description)
console.log(a === b) //输出false,不相等
//使用symbol.for全局声明,会在内存中记录,若存在则不创建,因此相同描述时,使用同一个
let a = Symbol.for('aaa')
let b = Symbol.for('aaa')
console.log(Symbol.keyFor(a))//使用symbol.for声明时才可以使用keyFor获取描述
console.log(a === b)
//symbol使用案例
let a = {
name: 'ella',
key: Symbol()
}
let b = {
name: 'ella',
key: Symbol()
}
let grade = {
[a.key]: {age: 20}, //json中key使用变量需要使用中括号
[b.key]: {age: 30}
}
console.log(grade[a.key])
//案例2:使用symbol当key时,如何遍历
let symbol = Symbol('个人资料');
let a = {
name: 'ella',
[symbol]: 'ella个人资料'
}
for (const key in a) {
console.log(key) //无法打印出symbol
}
for (const key of Object.keys(a)) {
console.log(key); //无法打印出symbol
}
for (const key of Object.getOwnPropertySymbols(a)) {
console.log(key); //只能打印出symbol
}
for (const key of Reflect.ownKeys(a)) {
console.log(key); //打印所有属性
}
set与WeakSet
set
- 不能有重复类型
//声明方式1:
let set = new Set([12,12,3,45]);
console.log(set);
//声明方式2:
let _set = new Set();
_set.add(13)
console.log(_set);
//判断是否存在
console.log(set.has(12))
//删除
set.delete(12)
console.log(set)
//清空
set.clear()
//类型转换:转换成数组
let set = new Set([12,12,3,45]);
console.log(Array.from(set)) //方法1
console.log([...set]) //方法2
set处理并集交集差集
//并集:利用不重复特性
let set = new Set([12,24,3,45,37]);
let _set = new Set([12,24,3,48,59]);
console.log(new Set([...set,..._set]))
//差集
console.log(
new Set(
[...set].filter(function(item){
return !_set.has(item) //_set数组中不包含set数组的集合
})
)
)
//交集
console.log(
new Set(
[...set].filter(function(item){
return _set.has(item) //_set数组中包含set数组的集合
})
)
)
WeakSet()
- 不含有重复值
- 里面的值必须为引用类型
- 具有弱引用特性 – 迭代器.key ,values/for of都用不了
//let set = new WeakSet([12,24,3,45,37]); 会报错
// 报错原因:该语句是将12,24等值类型分别添加进去
let set = new WeakSet();
set.add([12,24,3,45,37]) //将引用对象[12,24,3,45,37]添加
console.log(set)
//弱引用特性案例
let _person = {name:'ella','age':20};
let a = _person;
_person = null;
console.log(a) //输出正常结果,虽然_person被清空了,但是a还是指向内存地址
let set = new WeakSet();
let person = {name:'ella','age':20};
set.add(person);
person = null;
console.log(set)//输出为空,person被删除,WeakSet增加不会引用内存地址,会被垃圾回收机制清空
案例
<body>
<style>
.disable{
color : #ccc;
}
.a{
width: 100px;
height: 20px;
background-color: #587fff;
margin-bottom: 3px;
}
.remove{
background-color: #ccc;
}
</style>
<div class="a">1</div>
<div class="a">2</div>
<div class="a">3</div>
<div class="a">4</div>
<div class="a">5</div>
<script src="./test.js"></script>
</body>
//test.js
class removeDiv{
constructor(){
this.divs = document.querySelectorAll('.a');
this.lists = new WeakSet();
//将dom节点添加到webkset
this.divs.forEach(item => this.lists.add(item));
}
click(){
this.divs.forEach(item => {
item.addEventListener('click',() =>{
//如果weakset里面有dom对象,则添加移除样式,并将dom从weakset中移除
if(this.lists.has(item)){
item.classList.add('remove');
this.lists.delete(item);
}
else{
//否则移除样式,并添加dom节点对象至weakset
item.classList.remove('remove');
this.lists.add(item);
}
})
});
}
}
let a =new removeDiv();
a.click();
Map与WeakMap
Map
- 键可以为任务类型,例如:对象,数值等
- 因为可以为任意对象,所以键可以用来存储dom节点,值可以为dom的额外消息
let map = new Map();
map.set('name','ella');
console.log(map);
map.set({'a':'123'},'ella')
console.log(map);
map.set(1,'ella')
console.log(map);
map.set([1,2,3],'ella')
console.log(map);
let map = new Map();
map.set('name','ella');
let test = {'a':'123'};
map.set(test,'ella')
//查询
console.log(map.has(test));
//取值
console.log(map.get(test));//存的内存地址,可获取
console.log(map.get({'a':'123'}));//不可获取
//删除
map.delete('name');
console.log(map);
//清空
map.clear();
console.log(map)
WeakMap
- 键只能是引用类型
- 具有弱引用类型特性,类似于WeakSet
函数
函数声明
//声明方式1:
let fun = new Function('test','console.log(test)');//(参数,函数体)
fun('123');
//声明方式2:
funtion fun(test){
console.log(test);
}
//声明方式3:
let _fun = funtion fun(test){
console.log(test);
};//注意加分号
//声明方式4:
let person = {
name : '',
age : '',
setPerson(name, age) {
this.name = name;
this.age = age;
},
getPerson(){
console.log(`我的名字${this.name}是,我今年${this.age}岁`);
}
}
person.setPerson('ella',20);
person.getPerson();
全局函数
function a (){
console.log('a');
}
a()//输出a
window.a()//输出a,直接定义函数是全局函数,会增加到window对象中
var a = function b (){
console.log('a');
}
window.a()//输出a,var声明会增加到window对象中
//解决方式,使用let进行声明
let a = function b (){
console.log('a');
}
window.a()//报错
函数提升
b(); //输出b,声明b函数进行了提升
function b(){
console.log('b');
}
a();//报错,匿名函数不会进行函数提升
let a = function(){
console.log('a');
}
//箭头函数,求和案例
function sum(...args){
return args.reduce((a,b) => a+b)
}
console.log(sum(1,2,3,10));
立即执行函数
//普通函数声明
function a(){
console.log('aaa');
}
a();//调用函数执行
//立即执行函数,不需要调用,直接执行
(function a(){
console.log('aaa');
})()
//解决多个js文件同名函数冲突问题
//test1.js
(function(window){
function a(){
console.log('1aaa');
}
function b(){
console.log('1aaa');
}
window.test1 = {a,b};
})(window);
//test2.js
(function(window){
function a(){
console.log('2aaa');
}
function b(){
console.log('2aaa');
}
window.test2 = {a,b};
})(window);
test1.a();
test2.a();
函数默认值
function sum(a=1,b=2){
console.log(a+b);
}
sum();//未传参数使用默认值
sum(4,5);