1
判断是否为
NaN
利用其为唯一不等于自身的值这个特点
function wqd(value) {
return value !== value;
}
2
3
null
和undefined
只有在非严格相等下成立
只有null
和undefined
两者之间互相等于除此之外不等于任何值
null == undefined // true
4
或逻辑运算符
alert(alert(1) || 2 || alert(3));
先显示1后显示2
因为对alert
的调用没有返回值或者说返回undefined
5
6
空值合并运算符和或逻辑运算符的区别
前者返回第一个已定义的值后者返回第一个为真的值
另外需要注意的是空值合并运算符禁止与或逻辑运算符或与逻辑运算符一起使用
除非使用括号明确指定了优先级
7
break
和continue
标签
wqd:
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
break wqd;
}
console.log(i, j); // 0 0, 0 1, 0 2, 1 0
}
}
8
函数声明和函数表达式的区别
区别在于引擎会在什么时候创建函数
函数表达式在代码执行到达时创建并且仅从那一刻起可以调用
函数声明在被定义之前就可以调用
9
判断对象中是否有某个属性
使用in
操作符
let obj = {
name: undefined,
};
console.log("name" in obj); // true
10
对象遍历输出顺序
整数属性会被排序而其余属性按照创建的顺序
整数属性指的是一个可以在不做任何更改的情况下与一个整数进行相互转换的字符串
String(Math.trunc(+"20")) // "20" 相同所以是整数属性
String(Math.trunc(+"+20")) // "20" 不同所以不是整数属性
11
对象的克隆和合并
第一个参数是目标对象
从第二个开始的参数是源对象
该方法将从第二个开始的参数的所有属性拷贝到第一个参数并返回目标对象
该方法对于目标对象已经存在的属性会进行覆盖
let obj = {
name: "wqd",
};
let a = {
name: "wang",
};
let b = {
age: 25,
};
Object.assign(obj, a, b);
console.log(obj); // {name: "wang", age: 25}
对象的简单克隆
let obj = {
name: "wqd",
};
let a = Object.assign({}, obj);
console.log(a); // {name: "wqd"}
12
构造函数
function User() {
// 隐式创建
// let this = {};
this.name = "wqd";
this.age = 25;
// 隐式返回
// return this;
}
let user = new User();
console.log(user); // {name: "wqd", age: 25}
如果
return
返回的是一个对象则构造函数返回该对象否则返回this
function User() {
this.name = "wqd";
return {
name: "wang",
};
}
console.log(new User().name); // "wang"
13
可选链
如果可选链前面的部分是null
或者undefined
则会停止运算并返回该部分而不报错
let user = {};
console.log(user?.address?.street); // undefined
14
对象的属性键只能是字符串类型或者
Symbol
类型
Symbol
允许我们创建对象的隐藏属性并且会在循环中跳过
但是对象的克隆和合并会同时复制字符串和Symbol
属性
let id = Symbol("id"); // 即使描述一样也是不同的Symbol
let user = {
name: "wqd",
[id]: 25, // Symbol作为属性键需要用方括号包起来
};
for (let i in user) {
console.log(i); // "name"
}
console.log(user[id]); // 25
console.log(Object.keys(user)); // ["name"] 同样会忽略Symbol
15
let id1 = Symbol.for("id"); // 从全局注册表中读取不存在则创建
let id2 = Symbol.for("id");
console.log(id1 === id2); // true
console.log(Symbol.keyFor(id1)); // "id" 反向调用通过Symbol返回名字
16
对象到原始值的转换
分为string number default
三种hint
let user = {
name: "wqd",
age: 25,
[Symbol.toPrimitive](hint) {
console.log(hint);
switch(hint) {
case "string":
return this.name;
case "number":
return this.age;
case "default":
return this.age;
}
},
};
console.log(String(user)); // "string" "wqd"
console.log(+user); // "number" 25
console.log(user + 25); // "default" 50
17
Object.is(NaN, NaN) // true
Object.is(+0, -0) // false
18
创建数组的副本
let arr = [1, 2, 3];
let copy = arr.slice();
arr.pop();
console.log(arr); // [1, 2]
console.log(copy); // [1, 2, 3]
19
数组方法之
reduce
和reduceRight
应用函数时上一个函数调用的结果将作为第一个参数传递给下一个函数
let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((previous, current) => previous + current, 0);
console.log(result); // 15
20
判断是否是数组
typeof [] // "object" 这是错误的因为数组没有单独的类型
Array.isArray([]) // true 使用特定语法去判断
21
可迭代对象
可以应用for of
循环的对象称为可迭代的
let range = {
from: 1,
to: 5,
};
range[Symbol.iterator] = function() {
return {
min: this.from,
max: this.to,
next() {
if (this.min > this.max) {
return {
done: true,
};
} else {
return {
done: false,
value: this.min++,
};
}
},
};
}
for (let i of range) {
console.log(i); // 1 2 3 4 5
}
22
let wqd = {
0: "a",
1: "b",
length: 2,
};
let a = Array.from(wqd, item => item + item);
console.log(a); // ["aa", "bb"]
23
映射
和对象最大的区别是Map
允许任何类型的键
let map = new Map(); // 创建
map.set("123", "string"); // 根据键存储值
map.set(123, "number");
console.log(map.get(123)); // "number"
console.log(map.get(456)); // undefined
console.log(map.has("123")); // true
console.log(map.has(456)); // false
Map
迭代
迭代的顺序与插入值的顺序相同
map.keys() // 遍历所有的键
map.values() // 遍历所有的值
map.entries() // 遍历所有的实体
从对象创建
Map
let obj = {
name: "wqd",
age: 25,
};
let map = new Map(Object.entries(obj));
console.log(map.get("age")); // 25
从
Map
创建对象
let obj = Object.fromEntries([
["a", 1],
["b", 2],
["c", 3],
]);
console.log(obj.a); // 1
24
集合
其中的每个值只能出现一次
let set = new Set();
let a = {
name: "a",
};
let b = {
name: "b",
};
let c = {
name: "c",
};
set.add(a);
set.add(b);
set.add(c);
set.add(a);
set.add(b);
set.add(c);
console.log(set.size); // 3 set只保留不重复的值
25
弱映射
WeakMap
和Map
的第一个不同点是WeakMap
的键必须是对象
WeakMap
和Map
的第二个不同点是如果我们在WeakMap
中使用一个对象作为键并且没有对这个对象的引用那么这个对象会被从内存中自动清除
26
弱集合
WeakMap
和WeakSet
最明显的局限性就是不能迭代并且无法获取当前所有内容
27
转换对象
let obj = {
a: 1,
b: 2,
c: 3,
};
let double = Object.fromEntries(Object.entries(obj).map(
([key, value]) => [key, value * 2]
));
console.log(double); // {a: 2, b: 4, c: 6}
28
解构赋值
let arr = ["aa", "bb", "cc"];
let [a, b, c] = arr; // 数组解构
console.log(a, b, c); // 1 2 3
交换变量值的技巧
let a = 123;
let b = 456;
[a, b] = [b, a];
console.log(a, b); // 456 123
剩余的
let [a, b, ...rest] = [1, 2, 3, 4];
console.log(rest); // [3, 4]
29
Rest
参数
function wqd(a, b, ...rest) {
console.log(a + b); // 3
console.log(rest); // [3, 4, 5]
}
wqd(1, 2, 3, 4, 5);
30
Spread
语法
任何可迭代对象都可以使用
let a = [1, 2];
let b = [5, 6];
let c = [...a, 3, 4, ...b];
console.log(c); // [1, 2, 3, 4, 5, 6]
31
使用
Spread
语法获取数组和对象的副本
let arr = [1, 2, 3];
let a = [...arr];
console.log(JSON.stringify(arr) === JSON.stringify(a)); // true
console.log(arr === a); // false
let obj = {
a: 1,
b: 2,
c: 3,
};
let b = {...obj};
console.log(JSON.stringify(obj) === JSON.stringify(b)); // true
console.log(obj === b); // false
32
33
function a() {
a = false;
if (false) {
var a;
}
console.log(a); // false
}
a();
function b() {
console.log(b); // undefined
var b = false;
}
b();
34
嵌套的
setTimeout
能精确地设置两次执行之间的延时而setInterval
不能
因为嵌套的setTimeout
的下一次调用是在前一次调用完成时再进行的
let a = setTimeout(function f() {
// todo
a = setTimeout(f, 1000);
}, 1000);
35
call
允许调用一个显式设置this
的函数
function f() {
console.log(this.name);
}
let a = {
name: "a",
};
let b = {
name: "b",
};
f.call(a); // "a"
f.call(b); // "b"
36
37
function debounce(f, ms) {
let timeout;
return function() {
clearTimeout(timeout);
timeout = setTimeout(() => f.apply(this, arguments), ms);
};
}
节流装饰器
throttle
运行函数的频率不会大于所给定的时间适用于不应该经常进行的定期更新
38
call
apply
bind
的区别
call
和apply
本质相同但call
是一个一个传参而apply
是数组传参
call
和bind
完全相同但是bind
不会立即调用函数而是返回一个新函数
39
属性标志和属性描述符
value
writable
为false时只读
enumerable
为false时不可枚举
configurable
为false时不可配置
40
原生的原型
let obj = {};
console.log(obj.__proto__ === Object.prototype); // true
41
继承静态属性和方法
class A {}
class B extends A {}
// 对于静态的
console.log(B.__proto__ === A); // true
// 对于常规的
console.log(B.prototype.__proto__ === A.prototype); // true
有无
extends
的区别
class A {}
console.log(A.__proto__ === Function.prototype); // true
class A extends Object {}
console.log(A.__proto__ === Object); // true
42
受保护的属性和方法
class A {
_count = 0; // 受保护的属性
setCount(value) {
if (value < 0) {
return;
}
this._count = value;
}
getCount() {
return this._count;
}
// 只设置get函数不设置set函数实现只读
getName() {
return this._name;
}
constructor(name) {
this._name = name;
}
}
43
类型检查方法
Object.prototype.toString.call(123) // "[object Number]"
44
Promise
的5种静态方法
Promise.all
Promise.allSettled
Promise.race
45
generator
function* wqd() {
let a = yield "2 + 2";
console.log(a); // 4
let b = yield "3 * 3";
}
let generator = wqd();
console.log(generator.next().value); // "2 + 2"
console.log(generator.next(4).value); // "3 * 3"
46
for in
和for of
的区别
通过for in
循环我们可以遍历一个对象自有的继承的可枚举的非Symbol的属性
通过for of
我们可以迭代可迭代对象
47
构造函数相关
function Parent() {}
Parent.prototype.name = "a";
function Child() {}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
let childOne = new Child();
console.log(childOne.name); // "a"
Child.prototype.name = "b";
let childTwo = new Child();
console.log(childTwo.name); // "b"
48
交换两个变量的值
let a = 0, b = 1;
let c = a;
a = b;
b = c;
console.log(a, b); // 1 0
let a = 0, b = 1;
a = a + b;
b = a - b;
a = a - b;
console.log(a, b); // 1 0
let a = 0, b = 1;
a = [a, b];
b = a[0];
a = a[1];
console.log(a, b); // 1 0
let a = 0, b = 1;
a = {a: b, b: a};
b = a.b;
a = a.a;
console.log(a, b); // 1 0
let a = 0, b = 1;
a = [b, b = a][0];
console.log(a, b); // 1 0
let a = 0, b = 1;
a = a ^ b;
b = a ^ b;
a = a ^ b
console.log(a, b); // 1 0
let a = 0, b = 1;
[a, b] = [b, a];
console.log(a, b); // 1 0
49
获得当前滚动的值
window.pageYOffset
window.pageXOffset // 都是只读的
50
页面滚动的方法
window.scrollTo(x, y)
将页面滚动至绝对坐标
window.scrollBy(x, y)
相对当前位置移动坐标
element.scrollIntoView(boolean)
将element移动到窗口顶部或底部
51
清除浮动的方法
使用clear 创建一个空的块级元素放到末尾并设置clear
使用BFC 给父元素添加overflow或float
使用伪元素 原理同clear方法