数组去重
method
const objArray = [
{
age: "20",
name: "whl",
},
{
age: "20",
name: "qwe",
},
{
age: "30",
name: "qwe",
},
];
const target = [];
objArray.forEach((item) => {
if (!target.some((items) => items.age === item.age)) {
return target.push(item);
}
});
console.log(target);
let target = {};
data.forEach((item) => {
let k = item[key];
if (!target[k]) target[k] = item;
});
return Object.values(target);
};
console.log(Filter(objArray, "age"));
const arr = [1, 2, 3, 4, 4];
console.log(Array.from(new Set(arr)));
console.log([...new Set(arr)]);
const res = arr.filter((item, index) => {
return arr.indexOf(item) === index;
});
let target = [];
arr.forEach((item) => {
if (target.indexOf(item) === -1) {
target.push(item);
}
});
console.log(target);
console.log(res);
数组扁平化
const arr = [1, [2, [3, [4, 5]]], 6];
function flatten(arr) {
return arr.reduce((result, item) => {
return result.concat(Array.isArray(item) ? flatten(item) : item);
}, []);
}
console.log(flatten(arr));
console.log(arr.flat(Infinity))
new操作符原理
- 创建新对象
- 将构造函数的作用域赋给新对象
- 执行构造函数
- 返回新对象
function _new() {
let obj = {};
let Con = [].shift.call(arguments);
obj.__proto__ === Con.prototype;
const result = Con.apply(obj, arguments);
return typeof result === "object" ? result : obj;
}
function Person(name, age) {
this.name = name;
this.age = age;
}
const person = _new(Person, "whl", 21);
console.log(person);
instanceof
原理:原型链的向上查找 A instanceof B B的prototype属性指向的原型对象是否在A对象的原型链上
function InstanceOf(L, R) {
if (typeof L !== "object" || L === null) return false;
let p = Object.getPrototypeOf(L);
while (true) {
if (p === null) return false;
if (p === R.prototype) return true;
p = Object.getPrototypeOf(p);
}
}
console.log(InstanceOf("111", String));
console.log(InstanceOf(new String("111"), String));
JS数据类型
八种数据类型 number string boolean null undefined symbol bigint
- symbol: 独一无二的数据类型,解决全局变量冲突的问题
- bigint 数字类型的数据,存储、操作大整数
数据类型检测方式 typeof(除了null 对象 数组会被判断成object,其他都正确)
typeof {} === 'object'typeof [] === 'object'typeof null === 'object'
A instanceof B
- A一定是对象否则直接false
使用Object.prototype.toStirng.call()来判断数据类型 返回值格式[object Object] [object Array] 如列举几种判断数组的方法
console.log(Object.prototype.toString.call([]) === "[object Array]");
console.log([] instanceof Array);
console.log([].__proto__ === Array.prototype);
console.log(Array.isArray([]));
判断空对象
let obj = {};
function obj1(o) {
if (Object.keys(o).length === 0) {
console.log("我是空对象");
}
}
obj1(obj);
object.assign和扩展运算符是深拷贝还是浅拷贝
object.assign: 浅拷贝
let obj1 = {
p: { a: 1, b: 2 },
};
let newObj = Object.assign({}, obj1);
newObj.p.a = 2;
console.log(obj1);
...: 将数组或对象的所有值拷贝成新的对象或数组
let obj1 = {
p: { a: 1, b: 2 },
};
let newObj = { ...obj1 };
newObj.p.a = 2;
console.log(obj1);
let、const、var的区别
1.let和const有块级作用域用{}包裹,主要是为了解决内层变量可能覆盖外层变量 2.变量提升,var存在变量提升,let和const不存在,只能在声明后才能调用 3.var声明的变量会被添加到全局对象的属性上,let和const不会 4.var可以重复声明,let和const不能 5.const和let存在暂时性死区,不能再声明前调用 6.const必须有初始值,let和var不用
const对象的属性可以修改吗
const声明的常量如number string boolean不可修改 const声明的对象类型内存地址不变,可以修改
箭头函数和普通函数的区别
- 箭头函数中的this指向父级作用域中的this
- call apply bind无法改变箭头函数中的this指向
- 不能作为构造函数使用,因为没有自己的this
- 没有自己的arguments,再箭头函数中访问arguments是访问外层函数的arguments
- 没有protoype
for...in 和 for...of
for...in: 遍历出来的是key 用于对象
const a = {
a: 1,
b: 2,
c: 3
}
for(let k in a) {
console.log(k)
}
// 输出 a、b、c
for...of: 遍历出来的是value 用于数组
const arr = [1,2,3,4]
for(let k of arr) {
console.log(k)
}
输出1、2、3、4
原型和原型链
- prototype是函数的原型对象
__proto__引用了哪个prototype,就看是哪个构造函数创造了你,那你的__proto__就是那个构造函数的prototype- 原型链的终点是Object.prototype.proto === null
call、apply、bind
都能改变this指向 call传递的是参数列表,apply传递的是数组 call、apply更改this指向后直接调用,bind会返回对应的函数
事件委托 事件冒泡 事件捕获
事件委托:把内层元素事件绑定到外层元素上将绑定多个事件的操作变为只绑定一个,通过事件对象。target拿到当前点击的进行相应的操作 都是先捕获后冒泡 捕获:从上到下 冒泡从下到上