十、数据类型的区别
- 基本数据类型:按值操作,值存储在栈内存中;
- 引用数据类型:按照堆内存的地址来操作,我们把对象的键值对存储在堆内存中,我们操作的是堆内存的引用地址;
let a={},b=Symbol('1'),c=Symbol('1');
a[b]='哈哈';
a[c]='呵呵';
console.log(a[b]);//='哈哈'
/:唯一值相同不会替换。
十一、js中创建变量的六种方式
var\function\let\const\class\import
十二、数据类型面试题
1、

2、考察parseInt原理
var str = 'abc123';
var num = parseInt(str);//=NaN数字类型
if (num == NaN) {
console.log('NaN');
} else if (num == 123) {
console.log(123);
} else if (typeof num == 'number') {
console.log('number');
}
else{
console.log('str');
}
//='number'
3、考察输出
console.log(alert(1));/=undefined
/=原理:先执行alert,把alert执行的返回结果输出,alert没有返回结果,所以输出:undefined
typeof undefined; /=undefined
consloe.log(parseInt(undefined));/=NaN
isNaN(undefined);/=true
4、考察isNaN、parseInt、Number
- parseInt、Number各自有规则;
- isNaN:参照Number规则,先转数据为数字类型;
isNaN(null);/=false,null转为数字类型为0;
parseInt(null);/=NaN
isNaN(parseInt(null));/=true,相当于isNaN(NaN);
Number(null);/=0
parseInt("");/=NaN
Number("");/=0
isNaN("");/=false
5、考察基本数据类型
- js中比较两个值:
== 、===、ES6的Object.is 规则:null==undefined为true,只要没有布尔、数字,都是转为字符串或对象比较;下方(十六、有详情)==:如果左右两边数据类型不同,则先转为相同类型,再进行比较;至于转为什么类型,谁转为谁有自己的规则;- 推测:只要有(Boolean)布尔类型、(Number)数字类型时,都转为数字类型比较;
- 有字符串或引用类型就转为字符串比较;
isNaN(NaN) == "";
==>true == "";/=false
有布尔类型转数字比较;
6、关于<script>标签放在页面头部与尾部的区别,以及解决方法?
十三、条件判断、循环
1、js中常用判断语句
if 、else if 、else- 三元运算符:处理最简单的
if else情况:x>10? x++:x--;情况1:如果不想处理一些情况,就用null、undefined占位,不占位会报错;x>10 ? x++ : null;情况2:如果要处理的一种情况需要做多件事,则用小括号包裹,并且每件事之间用逗号分隔;x>10 ? (x++,console.log(x)) : null;
switch case break:一个变量在不同情况下有不同操作时使用;- 每一种情况结束都要使用
break不再向下执行,最后一个default就不需要加了,因为没有能再执行的了; - 每一步
case都是按照===规则选择的; switch(x){ case1:x += 1;break; }
- 每一种情况结束都要使用
2、for循环、for in循环
- 循环:一轮一轮重复做某件事;循环一个集合,或控制循环次数;
- 循环体中可能出现的关键字:
break:整个循环结束,当前循环有剩余代码也不执行,下一次i++也不执行;continue:直接结束本轮循环,当前循环体下面代码不再执行,下一次i++正常执行;
for循环可以遍历\循环\迭代一个数组;因为数组有索引、length;for(var key in obj){}:遍历对象;- 当前对象有多少可枚举属性就循环多少次;
- 每次循环属性名赋值给
key;使用obj[key]获取当前属性值;注意不要使用obj.key、obj['key']获取 for in 循环的顺序会先按数字排序(如果属性名有数字),其他正常先后顺序;
var n = 10;
for (; n > 0;) {
if(n>5){
n-=2;
}
else{
n-=3
}
}
console.log(`${n}`);/= '-2 '
3、死循环,程序不输出
for(var i=3;i<10;i++){
i--;
}
console.log(i);/= 没有输出
4、i++、i+=1、i=i+1
i++:默认为i=Number(i)+1;也是与其他两者的区别;i+=1==i=i+1
let a = '10';
a == 10 ? a++ : a--;
console.log(a);/= 11
十四、DOM操作
DOM概念:文档对象模型,提供一系列属性和方法,让我们能操作页面中的dom元素;
1、获取DOM元素概念
- 基于JS获取到的DOM元素是
对象数据类型的值,里面包含很多浏览器自带的用来操作元素的键值对;- 如:
id:'box';存储元素的ID style:{};存储当前元素的行内样式- 注意点:在设置行内样式的颜色时,使用基于16进制
#fff、rgb表示写法时rgb(255 255 255),得到的是RGB形式,所以推荐写英文单词;
- 如:
let box = document.getElementById('box');
---方式一:
box.style.color='red';/=可以修改,因为是操作堆内存
---方式二:
let boxSty = box.style;//指向样式对象
boxSty.color='red';/=可以修改,也是操作堆内存
---方式三:
let text = box.style.color;//指向""空字符串
text = 'red';/=不能修改,相当于给text赋值;
2、获取DOM元素常用方法
document.getElementById('box');:获取指定元素对象,在堆内存中;document.getElementByTagName('li');:获取HTMLCollection元素集合(类数组),也是对象,内部每一项也是对象;
十五、函数
1、概念
- 本质:把实现一个功能的代码封装起来,以后实现功能只需要执行函数,无需再写一遍代码;
- 目的:封装;
- 创建函数:生产洗衣机
function 函数名(形参1,...){}:参数规定放几件衣服,函数体规定怎么洗;
- 执行函数
函数名(实参1,...):放衣服开洗;
2、针对for循环产生的变量问题(var)
- 解决一:自定义属性编程思想:解决for循环后的
var i值问题;(没有兼容性问题)
for (let i = 0; i < itemList.length; i++) {
var bgc = 'white',
item = itemList[i];
i%2 !== 0 ? bgc='pink':null;
item.style.backgroundColor = bgc;
item.myBg = bgc;//自定义属性
item.onmouseover = function () {
this.style.backgroundColor = 'green';
}
item.onmouseout = function () {
this.style.backgroundColor = this.myBg;
}
}
- 解决二:闭包思想(没有兼容性问题)
for (let i = 0; i < itemList.length; i++) {
(function (i) {
var bgc = 'white',
item = itemList[i];
i%2 !== 0 ? bgc='pink':null;
item.style.backgroundColor = bgc;
item.onmouseover = function () {
item.style.backgroundColor = 'green';
}
item.onmouseout = function () {
item.style.backgroundColor = bgc;
}
})(i)
}
---另一种闭包形式
[].forEach.call(btnList,(item,index)=>{
item.onclick = function(){
alert(`当前点击按钮的索引为${index}`)
}
})
- 解决三:let声明变量(es6)–与闭包原理相似
for (let i = 0; i < itemList.length; i++) {
let bgc = 'white',
item = itemList[i];
i%2 !== 0 ? bgc='pink':null;
item.style.backgroundColor = bgc;
item.onmouseover = function () {
item.style.backgroundColor = 'green';
}
item.onmouseout = function () {
item.style.backgroundColor = bgc;
}
}
- 定义函数变量、函数声明、事件绑定都是只创建函数,此时函数中代码只是在堆内存中存储的字符串;
3、函数创建与执行的堆栈运行机制
- 创建:形成新的堆内存
- 执行:形成新的执行上下文栈内存;
- 形参:创建函数时设定的变量,对应实参不传就是undefined;
- 实参:执行函数时给形参传递的具体值,可以是变量、具体值、表达式,最终传进去的都是最终值(js数据类型);
4、形参、实参
- 指定数求和:
function(x,y,z,...){}有几个数,用几个形参接收; - 任意数求和:不确定实参个数,所以没法设置形参个数;
- 实参集合(箭头函数中没有):
function(){ console.log(arguments) };是类数组,与HTMLCollcetion类似;通过for循环使用; - es6的剩余运算符:
function(...args){ console.log( args ) }
- 实参集合(箭头函数中没有):
5、函数返回值return
return;:下面代码不再执行;return [变量、函数]:返回函数内部私有的变量,外部得到的是这个变量的值,需要外部定义新的变量接收(或者直接使用);
function sum(){
let a = 1;
return a
}
var aa = sum();/函数中不写return,返回undefined
console.log(aa);/=1
6、函数类型
- 实名函数:
function func(){} - 匿名函数:
- 函数表达式:
var func = function(){}; - 立即执行函数:
(function(n){})(n); - 箭头函数:
var func = ()=>{}
- 函数表达式:
十六、数据类型间比较的规则
1、==的比较规则
- 左右两边数据类型不同时,转为统一类型;
哪到底转成什么类型?
相同类型间:
NaN == NaN; /= false; NaN 跟任何值都不相等
Infinity == Infinity; /=true; 只和自己想等
Symbol(1) == Symbol(1); /=false; Symbol() 跟任何值都不相等
对象 == 对象; /= 比较地址,相等true,不等false
---
不同类型间:
null == undefined; /=true;除此之外,它们和任何值都不相等;
对象 == 字符串; /= 对象转为字符串
除此以上情况外,都转为 数字进行比较。
(只要没有布尔、数字,都是转为字符串或对象比较)
十七、数组
特殊的对象,属性名是索引;有length属性;
1、一维数组、多维数组
一维:let arr = [1,2,3];
二维数组:子项也可以展开
let arr = [1,{a:1}];
let arr = [1,[1,2]]
2、需要掌握
- 基础操作
arr[arr.length] = 1;数组末尾追加;for( let i=0;i<arr.length;i++ ){};遍历索引for( let index in arr ){};遍历属性名(索引)for( let item of arr ){};遍历属性值- 删除:
delete arr[0];但是数组长度不变,删除项为空,所以一般不用这种方式; - 删除最后一项:
arr.length--
- 内置方法(浏览器自带的方法)
- 排序、去重(算法)
- 扁平化、深度克隆
- 扁平化:数组的扁平化指将一个多维数组变为一维数组
[1, [2, [3, 4]]]--->[1, 2, 3, 4]
如果只有两层:let array = [1, [2, 3, 4]];
方法一:
function flatten(arr) {
return Array.prototype.concat.apply([], arr); /= apply第二个参数就是数组形式
}
方法二:
function flatten(arr) {
while(arr.some(item=>Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
console.log(flatten(array));
多层:let arrayDeeper = [1, [2, [3, 4]]];
方式一:toString&split&map方法
function flattenDeeper(arr){
return arr.toString().split(',').map((item)=>parseInt(item))
} /=map方法将字符串转为数字类型
方式二:reduce&concat方法
function flattenDeeper(arr) {
return arr.reduce((result, item)=> {
return result.concat(Array.isArray(item) ? flattenDeeper(item) : item);
}, []);
}
方法三:join&split&map方法
function flattenDeeper(arr){
return arr.join().split(',').map((item)=>parseInt(item))
}
let arr1 = [1,[2,3,[4,5]]]
console.log(flattenDeeper(arr1))//[1,2,3,4,5]
3、常见内置方法
- 记忆方式:
- 方法的意义和作用
- 参数
- 返回值
- 原始数组是否改变
- 1、关于数组的增删改
| 数组方法 | 作用 | 参数 | 返回值 | 原数组是否改变 |
|---|---|---|---|---|
| push | 数组末尾追加元素 | 参数个数、类型不固定 | 新增数组的长度 | 改变 |
| pop | 数组末尾删除一个元素 | 无 | 被删除的末尾数组元素 | 改变 |
| unshift | 数组开头追加元素 | 参数个数、类型不固定 | 新增数组的长度 | 改变 |
| shift | 数组开头删除一个元素 | 无 | 被删除的开头数组元素 | 改变 |
| splice | 实现数组指定位置的增删改 | 删:arr.splice(n,m),从索引n开始删m项增: arr.splice(n,0,x,..)改: arr.splice(n,m,x,..),从索引n开始删m项,用新元素替换 | 被删元素组成的数组;没有删除的返回[] | 都改变 |
- 2、关于查询和拼接
| 数组方法 | 作用 | 参数 | 返回值 | 原数组是否改变 |
|---|---|---|---|---|
| slice | 从数组中查询元素;浅克隆 | let newArr = arr.slice(n,m)从索引n开始,查到索引m的前一项 | 返回一个新数组,包含查询到的元素 | 不改变 |
| concat | 实现数组拼接;浅克隆 | let newArr = arr.concat('aa',arr1)传具体值、要连接的数组 | 返回连接后的新数组 | 不改变,目标数组也不改变 |
- 3、关于数组转为字符串
| 数组方法 | 作用 | 参数 | 返回值 | 原数组是否改变 |
|---|---|---|---|---|
| toString | 将数组转为字符串,以逗号分隔 | 无 | 返回字符串 | 不改变 |
| join | 将数组转为字符串,以指定符号分隔 | arr.join('-'),指定分隔符,不写默认,逗号 | 返回字符串 | 不改变 |
- 4、关于包含、排序
| 数组方法 | 作用 | 参数 | 返回值 | 原数组是否改变 |
|---|---|---|---|---|
| indexOf | 查询指定元素首次出现的索引 | arr.indexOf(item,start)所查元素内容,开始查询的位置 | 返回Number类型,查到则为第一次出现位置的索引;没有查到返回-1 | 不改变 |
| lastIndexOf | 查询指定元素最后出现的的索引 | array.lastIndexOf(item,start)所查元素内容,开始查询的位置 | 返回Number类型,查到为最后一次出现位置的索引;没有查到返回-1 | 不改变 |
| includes | 判断一个数组是否包含一个指定的值 | arr.includes(searchElement, fromIndex)要查询的元素,开始位置 | 返回布尔类型值; 包含:true;不包含:false | 不改变 |
| reverse | (排序)用于颠倒数组中元素的顺序 | 无 | 返回颠倒后的原数组 | 改变 |
| sort | (排序)按规则排序数组 | 函数规则 | 返回改变后的原数组 | 改变 |
- 5、关于数组中迭代方法
| 数组方法 | 作用 | 参数 | 返回值 | 原数组是否改变 |
|---|---|---|---|---|
| forEach | 遍历数组中每一项,可得到当前项值与索引 | 函数参数arr.forEach(function(item,index){}) | undefined,处理函数中return无效 | 不改变 |
| map | 遍历数组中每一项,可得到当前项值与索引 | 函数参数let newArr = arr.map(function(item,index){ return item*2 }) | 返回处理后新数组 每一项返回值由return决定; | 不改变 |
- 扩展:数组每项求和
let arr = [100,200,300];
let total = 0;
// --for循环
// for(var i=0;i<arr.length;i++){
// total += arr[i]
// }
// --for of循环
// for(let item of arr){
// total += item
// }
// --转字符串
// var str = arr.join('+');
// total = eval(str)
// --es6的reduce
total = arr.reduce((pre,item)=>{
return pre += item
},0)
console.log(total);
4、数组去重(12种)
- 双for循环(有问题)
- 问题:数组塌陷(数组元素减少时导致的后面元素前移)
- 原因:splice删除是直接删除原数组,所以每删除一项会导致后面数据前移,索引发生变化,如果不用
j--,就会产生每次删除后再循环时就会隔过去一项数据元素; - 解决:每次删除后随即调用
j--,用来与下次循环的j++抵消; - 优化:
splice删除优化(让后面每一项前移太耗性能),不在当前项删除,而是用最后一项替换这一项,把最后一项删除,因为本来就是为了去重,不考虑原有顺序问题;
let arr = [1,2,3,2,3,4,5,2,3,4,2,1,3,2,4];
for(let i=0;i<arr.length-1;i++){
let item = arr[i];
for(let j=i+1;j<arr.length;j++){
if(arr[j]===item){
arr.splice(j,1);==>改进:arr[j] = arr[arr.length-1];arr.length--;或arr.pop()
j--;/= 解决splice删除引发的数组塌陷问题
}
}
}
console.log(arr);
- 对象的键值对方式
- 弊端:去重数组中不能包含对象、函数,因为属性名不能为这些;而且数字与字符串一样的值也会认为重复;多个
undefined不会去重; - 优点:单循环,性能好点
- 弊端:去重数组中不能包含对象、函数,因为属性名不能为这些;而且数字与字符串一样的值也会认为重复;多个
:将数组每一项当做对象的键与值;如果属性名存在那当前项就是重复的。
let arr = [1,2,3,1,1,4]
let obj = {}
for(let i=0;i<arr.length;i++){
let item = arr[i]
if(obj[item] !== undefined){
arr[i] = arr[arr.length-1] /=这是改进写法,将最后一项的值拿过来,删除最后一项
arr.length--; /= 属性值不是undefined,就删除数组中这项
i--;
continue;
}
obj[item] = item;/= 属性值是undefined就正常存对象里,数组中不删
}
console.log(arr);/= [ 1, 2, 3, 4 ]
- Set数据结构:类似数组
let arr = ['a','a','b',1,2,1];
const set = new Set(arr);/=伪数组 Set(4) {"a", "b", 1, 2};有size属性替换length;
转真正数组:
const newArr = [...set];
或者const newArr = Array.from(set);
console.log(newArr);//[ 'a', 'b', 1, 2 ]
JS数据类型与数组详解
本文深入探讨JavaScript中的数据类型区别,包括基本与引用类型的特点,解析数据类型间的比较规则,以及六种创建变量的方式。此外,文章还详细介绍了数组的操作方法,包括一维与多维数组的管理,常见内置方法的使用,以及数组去重和扁平化的多种实现方案。
4万+

被折叠的 条评论
为什么被折叠?



