1.JavaScript数据类型与运算符
1.数据类型
原始数据类型:
- Number
- String
- Boolean
- undefined
- null
- Symbol
- bigint
2.复杂数据类型:
- Function
- 非函数:
- Array: 数组
- Object: 对象
- Date: 日期
- RegExp: 正则
- Map: 映射
- Set: 集合
- WeakMap: 弱映射
- WeakSet: 弱集合
- FormData: 表单数据
3.判断数据类型
- typeof 运算符 ⼀般⽤来 判断基本数据类型 ,如:string,number,boolean,symbol,bigint(es10新增⼀种基本数据类型bigint),undefined等。返回数据类型的字符串形式 typeof ⽬前能返回string,number,boolean,symbol,bigint,unfined,object,function这⼋种判断类型,但是注意 null 返回的是 Object
为什么typeof null 是 Object? 因为在JavaScript中,不同的对象都是使⽤⼆进制存储的,如果⼆进制前三位都是0的话,系统会判断为 是Object类型,⽽null的⼆进制全是0,⾃然也就判断为Object 扩展:
- 000 对象
- 1 整型
- 010 双精度类型
- 100字符串
- 110布尔类型
- 1000 Symbol类型
- 1001 bigint类型
- instanceof 运算符⽤于判断对象的具体类型,⽐如判断⼀个变量是否是数组类型,⽤typeof是不行的,因为typeof返回的是 object,⽽instanceof可以,因为instanceof可以精准判断对象的具体类型
//⼿写实现
function myInstance(L, R) { //L代表instanceof左边,R代表右边
var RP = R.prototype
var LP = L.__proto__
while (true) {
if (LP == null) {
return false
}
if (LP == RP) {
return true
}
LP = LP.__proto__
}
}
console.log(myInstance({}, Object));
- constructor 属性 与 instanceof 相似,但是对于 instanceof 只能再检测引⽤类型, ⽽ constructor 还可以检测基本类型,因为 constructor是原型对象的属性指向构造函数。
- null 和 undefined是⽆效的对象,因此是不会有 constructor 存在的,所以⽆法根据 constructor 来判 断。
- JS对象的 constructor 是不稳定的,这个主要体现在⾃定义对象上,当开发者重写prototype 后,原有 的 constructor 会丢失,constructor 会默认为Object
- 类继承的也会出错,因为 Object 被覆盖了,检测结果就不对了
-
对象原型链判断:Object.prototype.toString.call(这个是判断类型最准的⽅法) toString 是Object 原型对象上的⼀个⽅法,该⽅法默认返回其调⽤者的具体类型,更严格的讲,是 toString运⾏ 时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型 ,其中包括:String, Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument…
基本上所有对象的类型都可以通过这个⽅法获取到。 必须通过 Object.prototype.toString.call 来获取,⽽不能直接 new Date().toString(), 从原型链的⻆度讲, 所有对象的原型链最终都指向了Object,按照JS变量查找规则,其他对象应该也可以直接访问到Object的toString ⽅法,⽽事实上,⼤部分的对象都实现了⾃身的 toString ⽅法,这样就可能会导致 Object 的toString 被终⽌查找,因此要⽤ call 来强制执⾏ Object 的 toString ⽅法。 缺点:不能再细分
2.undefined 和 undeclared 的区别
Undeclared(未声明) : 当尝试访问尚未使⽤ var、let 或 const 声明的变量时会发⽣这种情况。
Undefined(未定义) : 它发⽣在使⽤ var、let 或 const 声明变量但未赋值时。
在 JavaScript 中,两者很容易被混为⼀谈typeof 对 undefined 和 undeclared 的 都返回 “undefined”
3.数组
- 数组的创建方式:
var arr = new Array(1, 2);
var arr = [1, 2];
- 数组的常用方法:
Array.from() // 浅拷⻉
从类数组对象或者可迭代对象中创建⼀个新的数组实例。 Array.from还可以接受第⼆个参数,作⽤类似于数组的
map⽅法,⽤来对每个元素进⾏处理,将处理后的值放⼊返回的数组。
Array.of() // 创建数组
根据⼀组参数来创建新的数组实例,⽀持任意的参数数量和类型,没有参数时返回 [],当参数只有⼀个的时候,实
际上是指定数组的⻓度。
Array.prototype.concat() // 连接数组
将传⼊的数组或非数组值与原数组合并,返回⼀个新数组,不影响原数组。
copyWithin(target,start,end)
将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。
target(必需):从该位置开始替换数据。如果为负值,表示倒数。
start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
end(可选):到该位置前停⽌读取数据,默认等于数组⻓度。如果为负值,表示从末尾开始计算。
find() // ⽤于找出第⼀个符合条件的数组成员参数是⼀个回调函数,接受三个参数依次为当前的值、当前的位置和原数组
findIndex() // findIndex返回第⼀个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1.find和findIndex这两个⽅法都可以接受第⼆个参数,⽤来绑定回调函数的this对象
fill() // 还可以接受第⼆个和第三个参数,⽤于指定填充的起始位置和结束位置.注意,如果填充的类型为对象,则是浅拷⻉.
push() pop() shift() unshift()
splice(index,howmay,item1,.....,itemX)
/**
/* index : 必需。添加/删除项⽬位置,使⽤负数可从数组结尾处规定位置。
/* howmany :必需。要删除项⽬数量。如果设置为 0,则不会删除项⽬。
/* item1, ..., itemX: 可选。向数组添加新项⽬。
*/
concat() // concat⽅法⽤于连接两个或多个数组。该⽅法将返回⼀个新数组,不影响原数组。
slice() // 创建⼀个包含原有数组中⼀个或多个元素的新数组
reduce() ⽅法不会改变原始数组。
filter() // 将所有元素进⾏判断,将满⾜条件的元素作为⼀个新的数组返回
some() // 将所有元素进⾏判断返回⼀个布尔值,如果存在元素都满⾜判断条件,则返回 true,若所有元素都不满⾜判断条
件,则返回 false:
every() // 将所有元素进⾏判断返回⼀个布尔值,如果所有元素都满⾜判断条件,则返回 true,否则为 false:
join() // 将数组中的所有元素转换⼀个字符串。
flat() // 将数组展平,返回⼀个新数组,原数组不改变。
flatMap() // 将数组中的每个元素都执行⼀个提供的函数,该函数返回⼀个新数组。
indexof() // 返回数组中第一个符合条件的元素的索引,如果不存在,则返回-1。
includes() // 返回一个布尔值,表示数组中是否包含给定的元素。
forEach() // 遍历数组,将数组中的每个元素执行⼀个提供的函数。
map() // 将数组中的每个元素都执行⼀个提供的函数,返回由每次函数调⽤结果组成的新数组。
reverse() //将数组中的元素顺序反转。
sort() // 对数组中的元素进⾏排序。
toString() // 将数组中的元素转换⼀个字符串。
4.数组去重
1.indexOf,filter
const arr = [1,2,3,2,3,4]
const newArr = arr.filter((item,index) => {
if(arr.indexOf(item) === index) {
return true
} else {
return false
}
})
2.Set
const set = new Set(arr)
const newArr = [...set]
3.Map
const map = new Map()
arr.forEach(item => {
if(!map.has(item) {
map.set(item,true)
})
})
const newArr = [...map.keys()]
4.forEach,includes
const arr = [1,2,3,4,3,4,5]
const newArr = []
arr.forEach(item => {
if(!newArr.includes(item)) {
newArr.push(item)
}
})
5.reduce
const newArr = arr.reduce((pre,i) => {
if(pre.indexOf(i) === - 1) {
pre.push(i)
}
},[])
6.暴力算法
const arr = [1,3,2,3,2,3,2,3,]
const newArr = []
for(let i = 0 ; i < arr.length;i++) {
for(let j = 0;j < i;j++) {
}
}
5.数组拍平
1.flat flat()⽅法⽤于将数组展平,返回⼀个新数组,原数组不改变。需要传入一个参数,这个参数表示要展平的层数
const arr = [1,2,[3,4,[5,6]]]
const newArr = arr.flat(Infinity)
2.toString + replace + split
const arr = [1,2,[3,4,[5,6]]]
const newArr = arr.toString().replace(/(\[|\])/g,'').split(',')
3.toString + replace + JSON.parse
const arr = [1,2,[3,4,[5,6]]]
const newArr = JSON.parse('[' + arr.toString().replace(/(\[|\])/g,'') + ']')
4.递归
const arr = [1,2,[3,4,[5,6]]]
const newArr = []
const fn = (arr) => {
for(let i = 0;i < arr.length;i++) {
if(Array.isArray(arr[i])) {
fn(arr[i])
} else {
newArr.push(arr[i])
}
}
}
fn(arr)
5.扩张运算符
const arr = [1,2,[3,4,[5,6]]]
const newArr = [].concat(...arr)
6.ES6新增的数组方法
- find // 找到符合条件的第一个元素
- findIndex // 找到符合条件的第一个元素索引
- includes // 判断数组中是否包含某个元素
- flat // 数组拍平
- flatMap // 数组拍平,并且可以指定回调函数
- Array.at(index) // 返回指定索引的元素
- Array.from(arrayLike) // 将伪数组或可遍历对象转换为真数组
- Array.of(element0, element1, ...) // 创建一个新的数组实例,并填充元素
- Array.copyWithin(target, start = 0, end = this.length) // 从数组中拷贝元素到当前数组
- Array.fill(value, start = 0, end = this.length) // 用指定的值填充数组
- Array.entries() // 返回一个包含数组中每个索引的键值对的遍历器对象
- Array.keys() // 返回一个包含数组中每个索引的键的遍历器对象
- Array.values() // 返回一个包含数组中每个索引的值的遍历器对象
- Array.sort(compareFunction) // 对数组中的元素进行排序
7.arguments
1.arguments是⼀个类数组对象,它包含函数调⽤时传⼊的参数。 这个对象存在于使用function声明的函数作用域中,并且只存在于函数内部。 这是一个类数组对象,可以进行遍历啊,也可以使使用下标获取元素含有callee,length属性
2.转为数组
const arr = Array.from(arguments)
const arr = [...arguments]
Array.prototype.slice.call(argument)
// Array.prototype.slice这个方法可以在传入一个类数组对象,该函数会调用类属组上的length属性进行遍历截取,因此在后两个参数中不传值则会将整个类数组都复制一遍,生成一个数组返回
3.扩展运算符
const arr = [...arguments]
const arr = [...arguments.callee]
8.对象
1.遍历对象 可以使用hasOwnProperty 函数来判断对象一个属性是不是存在与对象那个之中 对象也可以使用[]语法访问某一个属性
for(let key in obj) {} // 使用for...in 运算可以遍历对象的可枚举属性,包括对象继承的属性
Object.keys(obj) // 这个方法可以返回对象中的所有可枚举(不包括继承属性)属性组成的一个数组
Object.getOwnPropertyNames(obj) // 这个方法可以返回对象中所有的属性,包括不可枚举的属性
Object.getOwnPropertySymbols(obj) // 这个方法可以返回对象中所有的Symbol属性组成的数组
Reflect.ownKeys(obj) // 这个方法可以返回对象中所有的属性,包括不可枚举的属性和Symbol属性
Object.entries(obj) // 这个方法可以返回对象中所有可枚举的属性组成的数组
Object.values(obj) // 这个方法可以返回对象中所有可枚举的属性值组成的数组
Object.fromEntries(obj) // 这个方法可以将一个键值对组成的数组转换为对象
9.for...in 和 for...of
1.for...in // 遍历对象的可枚举属性,包括对象继承的属性(专门为遍历对象而构建)
2.for...of // 遍历数组,字符串,Map,Set,arguments等可迭代对象
10.原型与原型链
1.原型 // 每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。当这个函数作为构造函数创建实例时,该实例的内部[[Prototype]]指针被赋值为构造函数的prototype属性。这样构造函数的原型对象就和实例产生联系,实力就可以调用构造函数原型对象上的属性与方法。例如Array数组实例的绝大多数api都是来自Array.prototype原型对象prototype有⼀个默认的constructor属性,⽤于记录实例由哪个构造函数创建.
constructor: 每⼀个原型都有⼀个constructor属性指向关联的构造函数.
2.原型链 // 每个实例对象都有一个内部属性[[Prototype]],指向构造函数的原型对象。这个原型对象也有一个自己的原型对象[[Prototype]],层层向上直到Object.特殊的 Function 对象,
- Function 的 proto 指向的是⾃身的 prototype
- ⼀切对象都是继承⾃Object对象,Object 对象直接继承根源对象null
- ⼀切的函数对象(包括 Object 对象),都是继承⾃ Function 对象
- Object 对象直接继承⾃ Function 对象
- Function对象的proto会指向⾃⼰的原型对象,最终还是继承⾃Object对象