一.数据类型(6+1)
- 基本数据类型:undefined、null、Boolean、numbe、string、symbol
- 引用数据类型:object,里面又细分为function、Array、Date、正则等。
- 基本数据类型:占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储。
- 基本类型一般不可改变,值改变时,地址也改变,所以不是在改变原值,而是产生了新值。
- 引用数据类型同时存放在栈和堆中,引用数据类型在
栈中存储了指针(变量名)
,该指针指向堆中该实体的起始地址(变量值)
。 - 引用数据类型值可以改变的,是在原值基础上修改。
- 引用数据类型变量复制的时候,复制的是同一个指针地址,共享同一个堆实体。
1.1 基本数据类型
-
typeof 可以判断所有的值类型数据,返回的都是字符串
-
常见的值类型数据有:number,string,boolean,undefined,symbol,返回都是对应的类型(小写)
-
可以判断常见的引用类型数据:object,array,null.返回的都是 object
-
判断函数 function 返回的是 function
1.undefined
- 声明后变量的没有初始化就是undefined,是唯一值;
- 特殊情况是即使是没有声明变量a,typeof a ;//undefined
2. null类型
-
空对象指针,表现为检验typeof null会返回'Object';
-
在定义将来要保存的对象时建议用null初始化;
-
null是个假值;所以,null == undefined ;为true。
-
一律用===,只有判断是不是等于 null 或 undefined 才用==。
-
null==0 ;//false
-
!null==true;//true 常用于if判断
3.Boolean
所有数据类型都可以转化为布尔值。数据转化为布尔值的规律:只有0/NaN/null/undefined
五个值是false,其余全为true
4.number
5.string
-
1、toString(): 除了null和undefined值没有tostring()方法,其他值都有这个方法,该方法返回字符串的一个副本。
-
2.String():如果不确定一个值是null或undefined,可以使用String()转型函数,始终会返回相应类型值的字符串.
-
3.使用+" ": 即可以通过要转换的值 + 空字符串(" "),也可以实现转换。
-
ES6新增的模板字面量使用反引号包裹,它的作用是保留换行字符,可以跨行定义字符串,可以通过${}插值。
1.2 object引用数据类型
Object,即对象,是一组数据和功能的集合。
1.3 隐式转化
- 1转成String类型---- 1.字符串连接符(+)转成字符串。
- 2.转成Number类型(数学运算中)--判断
相等吗?大于吗
,一般都要转化成数字进行比较 - 3.转成Boolean型(逻辑判断中)--一般if()里面写上null就不执行,写上{}、[]、!null都会执行
1.4 数据类型检测(四种)
1.typeof基本数据类型检测
-
typeof [val] 检测基本类型值还是很准确的,返回当前值对应的数据类型(小写字符串),但不能检测基本数据类型的null值,typeof null =>"object" 【01开头存储的是对象。】;
-
typeof 无法对对象数据类型细分,返回的都是 "object";
2.[val] instanceof 类
- 判断当前类是否在这个被检测数据的原型链上。
- 对于数组、正则、对象,函数可以细分一下,但是无法检测基本数据类型
xxx instanceof Object/Array/Function
3.constructor
[val].constructor === 类;
因为获取实例的constructor实际上获取的是直接所属的类,判断比较准确
4.Object.prototype.toString.call([val])
- 在其它数据类型的内置类原型上有toString,但是都是用来转换为字符串的,只有Object基类原型上的toString是用来检测数据类型的。
console.log(Object.prototype.toString.call(a));//[object Array]
1.5 如何判断数组和对象?isArray、instanceof、constructor、toString
//方法一:ES6中通过Array.isArray()识别
Array.isArray([])//true
Array.isArray({})//false
//方法二:通过 `实例 instanceof 类`:
console.log({} instanceof Array)//false
console.log(['111','222'] instanceof Array)//true
//方法三:constructor
console.log([].constructor.name==='Array')//true
console.log({}.constructor.name==='Object')//true
//方法四:通过Object.prototype.toString.call()
Object.prototype.toString.call({}) //"[object Object]"
Object.prototype.toString.call([]) //"[object Array]"
二.变量提升
- 变量提升机制可以
使变量先使用,后声明
。var和function定义的变量存在变量提升机制,var是先声明,再初始化。function是声明和初始化一起进行。 - var : 可以重复定义;变量提升;定在单独{}中的依然是全局变量。
- let : 同一作用域不能重复定义;没有变量提升;定在单独{}中的是局部变量。
- const :定义常量,const仅保证指针不发生改变,所以定义的基本数据类型不可修改;但是引用数据类型可以被修改,
- let /const/function会把当前所在的大括号(除函数之外)作为一个全新的块级上下文,应用这个机制,在开发项目的时候,遇到循环事件绑定等类似的需求,无需再自己构建闭包来存储,只要基于let的块作用特征即可解决
三. 函数执行过程
- 形成私有上下文--》进栈执行---》一列列操作(初始化this、形参赋值、变量提升、代码执行)---》执行完后释放私有上上下文(执行环境栈)
- 若果当前私有上下文的某个东西(一般是一个堆)被上下文以外的事物占用了,则不会出战释放,形成不销毁的上下文.也就是闭包。
3.1 高阶函数与闭包
高阶函数有两种形式:(1)、如果一个函数可以接受函数作为它的参数,那么就把这个函数称之为高阶函数。(2)、如果一个函数的返回值是一个函数,那么这个函数就是高阶函数。
3.2 闭包
- 如果一个函数的作用域(A)有权访问另一个函数作用域(B)中的变量,那么我们就可以认为被访问的函数(B)是闭包。通常是嵌套函数中实现的。
- 闭包的作用:延伸了变量的作用范围,fn外面的作用域可以访问fn里面的作用域
- 闭包应用1
const li = document.getElementsByTagName("li");
for (var i = 0; i < li.length; i++) {
(function (i) {
li[i].onclick = function () {
console.log(i);
};
})(i);
}
3.3 堆栈内存
- 栈内存是代码执行环境栈,用来执行代码和存储基本类型值的(创建的变量也存栈里面了);
- 栈内存有全局执行上下文、函数执行形成的私有上下文、块级作用域
- 堆内存:用来存储引用数据类型值的 , 浏览器会把内置的属性和方法放到一个单独的内存中;然后在栈中存储一个指针指向它。
堆内存销毁
如果堆内存用完后想释放可以让变量指向空指针对象null。栈内存销毁
全局栈内存:关掉页面的时候才会销毁;一般情况下,函数只要执行完成,形成的私有栈内存就会被销毁释放掉,但是如果是闭包函数,可能不会被立马销毁。
四.一些运算符
4.1 自增自减++i和i++
++i是先自增然后参与运算; i++是先运算,再自增
4.2 相等和全等
- js中一律用===,只有判断是不是等于 null 或 undefined 才用==。
4.3 逻辑运算符||(或),&&(与),!(非)
逻辑短路现象:
//与运算--- 条件A && 条件B
如果条件A不成立, 那么就返回条件A
如果条件A成立, 无论条件B是否成立, 都会返回条件B
短路现象----一假则假, 所以只要条件A是假, 那么条件B就不会运算,综合结果结果就是为假
//条件A || 条件B
如果条件A成立, 那么就返回条件A。
如果条件A不成立, 无论条件B是否成立, 都会返回条件B。
因为在逻辑或运算中,有一个逻辑短路现象:由于逻辑或运算的规则是一真则真, 所以只要条件A是真, 那么条件B就不会运算
4.4 剩余/扩展运算符(...)
- 剩余运算符就是使用三个点
...
把项拆开,可以拆开字符串、数组、对象。 - 剩余参数是将多余的参数保存到数组中;扩展运算符是将数组每项拆开
- 1.
数组拷贝(copy)
var arr = [1, 2, 3];
var arr2 = [...arr];
arr2.push(4);
console.log(arr, arr2);//[1, 2, 3] [1, 2, 3, 4]
- 2.
连接数组
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
//var arr3 = arr1.concat(arr2);和下面一句一样
var arr3 = [...arr1, ...arr2];
//或者
arr1.push(...arr2)
- 3.函数调用时用展开语法展开实参。
- 4.作为剩余参数--当函数的实参个数大于形参个数,我们可以把多余的参数放到一个数组中,给这个数组加
...
- 5.将类数组转化为真正的数组--元素集合、实参列表,【其实利用数组的Array.from(arguments)也可以】
五.逻辑结构-if、switch、while、do...while...、for
- 1.if 用于区间判断;
- 2.可列举的固定值判断可以用switch;
let day = 7;
switch (day) {
case 1:
console.log("星期1");
break;
case 2:
console.log("星期2");
break;
case 3:
console.log("星期3");
break;
default:
console.log("Other");//执行这个打印other
break;
}
- 3.
while 循环语法--找到0-100之间能被7整除的
while(条件表达式){
条件满足执行的语句;
}
- 4.
do...while 循环
--输入密码验证
do{
需要重复执行的代码;
}while(条件表达式);
//无论条件表达式是否为真, 循环体都会被执行一次
let pwd;
do {
pwd = prompt("请输入正确的密码");
} while (pwd !== "123456");
alert("欢迎回来");
- 5.
for 循环
1.for循环的格式
for(初始化表达式;条件表达式;循环后增量表达式){
需要重复执行的代码;
}
2.for循环的特点
for循环的特点和while循环的特点一样, 只有条件表达式为真, 才会执行循环体
3.for循环的执行流程
3.1首先会执行初始化表达式, 并且只会执行一次
3.2判断条件表达式是否为真, 如果条件表达式为真, 就执行循环体
3.3执行完循环体就会执行循环后增量表达式
3.4重复3.2~3.3, 直到条件表达式不为真为止
//正三角
for (let i = 0; i <= 5; i++) {
for (let j = 0; j < i; j++) {
document.write("❤");
}
document.write("<br />");
}
//倒三角
for (let m = 0; m < 6; m++) {
for (let n = m; n < 6; n++) {
document.write("❤");
}
document.write("<br />");
}
99表,
//外循环控制换行,内循环控制每行显示
for (let i = 1; i < 10; i++) {
for (let j = 1; j <= i; j++) {
document.write(`${j}x${i}=${i * j}    `);
}
document.write("<br />");
}
六.数组Array
- 数组是指一组有序数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。
- 数组的索引(index)从0开始,数组的长度(length)从1开始。
- 数组的索引用于获取数组项
arr[index]
,数组的长度可以用来遍历数组,在数组末尾增加或删除元素。
6.1创建数组的四个方法
- 1.字面量法
- 2.构造函数方法
- 3.Array.from()可以将类数组或者可迭代对象转化为数组
- 4.Array.of(0, 2, 4, 6, 8));// [0, 2, 4, 6, 8]可以将一组参数转化为数组实例
6.2四种数组检测方法
- 1.Array.isArray(arr)
- 2.实例 instanceof 类
- 3.constructor
[].constructor.name==='Array'
- 4.
Object.prototype.toString.call(arr)
// [object Array]
6.3 增删改查
6.3.1 增加五种(下标、push、unshift、splice、concat)
let array=[1,2,3,4,5]
//1.通过下标增加
array.[array.length]=6
//2.Array.push()从后面增加
array.push("a", "b");
//3.unshift()前面数组
array.unshift('0')
//4.splice(a,b,5,6,78,9) 指定位置增加
//这个方法的意思:从第a个元素的后面删除b个,并把后面的都加到数组,a是index
//5.concat拼接
var arr = ['a','b','c'];
var arr2 = arr.concat('d',1,2,['e',3]);
console.log(arr2); // ["a", "b", "c", "d", 1, 2, "e", 3]
6.3.2 删除四种(pop、shift、slice、splice)
var arr = ["a", "b", "c", "d", 1, 2];
//1.pop()方法删除数组的最后一项,返回被删除的项。
let de = arr.pop();
//2.shift()删除数组的第一项并返回删除项
arr.shift();
//3.使用slice(a,b)截取多个,不操作原数组,返回的数组是截取的值
//从索引a截取,到索引b,包含a不包含b
//4.使用splice() 方法指定位置删除
//splice()原本的意思是在删除元素的同时可以在指定位置插入新元素,
//传入3个参数:开始位置,要删除元素个数,要插入的任意多个元素;
//
var arr = [1,2,3,4,'a','b','c'];
var arr2 = arr.splice(2,2);//从index为2的位置删除两个,包头
console.log(arr); // [1, 2, "a", "b", "c"]
console.log(arr2); // [3, 4]
6.3.3 更改数组一种---splice() 方法改变一个数组
splice(a,b,1,2,3,4)
从index为a的那个元素开始删除b个元素,然后把后面的元素添加进来,并返回
6.3.4 查询数组(索引查找、indexOf、include、find、findIndex、slice)
除了用原始的索引号查询数组外,js还提供了许多方法查询数组
let arr=[1,2,3,4]
//1.index查询
//arr[0]、arr[1]、arr[arr.length-1]
/*
2.indexOf()通过元素查找索引
返回数组中第一个满足条件的索引(从0开始), 不满足返回-1;
.有两个参数,第一个是要查找的元素;第二个是从哪个位置(索引值)开始查找。
lastIndexOf()从后往前查找
*/
var array = [2, 5, 9];
array.indexOf(2); // 0
array.indexOf(7); // -1
array.indexOf(9, 2); // 2
array.indexOf(2, -1); // -1
array.indexOf(2, -3); // 0
//3. include()表示数组中是否有这样一项,返回 true 或 false
var num = [10, 20, 30, 40, 50, 60, 70, 80, 90];
var newNum7 = num.includes(40);
var newNum8 = num.includes(40, 5);//从索引5的位置开始向后查找
console.log(newNum7);//true
console.log(newNum8);//false
/*
4.find()返回第一个符合条件的数组项
接受一个函数参数,函数依次接受三个参数:数组当前项value,数组当前项索引,数组本身
函数里面写上return语句,ruturn返回的是true则find返回的是满足条件的项
*/
var inventory = [
{ name: "apples", quantity: 2 },
{ name: "bananas", quantity: 0 },
{ name: "cherries", quantity: 5 },
];
function findCherries(value, index, item) {
// console.log(value, "数组当前项的值");
// console.log(index, "当前项索引");
// console.log(item, "数组本身");
return value.name === "cherries";
}
console.log(inventory.find(findCherries)); // { name: 'cherries', quantity: 5 }
//5. findIndex()返回数组中第一个满足条件的索引(从0开始), 不满足返回-1;和find用法一样
//6. 使用slice() 方法提取数组的数据:
var arr = [1,2,3,4,5,6];
var arr2 = arr.slice(-3);
console.log(arr); // [1, 2, 3, 4, 5, 6]
console.log(arr2); // [4, 5, 6]
6.4 排序(reverse、sort)
1.翻转数组
Array.reverse():将数组中元素的位置颠倒,并返回该数组。该方法会改变原数组
2.大小排序sort
- sort接受一个函数参数,函数接受两个值a,b;若果函数返回a-b则正序,返回b-a则倒序(大到小),sort改变原数组,返回处理好的原数组
let a=[2,1,5,7,21,12,33,46,64,0,2,7,8]
a.sort((a,b)=>a-b)//升序
a.sort((a,b)=>b-a)//降序
6.5 其他方法
6.5.1 Array.concat()
用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
let array=[10,20,30,40];
let array1=[50,60];
console.log(array.concat(array1));//[10, 20, 30, 40, 50, 60]
var arr = ['a','b','c'];
var arr2 = arr.concat('d',1,2,['e',3]);
console.log(arr2); // ["a", "b", "c", "d", 1, 2, "e", 3]
6.6 Array.splice()增删改
- 删除 =>可以删除任意数量的项,只需指定
两个参数
,要删除第一项的位置
和要删除的项数
- 插入=>可以向指定位置插入任意数量的项,只需提供
3个参数
,起始位置,0,要插入的项,如果要插入多个项,可以传入第n项,第n+1项,... - 替换=>可以向指定位置
插入任意数量的项
,且同时删除任意数量的项
,只需指定3个参数,起始位置,要删除的项数和要插入的的任意数量的项,插入的项数不必与删除的项数相等
6.7 Array.join()
join() 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。
var a = ['Wind', 'Rain', 'Fire'];
var myVar1 = a.join(); // myVar1的值变为"Wind,Rain,Fire"不写分隔符默认以逗号分割
var myVar4 = a.join(''); // myVar4的值变为"WindRainFire"
6.8 数组迭代(5种)
1.Array.every()判断所有条件是否都满足,满足返回true
Array.every((item,index,array)=>item>10)
:对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true.
2.Array.some()只要有满足条件的就返回true
Array.some((item,index,array)=>条件判断)
:对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true
3.Array.filter()将满足条件的数组筛选出来
Array.filter((item,index,array)=>条件语句判断)
:对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。
let arrays = [11, 22, 3, 4, 5, 4, 3, 2, 1];
let everyResult = arrays.filter((item, index, array) => {
return item > 10;
});
console.log(everyResult); [11,22]
4.Array.forEach()没有返回值只是对每个元素都执行--可以批量操作
Array.forEach((item,index,array)=>{操作数组})
:forEach() 方法对数组的每个元素执行一次给定的函数,没有返回值。
let arrays = [
{
name: "cc",
},
{
name: "aa",
},
];
arrays.forEach((item, index, array) => {
item.time = new Date();
});
console.log(arrays);
5.Array.map()对数组所有项做相同操作并返回新数组
Array.map((item,index,array)=>操作数组)
:对数组中的每一项运行给定函数,返回每次函数调用的结果返回的数组
let arrays = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let mapResult=arrays.map((item,index,array)=>{
return item*2;
})
console.log(mapResult);// 2,4,6,8,10,8,6,4,2
数组归并方法Array.reduce(total,current)可以作为一个累加器
接受两个参数第一个是前一项,第二个是当前项
let arrays = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let sum = arrays.reduce((total, current) => {
return total + current;
});
console.log(sum);
es6新增数组方法
1.Array.of()和Array.from()
- Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。
Array.of(1,2,3,4);//[1,2,3,4]
- Array.from()将类似数组对象和可遍历(iterable)的对象转化为数组。 常见类数组对象:NodeList 集合,函数内部的arguments对象, 可遍历对象terator 接口:字符串和 Set 结构
2.Array.copyWithin()填充数组和 Array.fill()批量替换
Array.fill()方法将固定值填充到数组指定位置,接受参数如下:
- value:需要填充的值
- start:填充的起点
- end:填充的终点(不包含的index),若果star和end相同填充失败
[1, 2, 3].fill(4, 1); // [1, 4, 4]
[1, 2, 3].fill(4, 3, 3); // [1, 2, 3]
3.Array.find()和Array.findIndex()和Array.includes()
数组深拷贝
- 方法一:原生
Array.prototype.mySlice = function () {
const arrNew = [];
for (let i = 0; i < this.length; i++) {
arrNew.push(this[i]);
}
return arrNew;
};
var array = [1, 2, 3, 4, 6];
var arrayNew = array.mySlice();
- 方法二:concat拼接数组,返回新值
const array = [1, 2, 3, 4, 6];
const arrayNew = array.concat();
- 方法三:slice截取数组,返回截取值
const array = [1, 2, 3, 4, 6];
const arrayNew = array.slice();
- 方法四:扩展运算符
const array = [1, 2, 3, 4, 6];
const arrayNew = [...array];
//或者
var arr1 = [1, 2, 3];
var [...arr2] = arr1;
数组最大值
- 方法一:原始
let arr = [3, 5, -2, 7, 4];
let max = arr[0];
for(let i = 1; i < arr.length; i++){
if(arr[i] > max){
max = arr[i];
}
}
console.log(max);
- 方法二:sort数组排序(从大到小)取第一个
const arr1 = [66, 31, 2, 68, 3, 66];
let max = arr1.sort((a, b) => b - a)[0];
console.log(max);
- 方法三:forEach()循环里面取item判断然后赋值
const arr1 = [66, 31, 2, 68, 3, 66];
let max = arr1[0];
arr1.forEach(function (item, index, arr1) {
if (item > max) {
max = item;
}
});
console.log(max);
- 方法四:用math.max()方法
let arr = [3, 5, -2, 7, 4];
let max = Math.max(...arr);
// let max = Math.max.apply(Math, arr); // max中的this还是Math
console.log(max);
数组去重
- 1.定义一个空数组放去重后的数组元素,forEach()遍历数组每一项,然后判断去重数组里面有没有该项,没有的话就添加进去。
let arr = [3, 5, -2, 7, 4, 4, 6, 5, 3];
const arrUnique = [];
arr.forEach((item) => {
if (arrUnique.indexOf(item) === -1) {
arrUnique.push(item);
}
});
console.log(arrUnique);
- 2.
先排序在去重
--先将原数组排序,在与相邻的进行比较,如果不同则存入新数组
let arr = [3, 5, -2, 7, 4, 4, 6, 5, 3];
const arrUnique = [];
arr.sort((a, b) => b - a);
arrUnique.push(arr[0]);
arr.reduce((pre, cur) => {
if (pre !== cur) {
arrUnique.push(cur);
pre = cur;
}
return pre;
});
console.log(arrUnique);
- 3.对象的属性去重(推荐) 每次取出原数组的元素作为对象的属性名进行赋值,然后用对象方法访问这些属性名赋值给数组,最后用map去除字符串
arr = [1, 7, 4, 5, 3, 4, 5, 6, 8, 6, 9, 6, 5, 6, 4, 6, 67, 7];
arrUnique = {};
arr.forEach((item, index) => {
arrUnique[item] = "蔡徐坤";
});
arrUnique = Object.keys(arrUnique);
arrUnique = arrUnique.map((item) => ~~item);
console.log(arrUnique);
- 4.下标去重for+indexof
function arrUnique(arr) {
let uni = [arr[0]];
for (let i = 1; i < arr.length; i++) {
if (uni.indexOf(arr[i]) === -1) {
uni.push(arr[i]);
}
}
return uni;
}
- 5.ES6 中的Set实现去重(ES6中最常用)
function arrUnique(arr) {
arr = new Set(arr);
arr = Array.from(arr);
return arr;
}
- 6.es6的filter()和indexOf()
function arrUnique(arr) {
let arrNew = arr.filter((item, index) => arr.indexOf(item) === index);
/*
在原数组里面找到当前项返回的索引是当前值吗,如果相等就添加到去重数组里面,
不相等就代表前面还有一个和当前item相同的项,当前的不应该添加
*/
return arrNew;
}
- 7.遍历原数组,
includes
判断新数组中是否有遍历的当前项,没有则添加入新数组
function arrUnique(arr) {
const arrNew = [arr[0]];
for (let i = 0; i < arr.length; i++) {
if (!arrNew.includes(arr[i])) {
arrNew.push(arr[i]);
}
}
return arrNew;
}