进阶面试题
大鹏一日同风起,扶摇直上九万里
经典题目与比较偏的知知识点
1
var a=? 要成立下面为true
console.log(a == 1 && a == 2 && a ==3);
答案
需要用==的知识,还有类型转换,由于需要满足三种情况,其实只有a的值为三个值才会成立,自然想到对象这一个类型,因为可以存储不同类型,不同的值。然后想到对象的类型转换,下面第三点,对象的valueOf()
和toString()
方法,,通过第一种方法,返回符合的值
var a = {
n: 1,
//改写内置的valueOf方法
valueOf: function() {
return this.n++;
}
}
所涉及的知识
相等运算符(==
和!=
)使用抽象相等比较算法比较两个操作数。可以大致概括如下:
- 如果两个操作数都是对象,则仅当两个操作数都引用同一个对象时才返回
true
。 - 如果一个操作数是
null
,另一个操作数是undefined
,则返回true
。 - 如果两个操作数是不同类型的,就会尝试在比较之前将它们转换为相同类型:
- 当数字与字符串进行比较时,会尝试将字符串转换为数字值。
- 如果操作数之一是Boolean,则将布尔操作数转换为 1 或 0。
- 如果是
true
,则转换为1
。 - 如果是
false
,则转换为0
。
- 如果是
- 如果操作数之一是对象,另一个是数字或字符串,会尝试使用对象的
valueOf()
和toString()
方法将对象转换为原始值。
- 如果操作数具有相同的类型,则将它们进行如下比较:
String
:true
仅当两个操作数具有相同顺序的相同字符时才返回。Number
:true
仅当两个操作数具有相同的值时才返回。+0
并被-0
视为相同的值。如果任一操作数为NaN
,则返回false
。Boolean
:true
仅当操作数为两个true
或两个false
时才返回true
。
此运算符与严格等于(===
)运算符之间最显着的区别在于,严格等于运算符不尝试类型转换。相反,严格相等运算符始终将不同类型的操作数视为不同。
不同类型对象的 valueOf() 方法的返回值:
Array:返回数组对象本身。
Boolean: 返回布尔值
Date:存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。
Function: 返回函数本身。
Number: 返回数字值。
Object:返回对象本身。这是默认情况。
String:返回字符串值。
Math 和 Error 对象没有 valueOf 方法。
2
一般不直接用undefined来定义值,var a= undefined (不直接这样使用);而是 var a= void 0
因为undefined可以用作为变量名,它是window的一个属性,所以为了避免混乱,就不直接定义为undefined
function a() {
var undefined = 1;
console.log(undefined);
}
a();//结果为1
3
不用数组内置函数,不用循环,实现数组求和
可以使用递归来实现
const a = [4, 5, 6, 7, 8];
let b = a[0];
function test(n) {
if (n === 1) {
return b;
} else {
return test(n - 1) + a[n - 1];
}
}
console.log(test(5));//30
4 (零宽字符、隐藏字符)
先来看一个奇怪的现象:为什么字符 abc 的长度是23?
是因为这个字符串存在零宽字符。
零宽度字符是隐藏不显示的,也是不可打印的,也就是说这种字符用大多数程序或编辑器是看不到的
零宽度字符是一种字节宽度为0的不可打印的Unicode字符, 在浏览器和一般的文本编辑器中是不可见, 但是真是存在, 获取字符串长度时也会占位置, 表示某一种控制功能的字符。
字符种类
零宽度空格符 (zero-width space) U+200B : 用于较长单词的换行分隔
零宽度非断空格符 (zero width no-break space) U+FEFF : 用于阻止特定位置的换行分隔
零宽度连字符 (zero-width joiner) U+200D : 用于阿拉伯文与印度语系等文字中,使不会发生连字的字符间产生连字效果
零宽度断字符 (zero-width non-joiner) U+200C : 用于阿拉伯文,德文,印度语系等文字中,阻止会发生连字的字符间的连字效果
左至右符 (left-to-right mark) U+200E : 用于在混合文字方向的多种语言文本中(例:混合左至右书写的英语与右至左书写的希伯来语),规定排版文字书写方向为左至右
右至左符 (right-to-left mark) U+200F : 用于在混合文字方向的多种语言文本中,规定排版文字书写方向为右至左
零宽字符有什么用处
- 数据防爬
将零宽度字符插入关键词文本中,使得匹配关键字时不能正确匹配,但是不影响用户的正常阅读 - 信息隐藏(可做水印)
5 函数二义性
function a() {};
a();
new a();
//两种调用方式,但是两种调用方式的意义不一样
//一种是当作普通函数来用,一种是当作构造函数来用
//为了区分这两种意思,什么时候用new,什么时候直接用
//es6就提出,当为构造函数的时候:
class a {
}
//这种时候如果用a(),将会报错
//而当为普通函数时,通过new.target来判断
function a() {
if (new.target) {
//有值代表为构造函数,但因为我们想不是class就全为普通函数
//所以new.target有值则报错,代表普通函数不能以new方式调用
throw new Error('不能以new方式调用');
}
};
6 函数签名
函数签名(或类型签名,或方法签名):定义函数命名、参数列表、返回值。
一个函数需要经过两步:
- 设计,即函数签名
- 实现,将你所需要实现的功能写进去
7 过渡结束事件多次触发
//dom是什么不用管,就把它当作一个元素,重点是看监听事件
function b() {
dom.style.transfrom = 'translateX(100px)';
dom.style.opacity = 0.5;
//每次都会打印两次11,这是因为监听触发了两次
//监听事件是监听过渡结束事件,之所以会触发两次
//是因为更改了两个属性,每一个属性过渡结束都会触发监听事件
dom.addEventListener('transitioned', () => {
console.log(11);
})
//解决方法:
// dom.addEventListener('transitioned', () => {
// console.log(11);
// },{
// once:true,代表调用函数只会触发一次监听事件
// })
}
8 失活页面的计时器问题
//这一个定时器的时间间隔10毫秒不一定准确
//当你在切换其它页面浏览的时候,浏览器为了保持电量,提高效率
//会将这一个时间间隔调至更多1s,或者更多,所以导致一系列的定时器问题
setInterval(() => {}, 10);
//解决方法:
//用一个监听事件监听你切换网页,然后将定时器暂停
//visibilitychange:页面可见度改变
document.addEventListener('visibilitychange', function() {
//visibilityState:页面可见度状态
if (document.visibilityState === "hidden") {
//暂停定时器,或者其它操作
}
})