# 前端 75 题
# 52. 展开(spread )运算符和 剩余(Rest) 运算符有什么区别
剩余元素和展开元素相反,展开元素会“展开”数组变成多个元素,剩余元素会收集多个元素和“压缩”成一个单一的元素
function add(...rest) {
return rest.reduce((total, current) => total + current);
}
console.log(add(1, 2)); // 3console.log(add(1, 2, 3, 4, 5)); // 15
2
3
4
在本例中,我们有一个 add 函数,它接受任意数量的参数,并将它们全部相加,然后返回总数。
const [first, ...others] = [1, 2, 3, 4, 5];
console.log(first); // 1console.log(others); // [2,3,4,5]
2
这里,我们使用剩余操作符提取所有剩余的数组值,并将它们放入除第一项之外的其他数组中。
# 54. 什么是包装对象(wrapper object)
引用类型有方法和属性,但是基本类型是没有的
let name = "marko";
console.log(typeof name); // "string"console.log(name.toUpperCase()); // "MARKO"
2
name 类型是 string,属于基本类型,所以它没有属性和方法,但是在这个例子中,我们调用了一个 toUpperCase()方法,它不会抛出错误,还返回了对象的变量值。
原因是基本类型的值被临时转换或强制转换为对象,因此 name 变量的行为类似于对象。除 null 和 undefined 之外的每个基本类型都有自己包装对象。也就是:String,Number,Boolean,Symbol 和 BigInt。在这种情况下,name.toUpperCase()在幕后看起来如下:
console.log(new String(name).toUpperCase()); // "MARKO"
在完成访问属性或调用方法之后,新创建的对象将立即被丢弃。
# 56. 什么是 NaN?以及如何检查值是否为 NaN
WARNING
NaN是唯一的值,它不等于自己。
function checkIfNaN(value) {
return value !== value;
}
2
3
# 59. 如何检查对象中是否存在某个属性
# 第一种使用 in 操作符号
const o = { prop: "bwahahah", prop2: "hweasa" };
console.log("prop" in o); // trueconsole.log("prop1" in o); // false
2
# 第二种使用 hasOwnProperty 方法
hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
console.log(o.hasOwnProperty("prop2")); // trueconsole.log(o.hasOwnProperty("prop1")); // false
# 第三种使用括号符号 obj["prop"]
如果属性存在,它将返回该属性的值,否则将返回 undefined。
console.log(o["prop"]); // "bwahahah"console.log(o["prop1"]); // undefined
# 63. in 运算符和 Object.hasOwnProperty 方法有什么区别
# hasOwnPropert 方法
hasOwnPropert()方法返回值是一个布尔值,指示对象自身属性中是否具有指定的属性,因此这个方法会忽略掉那些从原型链上继承到的属性。
Object.prototype.phone= '15345025546';let obj = { name: '前端小智', age: '28'}console.log(obj.hasOwnProperty('phone')) // falseconsole.log(obj.hasOwnProperty('name')) // true
可以看到,如果在函数原型上定义一个变量 phone,hasOwnProperty 方法会直接忽略掉。
# in 运算符
如果指定的属性在指定的对象或其原型链中,则 in 运算符返回 true。
console.log("phone" in obj); // true
可以看到 in 运算符会检查它或者其原型链是否包含具有指定名称的属性。
# 62. Object.seal 和 Object.freeze 方法之间有什么区别
# Object.freeze()
Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。
# Object.seal()
Object.seal()方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要可写就可以改变。
# 方法的相同点
- ES5 新增。
- 对象不可能扩展,也就是不能再添加新的属性或者方法。
- 对象已有属性不允许被删除。
- 对象属性特性不可以重新配置。
# 方法不同点
- Object.seal 方法生成的密封对象,如果属性是可写的,那么可以修改属性值。
- Object.freeze 方法生成的冻结对象,属性都是不可写的,也就是属性值无法更改。
# 66. 调用函数,可以使用哪些方法
在 JS 中有 4 种方法可以调用函数。
# 作为函数调用
如果一个函数没有作为方法、构造函数、apply、call 调用时,此时 this 指向的是 window 对象(非严格模式)
//Global
Scopefunction add(a,b){
console.log(this);
return a + b;
}
add(1,5); // 打印 "window" 对象和 6
const o = {
method(callback){
callback();
}}
o.method(function (){
console.log(this); // 打印 "window" 对象
});
2
3
4
5
6
7
8
9
10
11
12
13
# 作为方法调用
如果一个对象的属性有一个函数的值,我们就称它为方法。调用该方法时,该方法的 this 值指向该对象。
const details = { name : "Marko", getName(){ return this.name; }}details.getName(); // Marko
# 作为构造函数的调用
如果在函数之前使用 new 关键字调用了函数,则该函数称为构造函数。构造函数里面会默认创建一个空对象,并将 this 指向该对象。
function Employee(name, position, yearHired) {
// 创建一个空对象 {}
// 然后将空对象分配给“this”关键字 //
this = {};
this.name = name;
this.position = position;
this.yearHired = yearHired; // 如果没有指定 return ,这里会默认返回 this
}
const emp = new Employee("Marko Polo", "Software Developer", 2017);
2
3
4
5
6
7
8
9
# 使用 apply 和 call 方法调用
如果我们想显式地指定一个函数的 this 值,我们可以使用这些方法,这些方法对所有函数都可用。
const obj1 = { result: 0 };
const obj2 = { result: 0 };
function reduceAdd() {
let result = 0;
for (let i = 0, len = arguments.length; i < len; i++) {
result += arguments[i];
}
this.result = result;
}
reduceAdd.apply(obj1, [1, 2, 3, 4, 5]); // reduceAdd 函数中的 this 对象将是 obj1
reduceAdd.call(obj2, 1, 2, 3, 4, 5); // reduceAdd 函数中的 this 对象将是 obj2
2
3
4
5
6
7
8
9
10
11
# 71. 什么时候不使用箭头函数? 说出三个或更多的例子
- 当想要函数被提升时(箭头函数是匿名的)
- 要在函数中使用this/arguments时,由于箭头函数本身不具有this/arguments,因此它们取决于外部上下文
- 使用命名函数(箭头函数是匿名的)
- 使用函数作为构造函数时(箭头函数没有构造函数)
- 当想在对象字面是以将函数作为属性添加并在其中使用对象时,因为咱们无法访问 this 即对象本身。