前端常见面试题

让我们来看看有哪些常见的面试题,比如:

1、typeof能判断哪些类型?

2、何时使用===何时使用==?

3、window.onload和DomCententLoaded有什么区别?

4、JS创建5个P标签,点击的时候弹出对应的序号?

5、手写节流 throttle、防抖debounce?

6、Promise解决了什么问题?

7、值类型和引用类型的区别?

8、手写深拷贝?

9、手写一个简易的jQuery,考虑插件和扩展性?

10、this的不同应用场景,如何取值?

11、手写bind函数、手写call函数

12、闭包在实际开发的应用场景

13、同步和异步的区别

14、手写用promis加载一张图片

15、前端使用异步的场景有哪些?

16、编写一个通用的事件监听函数

17、描述事件冒泡的流程

18、无限下拉的图片列表,如何监听每个图片的点击

19、手写一个简易的ajax

20、跨域常用的实现方式

21、前端常见的攻击方式

22、前端性能优化

解答:

1、typeof可以判断所有的值类型,可以判断函数类型,判断不了引用类型,如图:

 

2、a==null情况可以用两等,因为null == undefined 为 true,其他情况下全部用三等

 

3、window.load页面的全部资源加载完才执行,包括图片,视频

     DomCententLoaded页面渲染完就执行,图片和视频可能还没加载完,一般用这个方法,不需要等图片和视频加载完

 

4、

for(let i = 0; i < 5; i++) {
    let p = document.createElement('p');
    p.innerHTML = i + '<br/>';
    p.addEventListener('click', function(e) {
        alert(i);
    })
    document.body.appendChild(p)
}

 

5、防抖debounce,如果输入框正在输入的时候不会触发函数,输入停止1s的时候,才触发函数

//监听输入框变化onchange
//简单版
let time;
document.getElementById('input').addEventListener('keyup', () => {
    if (time) {
        clearTimeout(time)
    }

    time = setTimeout(() => {
        time == null
    }, 1000)
})

//封装版
function debounce(fn, second = 500) {
    let time;
    return function () {
        if (time) {
            clearTimeout(time)
        }

        time = setTimeout(() => {
            fn.apply(this, arguments)
            time == null
        }, second)
    }

}

document.getElementById('input').addEventListener('keyup', debounce(() => {
    console.log(document.getElementById('input').value)
}, 1000))

节流throttle,不管拖拽的多快,函数触发时间都一样

//监听div拖拽事件drag
let time;
document.getElementById('div').addEventListener('drag', () => {
    if (time) {
        return
    }

    time = setTimeout(() => {
        time == null
    }, 1000)
})

function throttle(fn, second = 500) {
    let time;
    return function () {
        if (time) {
            return;
        }

        time = setTimeout(() => {
            fn.apply(this, arguments)
            time == null
        }, second)
    }

}

document.getElementById('div').addEventListener('drag', throttle((e) => {
    console.log(e.offsetX)
}, 600))

 

6、promise解决了callback hell的问题

//用callback的时候如果逻辑复杂,然后一层一层去加载代码看起来不优雅,可读性不好,而且也显得的复杂,调试也不好调试
$.get('./geo.json', function (data){
    console.log(data)

    $.get('./geo1.json', function (data1){
        console.log(data1)

        $.get('./geo2.json', function (data2){
            console.log(data2)

            $.get('./geo3.json', function (data3){
                console.log(data3)
            })
        })
    })
})

 

7、值类型赋值的时候修改不会改变原始值,引用类型赋值的时候修改会改变原始值

//值类型
let a = 100;
let b = a;
a = 200;
console.log(b)  //打印100

//引用类型
let a = {number: 10};
let b = a;
a.number = 20;
console.log(b.number)   //打印20

8、

var a = {
    a: 1,
    b: '2',
    c: {
        m: 'hahah'
    },
    d: [1,2,3]
}

function deep(obj = {}) {
    //如果不是对象和数组直接返回,typeof只能判断值类型
    if(typeof obj !== 'object' || obj == null) {
        return obj;
    }
    
    let result
    //判断是数组还是对象
    if(obj instanceof Array) {
        result = []
    } else {
        result = {}
    }
    
    for (let key in obj) {
        //判断是否为自身属性
        if (obj.hasOwnProperty(key)) {
            result[key] = deep(obj[key])
        }
    }
    return result
}
var b = deep(a);
a.a = 3;

console.log(b.a) //打印1而不是3

9、

class Jquery {
    constructor(selector){
        let result = document.querySelectorAll(selector);
        let length = result.length;
        for(let i = 0; i < length; i++) {
            this[i] = result[i];
        }
        this.length = length;
        this.selector = selector;
    }
    get(index) {
        return this[index];
    }
    each(fn) {
        for(let i = 0; i < this.length; i++) {
            let elem = this[i];
            fn(elem)
        }
    }
    on(type, fn) {
        return this.each(elem => {
            elem.addEventListener(type, fn, false);
        })
    }
}

//插件
Jquery.prototype.dialog = function(val) {
    alert(val)
}

//扩展
class my extends Jquery {
    constructor(selector) {
        super(selector)
    }
    addClass(name) {
    }
    style(name) {
    }
}

//使用获取p元素
const $ = new Jquery('p')
$.get(1)
$.each(elem => console.log(elem.nodeName))
$.on('click', () => {alert(1)})

10、查看基础知识(作用域和闭包)

11、

Function.prototype.bind1 = function () {
    let args = Array.prototype.slice.call(arguments)
    //获取this
    let t = args.shift();
    let self = this
    return function () {
        return self.apply(t, args)
    }
}


function fn1(a, b) {
    console.log(this)
    console.log(a,b)
}

let fn2 = fn1.bind1({a: 10}, 1, 2)
fn2()  //打印{a: 10} 1 2
var value = 'v in window';
function func() {
    arguments = [].slice.call(arguments, 0);
    console.log(arguments);
    console.log(this.value);
}
var obj = {
    value: 'v in obj'
};
Function.prototype.call2 = function (obj) {
    var obj = obj || window;
    var args = [];
    //从第1项开始循环,过滤掉第一个参数
    for(var i = 1; i < arguments.length; i++) {
        args.push(arguments[i]);
    }
    obj.fn = this;
    obj.fn(...args);
    delete obj.fn; //要删除obj.fn,否则obj就会多个fn
};

func(1,2,3); //打印 [1,2,3]  v in window
func.call2(obj,1,2); //打印[1,2]  v in obj

12、封装变量,闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。

var add = (function () {
    var counter = 0;
    return function () {return counter += 1;}
})();

add();
add();
add();

// 计数器为 3

13、js是单线程的语言,js和DOM渲染共用一个线程,因为js可以修改DOM,同步会阻塞代码执行,页面会卡住,异步不会阻塞代码执行

14、

function creatImg(url) {
    return new Promise((resolve, reject) => {
        var img = document.createElement('img');
        img.onload = function (){
            resolve(img)
        }
        img.onerror = function (data){
            reject(data)
        }
        img.src = url
    })
}

creatImg('./1.png').then((img) => {
    console.log(img.width)
    return img
}).then((img) => {
    console.log(img.height)
    return creatImg('./2.png')
}).then((img2) => {
    //img2是creatImg('./2.png')函数返回的数据
    console.log(img2.height)
    return img2
}).catch(() => {
    console.log('error')
})

15、网络请求(ajax、图片的加载等)、定时任务(setTimeout等)

//ajax
console.log(1)
$.get('./geo.json', function (data){
    console.log(data)
})
console.log(2)


//加载图片
console.log(1)
var img = document.createElement('img');
img.onload = function (data){
    console.log(data)
}
img.src = './1.png'
console.log(2)

//定时器
console.log(1)
setTimeOut(function (){
    console.log(3)
}, 1000)
console.log(2)

16、

//html
<body>
    <div id='div1'>1</div>
    <div id='div2'>2</div>
</body>

//js
function  bindEvent(ele, type, selector, fn) {
    if (fn == null) {
        fn = selector;
        selector = null
        ele.addEventListener(type, fn)
    }
    ele.addEventListener(type, function(e){
        let target = e.target;
        if (selector) {
            if(target.matches(selector)){
                fn.call(target, event)
            }
        } else {
                fn.call(target, event)  
        }
    })
}
var div1 = document.getElementById('div1')
bindEvent(div1, 'click', function (e) {
    console.log(this.innerHTML)
    console.log(e.target)
    console.log(e.preventDefault())    //阻止事件默认行为
    console.log(e.stopPropagation())    //阻止事件冒泡
})

var body = document.body
bindEvent(body, 'click', 'div', function (e) {
    e.preventDefault()
    console.log(this.innerHTML)
})

17、事件冒泡:点击div,body的点击事件也会执行

//html
<body>
    <div id='div1'>1</div>
    <div id='div2'>2</div>
</body>

//js
function  bindEvent(ele, type, fn) {
    ele.addEventListener(type, fn)
}
var div1 = document.getElementById('div1')
bindEvent(div1, 'click', function (e) {
    console.log(e.target)
    console.log(e.preventDefault())    //阻止事件默认行为
    console.log(e.stopPropagation())    //阻止事件冒泡
})

var body = document.body
bindEvent(body, 'click', function (e) {
    console.log(e.target)
})

18、

//html
<body>
    <div id='div1'><img src='./1.png'/></div>
    <div id='div2'><img src='./2.png'/></div>
</body>

//js
function  bindEvent(ele, type, fn) {
    ele.addEventListener(type, fn)
}

var body = document.body
bindEvent(body, 'click', function (e) {
    e.preventDefault()
    let target = e.target
    if(target.nodeName == 'div') {
        console.log(target.innerHTML)
    }
})

19、

//get请求
let http = new XMLHttpRequest()
http.open('get', '/web?fname=Henry', true)
http.onreadystatechange = function () {
    if (http.readyState == 4) {
        if (http.status == 200) {
            console.log(http.responseText)
        }
    }
}
http.send()

//post请求
let xmlhttp = new XMLHttpRequest()
xmlhttp.open("POST","/try/ajax/demo_post2.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("fname=Henry&lname=Ford");


//模拟ajax
function ajax(url) {
    let p = new Promise((resolve, reject) =>{
        let http = new XMLHttpRequest()
        http.open('get', url, true)
        http.onreadystatechange = function () {
            if (http.readyState == 4) {
                if (http.status == 200) {
                    resolve(http.responseText)
                }
            }
            else{
                reject('错误')
            }
        }
        http.send()
    })
    return p

}

ajax('./a.js').then((data) => {
    console.log(data)
}).catch((data) => {
    console.log(data)
})

20、主要的有jsonp、cors(cors为后端设置响应请求头)

//jsonp

window.callback = function (data) {
    console.log(data) //打印{name: hello}
}
//注意这个script标签也可以用document.createElement('script')创建
<script src='http://a.com/a.js'></script> //js返回callback({name: hello})

21、

XSS跨站请求攻击(例如写一篇文章,里面嵌入script代码获取cookie,别人访问你的文章是发送别人的cookie到自己的服务器)

XSS预防:替换特殊字符,显示html实体

CSRF跨站请求伪造(例如正在浏览购物网站,突然收到一封邮件,邮件中有一个<img  src='http://aa.com/pay/id=300'>,如果你打开邮件,就直接付款了)

CSRF预防:使用post接口,用img访问是不通的,增加验证(密码,短信,指纹)

 

22、

让加载更快(压缩代码,减少资源体积;合并代码,减少访问次数;SSR服务器端渲染,缓存;)

让渲染更快(CSS放在head,JS放在body最后面;尽早开始执行JS,用DomCententLoaded触发;懒加载;对DOM查询进行缓存;频繁操作DOM,合并后再一起插入DOM结构;节流,防抖)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值