前端各种问题总结

305 阅读8分钟

这是我学习前端过程中遇到的一系列问题,我经过查资料、看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、 instanceoftypeof

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);&emsp;//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)

如果感觉对你有帮助,别忘了点个赞再走哦~