『前端面试资料』 个人面试准备手稿 2020/10

这篇博客整理了前端面试的重要知识点,包括HTML、CSS的布局技巧,JavaScript的基础与进阶,如DOM操作、正则表达式、对象深拷贝、闭包、函数柯里化、ES5/6特性、原生AJAX和Node.js服务器创建。此外,还涵盖了算法中的归并排序,以及面试中常遇到的问题和错误,如异步问题的解决和深拷贝的实现方式。
摘要由CSDN通过智能技术生成

HTML



CSS


九宫格

		.myul{
            list-style: none;
            width: 400px;
            height: 100px;
            float: top;
        }
        .myli{
            width: 80px;
            height: 80px;
            margin: 10px;
            float: left;
            background-color: red;
            border-radius: 50%; /*轮廓圆角*/
        } 
	<div class="mydiv">
        <ul class="myul">
            <li class="myli"></li>
            <li class="myli"></li>
            <li class="myli"></li>
        </ul>
        <ul class="myul">
            <li class="myli"></li>
            <li class="myli"></li>
            <li class="myli"></li>
        </ul>
        <ul class="myul">
            <li class="myli"></li>
            <li class="myli"></li>
            <li class="myli"></li>
        </ul>
    </div>
  • 10.26:float建议用flex-flow: row wrap代替

三栏布局

        .container{
            display: flex;
            width: 1000px;
            height: 500px;
        }
        .left{
            flex-basis: 200px;
            background-color: red;
        }
        .right{
            flex-basis: 100px;
            background-color: blue;
        }
        .middle{
            flex: 1;
            background-color: green;
        }
    <div class="container">
        <div class="left"></div>
        <div class="middle"></div>
        <div class="right"></div>
    </div>
  • flex-basis 属性用于设置或检索弹性盒伸缩基准值。(即弹性盒元素的初始长度)
  • flex 属性用于设置或检索弹性盒模型对象的子元素如何分配空间。(让所有弹性盒模型对象的子元素都有相同的长度,且忽略它们内部的内容)
  • 参考:flex属性-flex:1到底是什么

半圆

        .mysemi{
            width: 50px;
            height: 100px;
            border: 1px solid transparent; /*width style color*/
            background-color: red;
            border-radius: 100px 0 0 100px; /*左上 右上 右下 左下*/
        }
	<div class="mysemi"></div>

三角形

		.tri{
            width: 0;
            height: 0;
            border: 50px solid;
            border-color: red transparent transparent transparent; /*上 右 下 左*/
        }
    <div class="tri"></div>



JS


基础


DOM

  • 复选框操作
	dom.checked = true; //false

E-mail正则表达式

    let reg = /^ \w+ ([-+.] \w+)* @ \w+ ([-.] \w+)* \. \w+ ([-.] \w+)* $/;



对象


深拷贝

  • 递归
	const deepCopy = obj => {
        let newobj = {};
        for(let i in obj) {
            if(typeof obj[i] != Object)
                newobj[i] = obj[i];
            else
                newobj[i] = deepCopy(obj[i]);
        }
        return newobj;
    };
    //浅拷贝:Object.assign(newobj, obj);
    //Object.create()是另一个方法
  • 孤儿写法
	let newobj = JSON.parse(JSON.stringify(obj));

new操作符的过程


  • classA为例
  1. 生成空对象
	let obj = {};
  1. 绑定原型和构造函数
	obj.__proto__ = classA.prototype;
	obj.constuctor = classA; //不用
  1. 绑定this
	classA.apply(obj, arguments);
  1. 返回

组合继承

        //警告:可以用const 慎用箭头函数
        
        const Father = function(name) { 
            this.name = name; //父类属性1
        };
        Father.prototype.getName = function() {
            return this.name; //父类方法1
        };

        const Son = function(name, age) {
            Father.call(this, name);
            this.age = age; //子类属性2
        };
        Son.prototype.getAge = function() {
            return this.age; //子类方法2
        }

        //继承1:原型指向父类实例
        Son.prototype = Object.create(Father.prototype);
        //继承2:原型的构造函数指回
        Son.prototype.constructor = Son;

        //测试
        let s1 = new Son("hello", 18);
        console.log(s1.getName()); //输出hello


函数


函数参数引用传递

  • 基本数值(Number、Boolean、String):值传递,只给值的副本
  • 复杂类型(Ojbect、Array):引用传递,给你引用此地址的一个指针
  1. 如果你在指针基础修改,则原地址内容也会修改
  2. 如果你把此指针指向其他位置,则原地址内容更改不了

闭包

	var add = (function () {
        var counter = 0; //直接执行一次=初始化
        return function () {return counter += 1;} //每次执行通过返回function改变值
        //需要取出值用return 否则只做操作
    })();

    t = add();console.log(t); //1
    t = add();console.log(t); //2
    t = add();console.log(t); //3
    //console.log(counter); //报错:闭包内定义不可使用

闭包实现m秒输出一个helloworld 输出k次

	const test = () => {
        let time = 5;
        let timer = null;
        return () => {
            timer = setInterval(() => {
                if(time > 0) {
                    console.log("hello world");
                    time--;
                }
                else
                    clearInterval(timer);
            }, 100);
        }
    };
    test()(); 
    //传参则失去闭包的意义 
    //执行时则运行一次,初始化 
    //加监听器也是因为小闭包执行一次

函数柯里化

    function add2(x) {
        return function(y) {
            return x + y;
        }
    }
    //const add2 = x => y => x + y;

    console.log(add2(1)(2)); //3
    function add3(x) {
        return function(y) {
            return function(z) {
                return x + y + z;
            }
        }
    }
    //const add3 = x => y => z => x + y + z;

    console.log(add3(1)(2)(3)); //6

call、apply、bind的相互实现

  • call和apply实现bind
    Function.prototype.bindAsApply = function(target) {
        let that = this; //保留当前this            
        let args = [].slice.call(arguments, 1); //arguments.slice(1)的合法写法
        //args = [...arguments].slice(1); //另一种写法
        return () => that.apply(target, args); //当前this使用apply,调用target和参数
    };
    Function.prototype.bindAsCall = function(target) {
        let that = this; //保留当前this
        let args = [].slice.call(arguments, 1); //arguments.slice(1)的合法写法
        //args = [...arguments].slice(1); //另一种写法
        return () => that.call(target, ...args); //当前this使用call,调用target和参数rest
    };
    //测试对象
    let obj = {name : 'aaa'};
    //测试函数
    function test(...args) { //根据参数形式决定是否用rest
        console.log('this:', this);
        console.log('我的名字:', this.name);
        console.log('我接收的参数:', args);
    }
    //测试语句
    test.bindAsApply(obj, 1, 2, 3)();
    test.bindAsCall(obj, 1, 2, 3)();

防抖和节流

  • 防抖:利用计时器灵活赋值
function debounce(fn, delay){ //防抖
    let timer = null;
    return function(){
        let that = this;
        timer && clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(that, arguments);
        }, delay)
    }
}
  • 节流:利用布尔值翻转
function throttle(fn, delay){ //节流
    let tag = true;
    return function(){
        if(!tag)
            return;
        let that = this;
        tag = false;
        setTimeout(() => {
            fn.apply(that, arguments);
            tag = true;
        }, delay)
    }
}

ES56


for-in和for-of

  • for in 总是得到key键值或者index索引(可用于对象 可枚举类型等)
    for index in arr 遍历数组 index是索引 arr[index]是值
  • for of 总是得到值(对象不可用)
    for val of arr 遍历数组 val是值
  • 要求可迭代对象,for i in 10 和for i of 10都不可

Array.sort()

回调函数的坑:

return a > b 

结果为true和false 就是1和0 只有小于0才交换

return a - b 

为正确写法


set进行数组去重

	let a = [1, 2, 3, 4, 3, 2, 1];
    a = [...(new Set(a))];
    console.log(a);

mapAPI

	//new
    let mymap = new Map();
    //基本方法
    mymap.set('a', 1);
    mymap.get('a'); //1
    mymap.has('a'); //true
    //遍历map
    mymap.forEach((value, key) => {});
    for(let item in mymap.values());
    for(let item in mymap.keys());
    for(let item in mymap); //数组
    for(let item in mymap.entries()); //等价上面
    //遍历计数的习惯写法
    mymap.set(item, mymap.has(item) ? mymap.get(item) + 1 : 1);

交互


原生AJAX

  • GET
	const ajax = (url) => {
		let xhr = new XMLHttpRequest();
		xhr.open('GET', url, true); //信息存放在url中
		xhr.send();
		xhr.onreadystatechange = function(){
		if(this.readyState == 4 && this.status == 200) 
			console.log(this.responseText);
    	}
	}
  • POST
	const ajax = (url, objstring) => {
		let xhr = new XMLHttpRequest();
		xhr.open('POST', url, true);
		xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //必备
		xhr.send(objstring); //信息存放在字符串中发送
		xhr.onreadystatechange = function(){
		if(this.readyState == 4 && this.status == 200) 
			console.log(this.responseText);
    	}
	}

· readyState

0:请求未初始化
1:服务器连接已建立
2:请求已收到
3:正在处理请求
4:请求已完成且响应已就绪


node.js建服务器

    var http = require('http');
    http.createServer(function (request, response) {
        response.setHeader('Access-Control-Allow-Origin', '*'); //CORS跨域资源共享
        response.writeHead(200, {'Content-Type': 'text/plain'});
        response.write('abc');
        response.end('Hello World\n');
    }).listen(8888);



算法


归并排序

        const merge = (arrLeft, arrRight) => { //合并两个排序数组
            let result = [];
            while(arrLeft.length && arrRight.length)
                result.push(arrLeft[0] < arrRight[0] ? arrLeft.shift() : arrRight.shift());
            result = result.concat(arrLeft.length ? arrLeft : arrRight); //数组连接只能用concat并赋返回值,或者双rest(不好用)
            return result;
        };
        const mergeSort = arr => {
            const LEN = arr.length;
            if(LEN < 2)
                return arr;
            else{
                let mid = Math.floor(LEN / 2);
                let arrLeft = arr.slice(0, mid);
                let arrRight = arr.slice(mid);
                return merge(mergeSort(arrLeft), mergeSort(arrRight)); //双路合并,嵌大排序
            }
        };



先前问题总结


面试时犯过的错误

  • 深拷贝忘了说用JSON
  • 默写完归并排序,考官问时间复杂度,我忘了
  • 面试时说,对象的静态属性不常用
  • 面试时说,自己不知道什么东西应该封装为组件(就是没深入学vue,还给自己找借口)
  • 考官问,为什么没做移动端适配,写的css都是定死的长度宽度,连个百分比都没有,我无言以对

老异步问题:点击列表输出索引号

  • HTML
  <div class="a">文字</div>
  <div class="a">文字</div>
  <div class="a">文字</div>
  <div class="a">文字</div>
  <div class="a">文字</div>

  1. JS:var + onclick - 不可以,点哪个都是输出总长度
    let a = document.getElementsByClassName('a');
    for(var i = 0; i < a.length; i++) {
      a[i].onclick = () => { console.log(i) };
    }

  1. JS:var + 监听器 - 不可以,点哪个都是输出总长度
    let a = document.getElementsByClassName('a');
    for(var i = 0; i < a.length; i++) {
      a[i].addEventListener('click', () => {console.log(i)});
    }

  1. JS:let+ onclick - 可以
    let a = document.getElementsByClassName('a');
    for(let i = 0; i < a.length; i++) {
      a[i].onclick = () => { console.log(i) };
    }

  1. JS:let + 监听器 - 可以
    let a = document.getElementsByClassName('a');
    for(let i = 0; i < a.length; i++) {
      a[i].addEventListener('click', () => {console.log(i)});
    }

  1. JS:var + 闭包 - 可以
    let a = document.getElementsByClassName('a');
    for(var i = 0; i < a.length; i++) {
      (function (item) {
        a[i].addEventListener('click', () => {console.log(item)});
      })(i);
    }

  1. JS:let + 闭包 - 可以
    let a = document.getElementsByClassName('a');
    for(var i = 0; i < a.length; i++) {
      (function (item) {
        a[i].addEventListener('click', () => {console.log(item)});
      })(i);
    }
  • 结论:
  1. 问题不在于是加onclick属性还是加addeventListener监听器
  2. 问题只在于var,var定义变量的局限性
  3. 要么改成let,要么改用闭包,任何一个都可以工作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大熊软糖M

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值