Web前端各面试经总结笔记

Web前端各面试经总结笔记_第1张图片

即将参加面试,逛了几个论坛学习了很多前端大牛的面试经,学习了很多,现收集总结与大家分享共同学习。

初学者阅后也要用心钻研其中的原理,重要知识需要系统学习、透彻学习,形成自己的知识链。临时抱佛脚只求面试侥幸混过关是错误的!也是不可能的!

本文比较基础精炼,欢迎评论指正,文章会不断更新。

? 文章列表

  • 一、JavaScript部分
  • 二、HTML和CSS部分
  • 三、开发性能优化

 

一、JavaScript

 

1.如何理解闭包


    function A() {
      let a = 1;
      function B() {
          console.log(a);
      }
      return B;
    }
    //函数 A 返回了一个函数 B,并且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包
    //就是闭包

    // 根据作用域链的规则,底层作用域没有声明的变量,会向上一级找,找到就返回,没找到就一直找,直到window的变量,没有就返回undefined。
    var count = 10;

    var cc = 'sss';

    function add() {
        var count = 0;

        return function () {
            console.log(count++);
            console.log(this.count++);
            console.log(cc);
        }
    }

    var s = add();
    s(); //0 10 sss
    s(); //1 11 sss
    s(); //2 12 sss



    // 循环中的闭包
    for (var i = 0; i < 10; i++) {
        setTimeout(function () {
            console.log(i);
        }, 1000);
    }
    // 上面的代码不会输出数字 0 到 9,而是会输出数字 10 十次。

    // 解决方法
    // 为了正确的获得循环序号,最好使用 匿名包装器,其实就是我们通常说的自执行匿名函数。
    for (var i = 0; i < 10; i++) {
        (function (e) {
            setTimeout(function () {
                console.log(e);
            }, 1000);
        })(i);
    }
    // 从匿名包装器中返回一个函数
    for (var i = 0; i < 10; i++) {
        setTimeout((function (e) {
            return function () {
                console.log(e);
            }
        })(i), 1000)
    }
    // 使用let
    for (let i = 0; i < 10; i++) {
        setTimeout(function () {
            console.log(i);
        }, 1000);
    }

 

2.JS继承的几种方式

 

3.JS深浅拷贝

   
    // 引入:

    let a = {
        age: 1
    };
    let b = a;
    a.age = 2;
    console.log(b.age); // 2

    // 上述例子如果给一个变量赋值一个对象,那么两者的值会是同一个引用,其中一方改变,另一方也会相应改变。

    // 浅拷贝
    // 1.使用 Object.assign
    // Object.assign是ES6新添加的接口,主要用来合并多个JavaScript对象。如果拷贝过来的属性的值是对象等复合属性
    // 如果拷贝过来的属性的值是对象等复合属性,那么只能拷贝过来一个引用。
    let aa = {
        age: 1
    };
    let bb = Object.assign({}, aa);
    aa.age = 2;
    console.log(aa.age); // 2
    console.log(bb.age); // 1

    // 2.通过展开运算符(...)解决
    let aaa = {
        age: 1
    };
    let bbb = {...aaa};
    aaa.age = 2;
    console.log(aaa.age); // 2
    console.log(bbb.age); // 1

    // 深拷贝  // 所需拷贝的属性的值为对象等复合属性是使用
    // 1.使用 JSON.parse(JSON.stringify(object)) (性能最优)
    let x = {
        age: 1,
        jobs: {
            first: 'first'
        }
    };
    let y = JSON.parse(JSON.stringify(x));
    x.jobs.first = 'second';
    console.log(x.jobs.first); // second
    console.log(y.jobs.first); // first

    // 此方法局限性:

    // 会忽略 undefined
    // 不能序列化函数
    // 不能解决循环引用的对象

 

4.JS拖拽

 

5.Cookie使用

window.onload = function () {
        document.cookie = "userID=10000";
        document.cookie = "name1=10000";
        //document.cookie = "name2=10000";
        document.cookie = "username=John Smith; expires=Thu, 18 Dec 2019 12:00:00 GMT; path=/";
        // expires:过期时间
        //移除Cookie name2
        //document.cookie = "name2=1;expires=-1";
        alert(document.cookie);

        //exdays: 过期天数
        function setCookie(cname, cvalue, exdays) {
            var d = new Date();
            d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
            var expires = "expires=" + d.toGMTString();
            document.cookie = cname + "=" + cvalue + "; " + expires;
        }

        function getCookie(cname) {
            var name = cname + "=";
            var ca = document.cookie.split(';');
            for (var i = 0; i < ca.length; i++) {
                var c = ca[i].trim();
                if (c.indexOf(name) == 0) {
                    return c.substring(name.length, c.length);
                }
            }
            return "";
        }

        function removeCookie(key) {
            setCookie(key, "", -1);
        }

        removeCookie("name2");
        setCookie('userID', '123', 600);

        alert(getCookie("userID"));
    }

 

6.Promise简化ajax异步处理

function myXHR(method, url, data) {
    var requset = new XMLHttpRequest();
    return new Promise((resolve, reject) => {
        requset.onreadystatechange = function () {
            if (requset.readyState === 4) {
                if (requset.status === 200) {
                    resolve(requset.responseText);
                }
                else {
                    reject(requset.status);
                }
            }
        }
        requset.open(method, url);
        requset.send(data);
    });
}

var p = myXHR('GET', 'url:');
p.then(responseText => {
    console.log(responseText);
}).catch(status => {
    console.log(new Error(status));
})

 

7.RAF-requestAnimationFrame-的使用

0%

    //显示器刷新率60Hz,so最平滑动画的最佳循环间隔为1000ms/60=16ms
    //requestID = requestAnimationFrame(callback);
    //requestAnimationFrame不需要设置时间间隔
    //回调函数作为参数传入,会返回一个整数(定时器的编号),可以传递给cancelAnimationFrame用于取消这个函数的执行
    //IE 9- 不支持该方法
    var timer1 = requestAnimationFrame(function () {
    });
    var timer2 = requestAnimationFrame(function () {
    });
    var timer3 = requestAnimationFrame(function () {
    });
    console.log(timer1);//1
    console.log(timer2);//2
    console.log(timer3);//3
    //cancelAnimationFrame
    cancelAnimationFrame(timer1);
    cancelAnimationFrame(2);
    cancelAnimationFrame(3);

    //兼容IE
    if (!window.requestAnimationFrame) {
        var lastTime = 0;
        window.requestAnimationFrame = function (callback) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));
            var id = window.setTimeout(function () {
                callback(currTime + timeToCall);
            }, timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        }
    }

    if (!window.cancelAnimationFrame) {
        window.cancelAnimationFrame = function (id) {
            clearTimeout(id);
        };
    }

    //示例
    var myDiv = document.getElementById('myDiv');
    var btn = document.getElementById('btn');
    var timer;
    btn.onclick = function () {
        myDiv.style.width = '0';
        cancelAnimationFrame(timer);
        timer = requestAnimationFrame(function fn() {
            if (parseInt(myDiv.style.width) < 500) {
                myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';
                myDiv.innerHTML = parseInt(myDiv.style.width) / 5 + ' %';
                timer = requestAnimationFrame(fn);
            } else {
                cancelAnimationFrame(timer);
            }
        });
    }

 

8.js怎么控制一次加载一张图片,加载完后再加载下一张(监控图片是否加载完成)

// 方法一
var obj=new Image();
obj.src="URL";
obj.onload=function(){
    alert('图片的宽度为:'+obj.width+';图片的高度为:'+obj.height);
    document.getElementById("mypic").innnerHTML="";
}

// 方法二
var obj=new Image();
obj.src="URL";
obj.onreadystatechange=function(){
    if(this.readyState=="complete"){
        alert('图片的宽度为:'+obj.width+';图片的高度为:'+obj.height);
        document.getElementById("mypic").innnerHTML="";
    }
}

 

9.Job queue 的执行顺序

//在Job queue中的队列分为两种类型:macro-task和microTask。

    // macro-task队列包含任务: a1, a2 , a3
    // micro-task队列包含任务: b1, b2 , b3
    //
    // 执行顺序为,首先执行marco-task队列开头的任务,也就是 a1 任务,执行完毕后,
    // 在执行micro-task队列里的所有任务,也就是依次执行***b1, b2 , b3***,执行完后清空micro-task中的任务,
    // 接着执行marco-task中的第二个任务,依次循环。

    //macro-task队列真实包含任务:
    //script(主程序代码),setTimeout, setInterval, setImmediate, I/O, UI rendering
    //micro-task队列真实包含任务:
    //process.nextTick, Promises, Object.observe, MutationObserver

    //举例
    setTimeout(function () {
        console.log(1)
    }, 0);

    new Promise(function (resolve, reject) {
        console.log(2);
        resolve();
    }).then(function () {
        console.log(3)
    }).then(function () {
        console.log(4)
    });

    process.nextTick(function () {
        console.log(5)
    });

    console.log(6);
    //输出2,6,5,3,4,1
    //这里要注意的一点在定义promise的时候,promise构造部分是同步执行的,这样问题就迎刃而解了。
    // 首先分析Job queue的执行顺序:
    //
    // script(主程序代码)——>process.nextTick——>promise——>setTimeout
    //
    //     I) 主体部分: 定义promise的构造部分是同步的,
    // 因此先输出2 ,主体部分再输出6(同步情况下,就是严格按照定义的先后顺序)
    //
    // II)process.nextTick: 输出5
    //
    //     III)promise: 这里的promise部分,严格的说其实是promise.then部分,输出的是3,4
    //
    //     IV) setTimeout : 最后输出1
    //
    //     综合的执行顺序就是: 2——>6——>5——>3——>4——>1

 

10.原生ajax的请求过程

function getXHR() {
        var xhr = null;
        if (window.XMLHttpRequest) {
            xhr = new XMLHttpRequest();
        } else if (window.ActiveXObject) {
            try {
                xhr = new ActiveXObject('Msxml2.XMLHTTP');//MSXML3
            } catch (e) {
                try {
                    xhr = new ActiveXObject('Microsoft.XMLHTTP')
                }
                catch (e) {
                    alert('不支持');
                }
            }
        }
        return xhr;
    }

    var xhr = getXHR();
    xhr.open('GET', url, true);//true 是否异步
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                var data = xhr.responseText;
                console.log(data);
            }
        }
    }
    xhr.onerror = function () {
        console.log('error');
    }
    xhr.send();//发送请求

 

11.JS检测变量类型

    var str = '123';
    var num = 3;
    console.log(typeof str); //string
    console.log(typeof num); //number

    console.log(typeof str === 'string'); //true
    console.log(typeof(num) === 'number'); //true
    console.log(str.constructor === String); //true

 

12.JS去除字符串空格

    var str = '  asd dasd s d sad asd asc   ';

    //方法一:使用replace正则匹配
    //去除所有空格
    console.log(str.replace(/\s*/g, '')); //asddasdsdsadasdasc

    //去除两头空格
    console.log(str.replace(/^\s*|\s*$/g, '')); //asd dasd s d sad asd asc

    //去除左空格
    console.log(str.replace(/^\s*/, '')); //asd dasd s d sad asd asc

    //去除右空格
    console.log(str.replace(/(\s*$)/g, '')); //  asd dasd s d sad asd asc

    //方法二:使用str.trim();(只能去除左右空格)
    console.log(str.trim()); //asd dasd s d sad asd asc

 

13.获取浏览器URL中查询字符串中的参数

    function showWindowHref(){
        // var sHref = window.location.href;
        var sHref = 'https://www.baidu.com/s?ie=UTF-8&wd=baidu';
        var args = sHref.split('?');
        if(args[0] == sHref){
            return "";
        }
        var arr = args[1].split('&');
        var obj = {};
        for(var i = 0;i< arr.length;i++){
            var arg = arr[i].split('=');
            obj[arg[0]] = arg[1];
        }
        return obj;
    }
    var href = showWindowHref(); // obj
    console.log(href); ////Object ie: "UTF-8"wd: "baidu"__proto__: Object

 

14.JS字符串操作函数

    var str = 'das12n12n 12 21n';
    var str1 = 'Hello World!', str2 = 'My name is 张三.', str3 = 'I am very Happy.';

    //stringObject.concat(str,...) 连接字符串
    console.log(str1.concat(str2, str3)); //Hello World!My name is 张三.I am very Happy.

    //stringObject.indexOf(searchvalue,fromindex) 方法可返回某个指定的字符串值在字符串中首次出现的位置。规定在字符串中开始检索的位置
    //不存在该字符串返回 -1;
    console.log(str1.indexOf('Hello')); //0
    console.log(str1.indexOf('HELLO')); //-1

    //stringObject.lastIndexOf(searchvalue,fromindex) 方法可返回某个指定的字符串值在字符串中最后出现的位置。规定在字符串中开始检索的位置
    //不存在该字符串返回 -1;
    console.log(str1.lastIndexOf('l')); //9
    console.log(str1.lastIndexOf('0')); //-1

    //stringObject.charAt() 返回指定位置的字符串
    console.log(str1.charAt(1)); //e

    //stringObject.match() 检查一个字符串是否匹配一个正则表达式
    console.log(str.match(/\d+/g));

    //stringObject.substr(start,length) 在字符串中抽取从 start: 下标开始的指定数目的字符 start-1 指字符串中最后一个字符,-2 指倒数第二个字符,以此类推
    console.log(str1.substr(0, 5)); //Hello
    console.log(str1.substr(-6, 5)); //World

    // stringObject.substring(start,stop) 用于提取字符串中介于两个指定下标之间的字符
    console.log(str1.substring(0, 11)); //Hello World
    console.log(str1.substring(0)); //Hello World!

    //stringObject.slice 提取字符串的一部分,并返回一个新字符串。
    console.log(str1.slice(0, 12)); //Hello World!
    console.log(str1.slice(0)); //Hello World!

    //replace() – 用来查找匹配一个正则表达式的字符串,然后使用新字符串代替匹配的字符串。
    console.log(str1.replace(/\s*/g, '_'));

    //search() – 执行一个正则表达式匹配查找。如果查找成功,返回字符串中匹配的索引值。否则返回 -1 。
    console.log(str1.search('H')); //0
    console.log(str1.search('ooo')); //-1

    //split() – 通过将字符串划分成子串,将一个字符串做成一个字符串数组。
    console.log(str1.split());

    var arr1 = str1.split();
    var arr2 = str2.split();
    var arr = arr1.concat(arr2);
    console.log(arr); //["Hello World!", "My name is 张三."]
    console.log(arr[1]); //My name is 张三.

    //toLowerCase() – 将整个字符串转成小写字母

    //toUpperCase() – 将整个字符串转成大写字母

 

15.JS创建、添加、移除、移动、复制、创建和查找节点

    var div1 = document.querySelector('#div1');
    var btn1 = document.querySelector('#btn1');
    var btn2 = document.querySelector('#btn2');
    var btn3 = document.querySelector('#btn3');

    //创建新节点
    //创建一个DOM片段
    var node1 = document.createDocumentFragment('

标题1

'); var browsers = ['Firefox', 'Chrome', 'Opera', 'Safari', 'Internet Explorer']; browsers.forEach(function (browser) { var li = document.createElement('li'); li.textContent = browser; node1.appendChild(li); }); //创建一个具体元素 var node2 = document.createElement('p'); //创建一个文本节点 var node3 = document.createTextNode('这是一个文本节点;HTML由元素节点和文本节点构成'); node2.appendChild(node3); // 添加、移除、替换、插入 //添加 btn1.onclick = function () { div1.appendChild(node1); div1.appendChild(node2); }; //移除 btn2.onclick = function () { div1.removeChild(node2); } //替换 replaceChild(new, old); btn3.onclick = function () { var node3 = document.createElement('h1'); node3.innerText = '标题'; div1.replaceChild(node3, node2); } //插入 inertBefore();inertAfter(); //查找 document.getElementById(); document.getElementsByName(); document.getElementsByTagName();

 

16.JS的各种位置

    //clientHeight表示的是可视区域的高度,不包含border和滚动条(css height + css padding)
    console.log('clientHeight:'+document.getElementById('div').clientHeight);
    //Element.scrollHeight 这个只读属性是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容
    console.log('scrollHeight:'+document.getElementById('div').scrollHeight);
    //HTMLElement.offsetHeight 是一个只读属性,它返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数
    console.log('offsetHeight:'+document.getElementById('div').offsetHeight);
    //clientTop一个元素顶部边框的宽度(以像素表示)。不包括顶部外边距或内边距。clientTop 是只读的
    console.log('clientTop:'+document.getElementById('div').clientTop);
    //Element.scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数。
    console.log('scrollTop:'+document.documentElement.scrollTop);
    //HTMLElement.offsetTop 为只读属性,它返回当前元素相对于其 offsetParent 元素的顶部的距离
    console.log('offsetTop:'+document.getElementById('div').offsetTop);
    

 

17.内存泄漏问题

// 定义和用法

    // 内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。
    // 浏览器中也是采用自动垃圾回收方法管理内存,但由于浏览器垃圾回收方法有bug,会产生内存泄露。

    // 内存泄漏的几种情况
    // 1.当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在IE中不会作出恰当处理,此时要先手工移除事件,不然会存在内存泄露。

    //实例如下
    var btn = document.getElementById("myBtn");
    // btn.onclick = function () {
    //     document.getElementById("myDiv").innerHTML = "Processing...";
    // }

    // 解决方法

    btn.onclick = function () {
        /******************
         * btn.onclick = null;
         *
         */
        btn.onclick = null;

        document.getElementById("myDiv").innerHTML = "Processing...";
    }

    //2.由于是函数内定义函数,并且内部函数--事件回调的引用外暴了,形成了闭包。闭包可以维持函数内局部变量,使其得不到释放。

    //实例如下
    function bindEvent() {
        var obj = document.createElement('XXX');
        obj.onclick = function () {
            // Even if it is a empty function
        };
    }

    //解决方法
    function bindEvent() {
        var obj = document.createElement('XXX');
        obj.onclick = function () {
            // Even if it is a empty function
        };
        obj = null;
    }

 

18.JS面向对象中继承的实现(ES5和ES6)

    //ES5:寄生组合式继承:通过借用构造函数来继承属性和原型链来实现子继承父。
    function Animal(name) {
        this.name = name || 'Animal';
        this.sleep = function () {
            console.log('(Animal sleep) -> ' + this.name);
        }
    }

    Animal.prototype.eat = function (food) {
        console.log('(Animal eat) -> ' + food + ' -> ' + this.name);
    }

    function Cat(name) {
        Animal.call(this);
        this.name = name || 'Cat';
    }

    Cat.prototype = Object.create(Animal.prototype);
    Cat.prototype.constructor = Cat;
    Cat.prototype.eatFish = function (num) {
        num = num || 'a little';
        console.log('(Cat eatFish) -> ' + this.name + ' -> ' + num);
    };

    // Object.create()的polyfill
    /*
    function pureObject(o){
        //定义了一个临时构造函数
         function F() {}
         //将这个临时构造函数的原型指向了传入进来的对象。
         F.prototype = obj;
         //返回这个构造函数的一个实例。该实例拥有obj的所有属性和方法。
         //因为该实例的原型是obj对象。
         return new F();
    }
    */

    let animal = new Animal('Dog');
    console.log(animal.name); //Dog
    animal.sleep(); //(Animal sleep) -> Dog
    animal.eat('Meat'); //(Animal eat) -> Meat -> Dog

    console.log('-----------'); //-----------

    let cat = new Cat('Big Cat');
    console.log(cat.name); //Big Cat
    cat.sleep(); //(Animal sleep) -> Big Cat
    cat.eat('Small Fish'); //(Animal eat) -> Small Fish -> Big Cat
    cat.eatFish('more'); //(Cat eatFish) -> Big Cat -> more

    // ES6
    class Animal {
        constructor(name) {
            this.name = name || 'Animal';
            this.sleep = function () {
                console.log('(Animal sleep) -> ' + this.name);
            }
        }

        eat(food) {
            console.log('(Animal eat) -> ' + food + ' -> ' + this.name);
        }
    }

    class Cat extends Animal {
        constructor(name) {
            super(name || 'Cat');
        }

        eatFish(num) {
            num = num || 'a little';
            console.log('(Cat eatFish) -> ' + this.name + ' -> ' + num);
        }

        //重新声明父类同名方法会覆盖,ES5直接在原型链上操作
        eat(food) {
            console.log('(重写的)(Animal eat) -> ' + food + ' -> ' + this.name);
        }
    }

    let animal = new Animal('Dog');
    console.log(animal.name); //Dog
    animal.sleep(); //(Animal sleep) -> Dog
    animal.eat('Meat'); //(Animal eat) -> Meat -> Dog

    console.log('-----------'); //-----------

    let cat = new Cat('Big Cat');
    console.log(cat.name); //Big Cat
    cat.sleep(); //(Animal sleep) -> Big Cat
    cat.eat('Small Fish'); //(重写的)(Animal eat) -> Small Fish -> Big Cat
    cat.eatFish('more'); //(Cat eatFish) -> Big Cat -> more

 

19.JS Array对象

    var arr1 = [1, 2, 3, 41, 4, 3, 312, 3, 123];

    console.log(arr1.constructor);
    console.dir(arr1.constructor);

    // Array对象方法
    // join() 用于把数组中的所有元素放入一个字符串。
    var arr = new Array(3)
    arr[0] = "George"
    arr[1] = "John"
    arr[2] = "Thomas"

    console.log(arr.join(".")); //George.John.Thomas

    //pop() 删除并返回数组的最后一个元素
    console.log(arr1.pop()); //123

    //shift() 删除并返回数组的第一个元素

    // push() 向数组的末尾添加一个或更多元素,并返回新的长度。
    var arrPush = ['first', 'second'];
    console.log(arrPush.push('third', 'fourth'));
    console.log(arrPush); //(4) ["first", "second", "third", "fourth"]

    // unshift() 向数组的开头添加一个或更多元素,并返回新的长度。

    // reverse() 颠倒数组中元素的顺序
    console.log(arrPush.reverse()); //(4) ["fourth", "third", "second", "first"]

    // splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目
    // arrayObject.splice(index,howmany,item1,.....,itemX)
    // index	必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
    // howmany	必需。要删除的项目数量。如果设置为 0,则不会删除项目。
    // item1, ..., itemX	可选。向数组添加的新项目。

    // toSource() 返回该对象的源代码。
    // 只有 Gecko 核心的浏览器(比如 Firefox)支持该方法,也就是说 IE、Safari、Chrome、Opera 等浏览器均不支持该方法。
    function employee(name, job, born) {
        this.name = name;
        this.job = job;
        this.born = born;
    }

    var bill = new employee("Bill Gates", "Engineer", 1985);
    console.log(bill.toSource());

    // toString() 把数组转换为字符串,并返回结果。

    // toLocaleString() 把数组转换为本地数组,并返回结果。

    // valueOf() 返回数组对象的原始值

 

20.数组去重的几种方法

    var arr = [12, 1, 1, 1, 3, 1, 3, 12, 3, 14, 2, 45, 2, 34, 21, 3, 12, 3, 21312, 3];
    var obj = {};
    var tmp = [];//去重后
    var rec = [];//重复的

    //方法一
    for (let i = 0; i < arr.length; i++) {
        if (!obj[arr[i]]) {
            obj[arr[i]] = 1;
            tmp.push(arr[i]);
        } else {
            rec.push(arr[i]);
        }
    }
    console.log(tmp);
    // 0: 12
    // 1: 1
    // 2: 3
    // 3: 14
    // 4: 2
    // 5: 45
    // 6: 34
    // 7: 21
    // 8: 21312
    console.log(rec);
    // 0: 1
    // 1: 1
    // 2: 1
    // 3: 3
    // 4: 12
    // 5: 3
    // 6: 2
    // 7: 3
    // 8: 12
    // 9: 3
    // 10: 3

    // 方法二
    var tmp2 = [];
    var rec2 = [];
    for (let i = 0; i < arr.length; i++) {
        if (tmp2.indexOf(arr[i]) < 0) {
            tmp2.push(arr[i]);
        }
        else {
            rec2.push(arr[i]);
        }

    }
    console.log(tmp2);
    // 0: 12
    // 1: 1
    // 2: 3
    // 3: 14
    // 4: 2
    // 5: 45
    // 6: 34
    // 7: 21
    // 8: 21312
    console.log(rec2);
    // 0: 1
    // 1: 1
    // 2: 1
    // 3: 3
    // 4: 12
    // 5: 3
    // 6: 2
    // 7: 3
    // 8: 12
    // 9: 3
    // 10: 3

    //方法3
    var tmp3 = arr.filter(function (element, index, self) {
        return self.indexOf(element) === index;
    });
    console.log(tmp3);
    // 0: 12
    // 1: 1
    // 2: 3
    // 3: 14
    // 4: 2
    // 5: 45
    // 6: 34
    // 7: 21
    // 8: 21312

 

21.防抖

 
    const text = document.getElementById('text');
    text.oninput = debounce(search, 500);

    let flag = 0;

    function search() {
        flag++;
        console.log(`发起请求${flag}次`);
    }

    function debounce(fn, delay) {
        var timer = null;
        return function () {
            // 通过 ‘this’ 和 ‘arguments’ 获取函数的作用域和变量
            var context = this;
            var args = arguments;
            // 清理掉正在执行的函数,并重新执行
            clearTimeout(timer);
            timer = setTimeout(function () {
                fn.apply(context, args);
            }, delay);
        }
    }

    // function debounce(fn, delay) {
    //     let timer
    //     return function (...args) {
    //         if (timer) clearTimeout(timer)
    //         timer = setTimeout(() => {
    //             fn.apply(this, args)
    //         }, delay)
    //     }
    // }

 

二、HTML和CSS部分

 

1.清除浮动的几种方式

        /* 最好方法使用:after */

        div:after{
            content: '';
            clear: both;
            display: block;
            width: 0;
            height: 0;
        }

        /* 或者新建一个空元素来清除浮动 */

        .clear{
            clear: both;
            height: 0;
            line-height: 0;
            font-size: 0;
        }

        /* 给父元素增加overflow属性 */

        .over-flow{
            over-flow: auto;
            zoom: 1; /* 触发IE hasLayout, 处理兼容性问题*/
        }

2.引入样式link与import区别

    
    

    
    
  • 区别1:link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS。
  • 区别2:link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载。
  • 区别3:link是XHTML标签,无兼容问题;@import是在CSS2.1提出的,低版本的浏览器不支持。
  • 区别4:ink支持使用Javascript控制DOM去改变样式;而@import不支持。

3.CSS画三角形

div{
            width: 0;
            height: 0;
            border: 100px solid transparent;
            border-bottom-color: red;/*下边框,向上的三角形*/
        }

4.不使用border新建一个一像素的直线

 

5.HTML5新特性

  • 语义化标签 nav header footer section aside
  • 绘图的canvas
  • 媒体的video和audio
  • localStorage与sessionStorage
  • 表单控件:calendar、date、time、email、url、search

  • html5 与 html可以使用标签或者doctype区分


    语义化使HTML结构更清晰,便于浏览器解析,利于SEO搜索,使代码更好理解,便于维护

     

    6.CSS3动画

                /*2D转换 transform*/
                transform: translate(-20px, -20px); /*坐标内移动*/
                transform: rotate(45deg); /*旋转*/
                transform: scale(0.8); /*缩放*//*给定的宽度(X 轴)和高度(Y 轴)参数。transform: scale(2,4);*/
                transform: skew(0, 20deg); /*倾斜*/
                transform: matrix(0, 0, 0, 0, 0, 0); /*把所有 2D 转换方法组合在一起,需要六个参数,包含数学函数,允许您:旋转、缩放、移动以及倾斜元素*/
    
                /*3D转换*/
                transform: rotateX(120deg); /*元素围绕其 X 轴以给定的度数进行旋转*/
                transform: rotateY(120deg); /*元素围绕其 Y 轴以给定的度数进行旋转*/
    
                /*transition 过渡效果*/
                transition-property: all; /*执行动画对应属性 color background*/
                transition-duration: 5s; /*动画持续时间*/
                transition-timing-function: linear; /*动画变化的速率 ease | linear | ease-in | ease-out | ease-in-out | cubic-bezier */
                transition-delay: 5s; /*延迟多久开始动画*/
                transition: all 5s linear 5s;
    
                /*animation 动画*/
                animation-name: name;
                animation-duration: 5s;
                animation-timing-function: linear;
                animation-delay: 5s;
                animation-iteration-count: infinite; /*指定元素播放动画的循环次数 infinite | */
                animation-direction: normal; /*指定元素动画播放的方向,其只有两个值,默认值为normal,如果设置为normal时,动画的每次循环都是向前播放;另一个值是alternate,他的作用是,动画播放在第偶数次向前播放,第奇数次向反方向播放。*/
                animation-play-state: paused; /*控制元素动画的播放状态*/
                animation: name 5s linear 5s infinite normal paused;

     

    7.CSS垂直和水平居中的几种方式

    不固定宽高
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: -25%;
    margin-top: -25%;
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores aut deserunt incidunt itaque voluptate. Enim et eum, neque nihil officia perspiciatis suscipit tenetur voluptatem voluptatum! Architecto dolorem doloribus perspiciatis vitae.
    不固定宽高
    transform:translate(50%,50%)
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores aut deserunt incidunt itaque voluptate. Enim et eum, neque nihil officia perspiciatis suscipit tenetur voluptatem voluptatum! Architecto dolorem doloribus perspiciatis vitae.
    固定宽高
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    right: 0;
    margin: auto;
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores aut deserunt incidunt itaque voluptate. Enim et eum, neque nihil officia perspiciatis suscipit tenetur voluptatem voluptatum! Architecto dolorem doloribus perspiciatis vitae.
    父元素使用:
    display: flex;
    justify-content: center;
    align-items: center;
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores aut deserunt incidunt itaque voluptate. Enim et eum, neque nihil officia perspiciatis suscipit tenetur voluptatem voluptatum! Architecto dolorem doloribus perspiciatis vitae.
    grid布局
    父元素:display:grid;
    子元素:align-self: center;
    justify-self: center;
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores aut deserunt incidunt itaque voluptate. Enim et eum, neque nihil officia perspiciatis suscipit tenetur voluptatem voluptatum! Architecto dolorem doloribus perspiciatis vitae.
    父盒子宽高为100%
    table布局
    父元素:display:table;
    子元素:display:table-cell text-align: center;
    verical-align: middle;
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Asperiores aut deserunt incidunt itaque voluptate. Enim et eum, neque nihil officia perspiciatis suscipit tenetur voluptatem voluptatum! Architecto dolorem doloribus perspiciatis vitae.

     

    三、开发性能优化

    1.规避JavaScript多人开发函数重名问题

        // 1.命名空间
        // var MYNAMESPACE=MYNAMESPACE||{};
        // 若全局空间中已有同名对象,则不覆盖该对象;否则创建一个新的命名空间。
    
        // 举例
        var MYNAMESPACE=MYNAMESPACE||{};
    
        MYNAMESPACE.person=function (name) {
            this.name=name;
        };
        MYNAMESPACE.person.prototype.getName=function () {
            return this.name;
        };
    
        var p=new MYNAMESPACE.person('NAME');
        console.log(p.getName());
    
    
        // 2.封闭空间
        // js中的封闭空间主要是利用了给变量加括号结果不变
    
        // 书写方式
        ;(function () {
            // code...
        })();
        // 在函数前面加分号是为了避免被别人坑,导致和别的程序猿发生肢体冲突:
        // 如果别人的代码没有写分号,如果代码压缩的时候就会发生问题,
        // 这个时候我们自己的代码就会拯救我们,而两个分号写在一起时是没有问题的。
    
        // 3.JS模块化MVC(数据层、表现层、控制层)
    
        // 4.seajs
        // SeaJS是一个遵循CMD规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制
    
    
        // 5.变量转化成对象的属性
        var WMD={};
        WMD['name']='张三';
    
        WMD['person']=function (name) {
            this.name=name;
        };
    
        WMD.person.prototype.getName=function () {
            return this.name;
        };
    
        var _p=new WMD.person('Tom');
        console.log(_p.getName());
        console.log(WMD);
    
        // 6.对象化

     

    2.降低页面加载时间的方法

    (1) 压缩css、js文件

    // 在线压缩工具:http://tool.oschina.net/jscompress
    // 由后端动态生成或工具直接生成(grunt+requirejs)

    (2) 合并js、css文件,减少http请求

    // 页面引入的的js,css越多的话,那么对就增加了http请求数
    
    // 以合并JS文件为例,使用bat批处理命令
    // 新建.bat批处理文件 内容 /b:固定参数
    // 语法 cope 文件1.文件类型+文件2.文件类型 合并后文件名.文件类型 \b
    // 例如 copy G.js+T.JS GT_bin.js /b
    
    // 由后端动态生成或工具直接生成(grunt+requirejs)

    (3) 外部js、css文件放在最底下

    (4) 减少dom操作,尽可能用变量替代不必要的dom操作

     

    3.web前端提高页面性能优化

      针对HTML
    
            1. 避免再HTML中直接写css代码。
    
            2. 使用Viewport加速页面的渲染。
    
            3. 使用语义化标签,减少css的代码,增加可读性和SEO。
    
            4. 减少标签的使用,dom解析是一个大量遍历的过程,减少无必要的标签,能降低遍历的次数。
    
            5. 避免src、href等的值为空。
    
            6. 减少dns查询的次数。
            7. 避免再HTML中直接写css代码。
    
       针对CSS:
    
            1.优化选择器路径:
                相比于 .a .b .c{} ,更倾向于大家写.c{}
    
            2.压缩文件
    
            3.选择器合并
                把有共同的属性内容的一系列选择器组合到一起
    
            4.精准样式  减少不必要的属性设置
                比如你只要设置{padding-left:10px}的值,那就避免{padding:0 0 0 10px}这样的写法
    
            5.雪碧图
    
            6.避免通配符
                .a .b *{} 像这样的选择器,根据从右到左的解析顺序在解析过程中遇到通配符(*)会回去遍历整个dom
    
            7.少用float
                Float在渲染时计算量比较大,尽量减少使用。
    
            8. 0 值去单位
    
            9.把 CSS 放到代码页上端
    
      针对JavaScript :
    
            1. 脚本放到 HTML 代码页底部 (Put Scripts at the Bottom)
    
            2. 尽可能合并script代码
    
            3. css能干的事情,尽量不要用JavaScript来干。
    
            4. 尽可能压缩的js文件,减少资源下载的负担
    
            5. 尽可能避免在js中逐条操作dom样式,尽可能预定义好css样式,然后通过改变样式名来修改dom样式,这样集中式的操作能减少reflow或repaint的次数。
    
            6. 尽可能少的在js中创建dom,而是预先埋到HTML中用display:none来隐藏,在js中按需调用,减少js对dom的暴力操作。
    
      面向图片(Image):
    
            1.优化图片
    
            2 不要在 HTML 中使用缩放图片
    
            3 使用恰当的图片格式
    
    
    
    
     

    4.图像优化 图片格式区别

    //     优化图像:
    //     1、不用图片,尽量用css3代替。 比如说要实现修饰效果,如半透明、边框、圆角、阴影、渐变等,在当前主流浏览器中都可以用CSS达成。
    //    
    //     2、 使用矢量图SVG替代位图。对于绝大多数图案、图标等,矢量图更小,且可缩放而无需生成多套图。现在主流浏览器都支持SVG了,所以可放心使用!
    //    
    //     3.、使用恰当的图片格式。
    //     我们常见的图片格式有JPEG、GIF、PNG。
    //     基本上,内容图片多为照片之类的,适用于JPEG。
    //     而修饰图片通常更适合用无损压缩的PNG。
    //     GIF基本上除了GIF动画外不要使用。且动画的话,也更建议用video元素和视频格式,或用SVG动画取代。
    //    
    //     4、按照HTTP协议设置合理的缓存。
    //    
    //     5、使用字体图标webfont、CSS Sprites等。
    //    
    //     6、用CSS或JavaScript实现预加载。
    //    
    //     7、WebP图片格式能给前端带来的优化。WebP支持无损、有损压缩,动态、静态图片,压缩比率优于GIF、JPEG、JPEG2000、PG等格式,非常适合用于网络等图片传输。
    //    
    //     图像格式的区别:
    //     矢量图:图标字体,如 font-awesome;svg
    //    
    //     位图:gif,jpg(jpeg),png
    //    
    //     区别:
    //
    //   1、gif:是是一种无损,8位图片格式。具有支持动画,索引透明,压缩等特性。适用于做色彩简单(色调少)的图片,如logo,各种小图标icons等。
    //
    //   2、JPEG格式是一种大小与质量相平衡的压缩图片格式。适用于允许轻微失真的色彩丰富的照片,不适合做色彩简单(色调少)的图片,如logo,各种小图标icons等。
    //
    //   3、png:PNG可以细分为三种格式:PNG8,PNG24,PNG32。后面的数字代表这种PNG格式最多可以索引和存储的颜色值。
    //
    //     关于透明:PNG8支持索引透明和alpha透明;PNG24不支持透明;而PNG32在24位的PNG基础上增加了8位(256阶)的alpha通道透明;
    //
    //     优缺点:
    //
    //   1、能在保证最不失真的情况下尽可能压缩图像文件的大小。
    //
    //   2、对于需要高保真的较复杂的图像,PNG虽然能无损压缩,但图片文件较大,不适合应用在Web页面上。

    5.浏览器渲染页面流程

    Web前端各面试经总结笔记_第2张图片

      1.解析HTML文件,创建DOM树。
         浏览器通过HTMLParser(HTML解析器)根据深度遍历的原则把HTML解析成DOM Tree。
         自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)。
    
      2.解析CSS。
         将CSS解析成CSS Rule Tree(CSSOM Tree)。
         优先级:浏览器默认设置<用户设置<外部样式<内联样式

    (部分未完成,待更新)

    你可能感兴趣的:(Web学习,Web支持)