这是我学习前端过程中遇到的一系列问题,我经过查资料、看MDN、看掘金、博客等总结的,发表到掘金上共享一下,希望大家共同进步。
文章中如果有不对的地方欢迎评论指出。以后遇到新的问题,会继续更新^-^
0、隐式类型转换面试大坑
1.1-隐式转换介绍
在js中,当运算符在运算时,如果两边数据不统一,CPU就无法计算,这时我们编译器会自动将运算符两边的数据做一个数据类型转换,转成一样的数据类型再计算
这种无需程序员手动转换,而由编译器自动转换的方式就称为隐式转换
例如1 > “0”这行代码在js中并不会报错,编译器在运算符时会先把右边的“0”转成数字0`然后在比较大小
1.2-隐式转换规则
- 转成string类型: +(字符串连接符)
- 转成number类型:
- 自增自减运算符:++/-–
- 算术运算符:+ - * / %
- 关系运算符: > < >= <= == != == = !===
- 转成boolean类型:!(逻辑非运算符)
1.3-坑一:字符串连接符与算术运算符隐式转换规则混淆
• 常见面试题如下
console.log ( 1 + "true" );// ‘1true'
console.log ( 1 + true );//2
console.log ( 1 + undefined );// NaN
console.log ( 1 + null );//1
1.4-坑二:关系运算符:会把其他数据类型转换成number之后再比较关系 常见面试题如下
console.log ( "2" > 10 );//false
console.log ( "2" > "10" );//true
console.log ( "abc" > "b" );//false
console.log ( "abc" > "aad" );//true
console.log ( NaN == NaN );//false
console.log ( undefined == null );//true
• 原理分析
当关系运算符两边有一边是字符串的时候,会将其他数据类型使用Number()转换,然后比较关系
console.log ( "2" > 10 );//false Number('2') > 10 = 2 > 10 = false
/*2.2: 当关系运算符两边都是字符串的时候,此时同时转成number然后比较关系
重点:此时并不是按照Number()的形式转成数字,而是按照字符串对应的unicode编码来转成数字
使用这个方法可以查看字符的unicode编码: 字符串.charCodeAt(字符下标,默认为0)
1.5-坑三:复杂数据类型在隐式转换时会先转成String,然后再转成Number运算
console.log ( [ 1,2] == '1,2' );//true
// 先将左边数组转成string,然后右边也是string则转成unicode编码运算
console.log ( [ 1, 2 ].valueOf () );// [1,2]
console.log ( [ 1, 2 ].toString () );// '1,2'
var a = {};
console.log ( a == "[object Object]" );//true
console.log ( a.valueOf ().toString() );//[object Object]
/*分析:逻辑与运算一假则假,要想if分支语句小括号条件成立,则必须要让a的值同时等于1 且 等于 2 且等于3
乍看之下,好像根本不可能实现,但是复杂数据类型会先调用valueOf()方法,然后转成number运算
而对象的valueOf()方法是可以重写的
*/
var a = {
i : 0,//声明一个属性i
valueOf:function ( ) {
return ++a.i;//每调用一次,让对象a的i属性自增一次并且返回
}
}
if (a == 1 && a == 2 && a == 3){//每一次运算时都会调用一次a的valueOf()方法
console.log ( "1" );
}
1.6-坑四:逻辑非隐式转换与关系运算符隐式转换搞混淆
前方高能,请注意~
空数组的toString()方法会得到空字符串,而空对象的toString()方法会得到字符串[object Object] (注意第一个小写o,第二个大写O哟)
//大坑
console.log ( [] == 0 );//true
console.log ( ! [] == 0 );//true
//神坑
console.log ( [] == ! [] );//true
console.log ( [] == [] );//false
//史诗级坑
console.log({} == !{});//false
console.log({} == {});//false
• 原理分析
/*1.关系运算符:将其他数据类型转成数字
2.逻辑非:将其他数据类型使用Boolean()转成布尔类型
* 以下八种情况转换为布尔类型会得到false
* 0 、-0、NaN、undefined、null、''(空字符串)、false、document.all()
* 除以上八种情况之外所有数据都会得到true
*/
/*原理
(1)[].valueOf().toString() 得到空字符串
(2)Number('') == 0 成立
*/
console.log ( [] == 0 );//true
/* 原理 :本质是 `![]` 逻辑非表达式结果 与 0 比较关系
(1)逻辑非优先级高于关系运算符 ![] = false (空数组转布尔得到true,然后取反得到false)
(2)false == 0 成立
*/
console.log ( ! [] == 0 );//true
/*原理 :本质其实是 `空对象{}` 与 `!{}` 这个逻辑非表达式结果做比较
(1) {}.valueOf().toString() 得到字符串 '[object Object]'
(2) !{} = false
(3) Number('[object Object]') == Number(false)
*/
console.log({} == !{});//false
//引用类型数据存在堆中,栈中存储的是地址,所以他们的结果是false
console.log({} == {});//false
/*原理:本质是 `空数组[]` 与 `![]` 这个逻辑非表达式结果做比较
(1) [].valueOf().toString() 得到空字符串 ''
(2) ![] = false
(3) Number('') == Number(false) 成立 都是0
*/
console.log ( [] == ! [] );//true
//引用类型数据存在堆中,栈中存储的是地址,所以他们的结果是false
console.log ( [] == [] );//false
console.log ( {}.valueOf ().toString () )//[object Object]
console.log ( [].valueOf ().toString () );//'' 空字符串
1、执行上下文
function a(age) {
console.log(age);
var age = 20
console.log(age);
function age() {
}
console.log(age);
}
a(18);
解析:
function a(age) { //形参赋值,age->18
console.log(age);
var age = 20 //由于age已经存在局部执行上下文,故,不做处理(有同名属性,不做任何事)
console.log(age);
function age() {//函数提升,地址值给age
}
console.log(age);
}
a(18);
注意函数声明提升,function age(){}赋值给age,最后执行第一个log的时候,age中存放的是age()的地址
function age()
20
20
2、函数表达式执行上下文
function a(age) {
console.log(age);
var age = function () {
console.log('25');
}
}
a(18);
解析:18
由于是函数表达式,而不是函数声明,并且局部执行上下文中,在形参赋值的时候已经有age了,所以,声明提升时期,对函数表达式不作处理。故输出为18
3、全局执行上下文与局部执行上下文深入理解
console.log(a,b);
var a=1;
var b = 1;
function f(){
console.log(a,b);
var a = b = 2;
console.log(a,b);
}
f();
console.log(a,b);
----------------------------------------------------------------------------------------
变量提升
var a; var b; function f();
代码执行
console.log(a,b);//undefined undefined
a = 1; b = 1;
f();(此处调用函数)
--------函数内部栈:-------
变量提升:
var a;(函数内部有声明a,未声明b,b从上级元素中找)
形参赋值:无形参
代码执行:
console.log(a,b);//undefined,1
a = 2; b = 2;(此处的b是全局变量中的b)
console.log(a,b);//2,2
--------函数调用结束----
console.log(a,b);//1,2(此时的a还是原来全局变量的a,未改变,b在函数内部被改为了2)
var a = 1;
function f(){
console.log(a);//undefined
var a = 2;
console.log(a);//2
}
f();//undefined 1
console.log(a);//1
if (false) {
var a = 1;
}
function f() {
console.log(a);//undefined
var b = 666;
console.log(b);//666
}
f();
console.log(a);//undefined
console.log(b);//'b' is not defined
4、伪数组以及将伪数组转换为数组的几个方法
什么是伪数组?
伪数组具有以下特征:
- 具有length属性
- 能够使用数组遍历方法遍历它们
- 不具有数组的push,pop等方法
伪数组有哪些?
函数的argument参数;还有像调用getElementsByTagName;document.childNodes之类的
它们都返回NodeList对象,都属于伪数组
var obj5 = { name: ‘wangcai’ , age: ‘ 99’ }这样的数据也是伪数组
真伪数组如何判断?
let arr = [1,2,3];
let arr1 = {naem:'wangcai',age:'99'};
console.log(Array.isArray(arr)); //true
console.log(Array.isArray(arr1)); //false
将伪数组转换为数组的几个方法
方法一:
let newArr1 = Array.prototype.slice.call(arr1);
console.log(Array.isArray(newArr1)); //true
方法二
let newArr1 = Array.from(arr1);
console.log(Array.isArray(newArr1)); //true
方法三
对于伪数组arguments可以使用ES6里面的..…运算符
// 对于伪数组arguments可以使用ES6里面的...运算符
function fn (){
console.log(arguments); //Arguments { 0: 1, 1: 2, 2: 3, 3: 4, 4: 5, … }
console.log(Array.isArray(arguments)); //false
let newArr1 = [...arguments];
console.log(Array.isArray(newArr1)); //true
}
fn(1,2,3,4,5);
5、 奇怪的Math.Max()与Math.min()
// 一个参数,就返回该数
document.writeln( Math.max( 2 ) ); // 2
// 两个参数,返回较大的数
document.writeln( Math.max( -3, -3 ) ); // -3
// 多个参数时,返回最大的数
document.writeln( Math.max( -1, 2.1, 10.5, 7 ) ); // 10.5
// 没有传递任何参数
document.writeln( Math.max( ) ); // -Infinity
//传递的参数中有NaN值
document.writeln( Math.max( "张三", 10, 5 ) ); // NaN
6、 instanceof 和 typeof
7、 交集,并集,和差集
let arr1 = [5,6,7];
let arr2 = [6,7,8];
let arr3 = [7,8,9];
//并集是全部的去重复
function bin_v1 (param1,param2,param3){
let ret = new Set([...param1,...param2,...param3]);
return [...ret];
}
//交集是都有的部分
function jiao_v1(param1,param2,param3){
return param1.filter((val)=>{
return new Set(param2).has(val)
}).filter((val)=>{
return new Set(param3).has(val)
});
}
//并集减去交集是差集
function cha_v1(param1,param2,param3){
return bin_v1(param1,param2,param3).filter((val)=>{
return jiao_v1(param1,param2,param3).indexOf(val) === -1;
})
}
bin_v1(arr1,arr2,arr3)
jiao_v1(arr1,arr2,arr3);
cha_v1(arr1,arr2,arr3);
8、JavaScript数字转字符串,字符串转数字
//--------------------------字符串转数字-----------------------------------
var s = "234";
//1、纯数字转换
//1 字符串在运算操作中会被当做数字类型来处理
s *= 1;
//2 字符前加“+”
console.log(+s);
//3 string的两个转换函数,只对string有效
parseInt(s); // 234
parseFloat(s); //234
//4 强制类型转换
Number(s); // 234
//2、数字加字母等非数字转换
var s = '234string';
parseInt(s); //234
parseFloat(s); //234.0
//----------------------------数字转换字符串--------------------------------
var num=123123;
//1、toString()
console.log(num.toString());
//2、数字+任何字符串""
console.log(num+"");
// ----------------------------关于字符串----------------------------------
//判断是否包含某个字符串 包含返回下标 不包含返回-1
var i = str.indexOf("x")
//最后一次下标的字符串的字符串
var i = str .lastIndexOf("")
//转化大小写
str.toUpperCase() //转大写
str.tolowerCase()// 转小写
//截取字符串 字符串.substr("从哪开始","截取几个")
str.substr(0,5)
如果感觉对你有帮助,别忘了点个赞再走哦~