title: 基础面试题
date: 2019-10-12 20:23:00
updated: 2019-10-12 20:23:00
tags: ['web前端面试']
基础面试题
1. bootstrap删格化系统标识,区间分割
超小屏幕 手机 (<768px) | 小屏幕 平板 (≥768px) | 中等屏幕 桌面显示器 (≥992px) | 大屏幕 大桌面显示器 (≥1200px) | |
---|---|---|---|---|
栅格系统行为 | 总是水平排列 | 开始是堆叠在一起的,当大于这些阈值时将变为水平排列C | ||
.container 最大宽度 | None (自动) | 750px | 970px | 1170px |
类前缀 | .col-xs- | .col-sm- | .col-md- | .col-lg- |
2.给定一个数组,vue循环li,每个添加上添加点击事件,点击在li上添加active类
let li = [{'id':1, 'name':'lxl', 'isShow': false}, {'id':2, 'name':'lxl', 'isShow': false}];
<ul>
<li v-for="(value, index) in data" :key="index" :class="{active: value.isShow}" @click="func(value.id)">
数据
</li>
</ul>
3. js原型链
原型(prototype)
在JavaScript中,原型(prototype)也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个prototype内部属性,这个属性所对应的就是该对象的原型。
prototype作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了 __ proto__ 这个非标准(不是所有浏览器都支持)的访问器(ECMA引入了标准对象原型访问器 Object.getPrototype(object))。在JavaScript的原型对象中,还包含了一个construcor属性,这个属性对应创建所有指向该原型的实例的构造函数。-
原型链
原型链的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。因为每个对象和原型都有原型,对象的原型指向原型对象,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链(prototype chain)[图片上传失败...(image-cf33f9-1571671166427)]
// 构造函数 function Foo (name, age) { this.name = name; } Foo.prototype.alertName = function() { alert(this.name) } // 创建示例 var f = new Foo('张三') f.printName = function() { console.log(this.name) } console.log(f.__proto__); f.printName() f.alertName() f.toString() /* 要去 f.__proto__.__proto__ 里找*/
4. 怎样用原型链继承对象
// 动物
function Animal() {
this.eat = function () {
console.log('animal eat')
}
}
// 狗
function Dog() {
this.brak = function() {
console.log('dog bark')
}
}
Dog.prototype = new Animal()
// 哈士奇
var hashiqi = new Dog()
5. 原型规则和示例
-
所有的引用类型(对象,数组,函数),都具有对象特性,即可自由扩展属性(除了null 以外)
var obj = {}; obj.a = 100; var arr = []; arr.a = 100; function fn () {} fn.a = 100;
-
所有的引用类型(数组、对象、函数),都有一个"proto" 属性,属性值是一个普通的对象
console.log(obj.__proto__); console.log(arr.__proto__); console.log(fn.__proto__);
-
所有的函数,都有一个 prototype 属性,属性值也是一个普通的对象
console.log(fn.prototype);
-
所有的引用类型(数组、对象、函数),proto属性值指向它的构造函数的 ”prototype“ 属性值
console.log(obj.__proto__ === Object.prototype);
-
当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的 proto(即它的构造函数的prototype)中寻找。
// 构造函数 function Foo (name, age) { this.name = name; } Foo.prototype.alertName = function() { alert(this.name) } // 创建示例 var f = new Foo('张三') f.printName = function() { console.log(this.name) } f.printName() f.alertName()
5. 对象实例化
-
利用内置对象创建直接实例
JavaScript有一个内置对象Object,利用它可以创建一个空白的对象。aObject = new Object();
利用构造函数实例化对象
当我们需要实例化多个对象时,有必要使用构造函数来创建对象。
构造函数的声明
function Person(personName) { // 括号内为参数,可以设置多个参数来定制对象。
this.name = personName; // 将传入的personName值赋予name属性
this.info = 'I am called' + this.name; //设置info属性
this.infoShow = function () { // 利用匿名函数添加方法
alert(this.info);
}
}
// 对象实例化
var person1 = new Person('Adam');
var person2 = new Person('Eve'); //利用构造函数实例化了两个对象,并根据传入的参数的不同,定制了两个不同的对象。
6. 对象的静态方法
Javascript语言的面向对象特征很弱,其他面向对象语言在创建类时只要使用关键字static即可指定类为静态类,Javascript没有提供static这样的关键字,要让Javascript也具有“静态”特性只有靠一些“奇技淫巧”了。
代码中列举了两种静态方法/属性的实现方式,一种是静态类的静态方法和属性,另一种是非静态类的静态方法和属性,代码说明都写在每行的代码注释里,这里就不重复了。
/****************************************
* 方法一
* 类、方法、属性都为静态类型
* 不能创建实例
*****************************************/
var Time = {
today: ‘2009-3-8′,
weather: ‘rain’,
show: function() {
alert(‘Today is ‘ + this.today);
}
};
//静态对象可直接使用,无需创建实例
alert(‘It is ‘ + Time.weather + ‘ today.’);
Time.show();
//下面的代码会出错,因为静态类不能创建实例
//var t = new Time();
//t.show();
/****************************************
* 方法二
* 普通对象,同时拥有静态和非静态属性、方法
* 可以用实例化
* 注意:
* 1.静态方法/属性使用类名访问
* 2.非静态方法/属性使用实例名访问
*****************************************/
function Person(name) {
//非静态属性
this.name = name;
//非静态方法
this.show = function() {
alert(‘My name is ‘ + this.name + ‘.’);
}
}
//添加静态属性,人都是一张嘴
Person.mouth = 1;
//添加静态方法,哇哇大哭
Person.cry = function() {
alert(‘Wa wa wa …’);
};
//使用prototype关键字添加非静态属性,每个人的牙可能不一样多
Person.prototype.teeth = 32;
//非静态方法必须通过类的实例来访问
var me = new Person(‘Zhangsan’);
//使用非静态方法、属性
me.show();
alert(‘I have ‘ + me.teeth + ‘ teeth.’);
//使用静态方法、属性
Person.cry();
alert(‘I have ‘ + Person.mouth + ‘ mouth.’);
7. this指向
https://www.jianshu.com/p/5f8440535a2a
8. 怎样改变this指向(call, apply,bind)
https://www.runoob.com/w3cnote/js-call-apply-bind.html
call, apply,bind这三个方法可以用来改变this的指向,
用法:
funcName.call(Obj, 参数1, 参数2, 参数3...)
funcName.apply(Obj, [参数1, 参数2, 参数3...])
funcName.bind(Obj, 参数1, 参数2, 参数3...)()
三个方法第一个参数都相同,都是this的新指向对象,后面的参数都是向方法里面传递的参数,apply需要将参数放在数组里,call和bind相同,都是字符串罗列,不同的是bind返回的是函数
9. 常见的浏览器兼容问题
event.srcElement问题
问题说明:IE下,event对象有srcElement属性,但是没有target属性;Firefox下,even对象有target属性,但是没有srcElement属性。
解决方法:使用srcObj =event.srcElement ?event.srcElement : event.target;ajax略有不同
IE:ActiveXObject
其他:xmlHttpReuestevent.x 与 event.y 问题
在IE中,event 对象有x,y属性,FF中没有
在FF中,与 event.x 等效的是 event.pageX ,但event.pageX IE中没有
故采用 event.clientX 代替 event.x ,在IE中也有这个变量
event.clientX 与 event.pageX 有微妙的差别,就是滚动条
要完全一样,可以这样:
mX = event.x ? event.x : event.pageX;
然后用 mX 代替 event.xcss中的width和padding
在IE7和FF中width宽度不包括padding,在Ie6中包括padding.边框:
border-radius: 最低兼容至 IE9,其它浏览器兼容情况优良。
box-shadow: 最低兼容至IE9, 其它浏览器兼容情况优良。背景:
background-size: 最低兼容至IE9, 其它浏览器兼容情况优良。
7.字体:
@font-face: IE9及以上版本的IE浏览器,支持引入任何格式的字体文件,而在IE9之前的浏览器,只支持引入EOT格式的字体文件。 其它浏览器兼容情况优良。
- 2D转换:
transform: 最低兼容至IE9(需要添加-ms-前缀),其它浏览器兼容情况优良。在transform属性前加入浏览器内核前缀是很好的实践。不建议在svg元素上使用transform属性,最新版本的IE并不支持这一使用方式。 - 3D转换:
IE10 和 Firefox 支持 3D 转换。Chrome 和 Safari 需要前缀 -webkit-。Opera 仍然不支持 3D 转换,它只支持2D 转换。 - 过渡:
transition:最低兼容至IE10,其它浏览器兼容情况优良。Safari浏览器需要前缀-webkit-,其它大部分浏览器对此并未有前缀要求,因此除了特殊情况,可以不添加其它浏览器的前缀。 - 动画:
animation:兼容情况与transition属性大致相同。
还有很多.....
10. ajax 实现原理
(1)创建xmlHttpRequest对象(异步调用对象);
(2)创建http请求,设置请求方法,URL及验证信息;
(3)设置响应HTTP请求状态变化的函数.
(4)发送http请求;
(5)获取异步的数据;
(6)使用JavaScript和DOM实现局部刷新;
var xmlHttp;
if(window.XMLHttpRequest){ //针对除IE6以外的浏览器
xmlHttp=new XMLHttpRequest(); //实例化一个XMLHttpRequest
}else{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP"); //针对IE5,IE6
}
xmlHttp.open('get','demo_get.html','true');//调用open()方法并采用异步方式
xmlHttp.send(); //使用open()方法将请求发送出去
xmlHttp.onreadystatechange()=>{
if(xmlHttp.readyState === 4 && xmlHttp.status === 200){
}
}
11. iframe遇到跨域怎么传递数据
window方法:postMessage() https://www.w3cschool.cn/fetch_api/fetch_api-lx142x8t.html
iframe跨域相互传值–messageEvent.js https://www.xgllseo.com/?p=5058
12. jQ的扩展方法
两种扩展机制
// jQuery中利用上面实现的扩展机制,添加了许多方法,其中
// 直接添加在构造函数上,被称为工具方法
jQuery.extend({
isFunction: function() {},
type: function() {},
parseHTML: function() {},
parseJSON: function() {},
ajax: function() {}
// ...
})
// 添加到原型上
jQuery.fn.extend({
queue: function() {},
promise: function() {},
attr: function() {},
prop: function() {},
addClass: function() {},
removeClass: function() {},
val: function(v) {
//自写方式,原生方式实现
v=this[0].defaultValue
return v;
},
css: function() {},
html:function(el){
//自写方式,原生方式实现
console.log(this);
el=this[0].innerText;
return el
}
// ...
})
13. jQ的链式操作是怎么实现的
- 实现原理:
这里使用原生js来模拟这样的效果:
let fun = {
fun1: function() {
console.log("fun1");
return this;
},
fun2: function() {
console.log("fun2");
return this;
},
fun3: function() {
console.log("fun3");
return this;
}
}
fun.fun1().fun2().fun3();
这样就可以连续的输出字符串的fun1、fun2、fun3 了,原因是在每个方法后面加了一个return this。
如果没有加上return this语句的话,那么执行完一个函数之后,会默认返回undefined,这个是js内部自己隐式添加的。返回undefined的时候,再调用另一个方法肯定就会报错,因为undefined是没有方法的。
- 为什么要返回this?
因为在一个对象里面,this指向的是对象本身,而我们连续调用方法的时候,这些方法都是在对象内部定义的,所以this是可以访问到这些方法
例子:
function jQ(selector){
this.elem = document.querySelectorAll(selector)[0];
}
jQ.prototype = {
html: function(strHtml) {
let elem = this.elem;
elem.innerHTML = strHtml;
return this;
},
on: function(type, func) {
let elem = this.elem;
elem.addEventListener(type, func)
return this
}
};
window.$ = function(selector) {
return new jQ(selector);
}
console.log($('#test_demo'));
$('#test_demo').html('<a>111</a>').on('click', function() {
console.log('click');
})
14. 计算阶乘
function jie(n) {
if (n > 1) {
return n * jie(n-1)
} else {
return 1
}
}
console.log(jie(6));
15. 使用vuex状态管理,刷新页面后会不会丢失
会,可以解决,使用插件vue-savedata
16. typeof NaN ?
number
17. 有个id为isShow的元素,需要在ios系统上显示android上隐藏,如何实现?
function open_or_download_app() {
// alert(navigator.userAgent);
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
return 'ios'
} else if (/(Android)/i.test(navigator.userAgent)) {
return 'android'
} else {
return 'pc'
}
};
console.log(open_or_download_app());
18. alert(!0&&6)输出什么?
输出: 6
```
a || b:如果a是true,那么b不管是true还是false,都返回true。因此不用判断b了,这个时候刚好判断到a,因此返回a。
```
如果a是false,那么就要判断b,如果b是true,那么返回true,如果b是false,返回false,其实不就是返回b了吗。
a && b:如果a是false,那么b不管是true还是false,都返回false,因此不用判断b了,这个时候刚好判断到a,因此返回a。
如果a是true,那么就要在判断b,和刚刚一样,不管b是true是false,都返回b。
```
19. 如何阻止事件冒泡和默认事件?
js冒泡和捕获是事件的两种行为,使用event.stopPropagation()起到阻止捕获和冒泡阶段中当前事件的进一步传播。使用event.preventDefault()可以取消默认事件
-
防止冒泡和捕获 (单词:propagation,繁殖,传播)
w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true
stopPropagation也是事件对象(Event)的一个方法,作用是阻止目标元素的冒泡事件,但是会不阻止默认行为。什么是冒泡事件?如在一个按钮是绑定一个”click”事件,那么”click”事件会依次在它的父级元素中被触发 。stopPropagation就是阻止目标元素的事件冒泡到父级元素。如:<div id='div' onclick='alert("div");'> <ul onclick='alert("ul");'> <li onclick='alert("li");'>test</li> </ul> </div>
上面的代码,Demo如下,我们单击test时,会依次触发alert(“li”),alert(“ul”),alert(“div”),这就是事件冒泡。
阻止冒泡
window.event? window.event.cancelBubble = true : e.stopPropagation();取消默认事件
w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;
preventDefault它是事件对象(Event)的一个方法,作用是取消一个目标元素的默认行为。既然是说默认行为,当然是元素必须有默认行为才能被取消,如果元素本身就没有默认行为,调用当然就无效了。什么元素有默认行为呢?如链接<a>,提交按钮<input type=”submit”>等。当Event 对象的 cancelable为false时,表示没有默认行为,这时即使有默认行为,调用preventDefault也是不会起作用的。
我们都知道,链接<a>的默认动作就是跳转到指定页面,下面就以它为例,阻止它的跳转:
//假定有链接<a href="http://caibaojian.com/" target="_blank" rel="external nofollow" id="testA" >caibaojian.com</a>
var a = document.getElementById("testA");
a.onclick =function(e){
if(e.preventDefault){
e.preventDefault();
}else{
window.event.returnValue == false;
}
}
- 总结
当需要停止冒泡行为时,可以使用
function stopBubble(e) {
//如果提供了事件对象,则这是一个非IE浏览器
if ( e && e.stopPropagation )
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
else
//否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}
当需要阻止默认行为时,可以使用
//阻止浏览器的默认行为
function stopDefault( e ) {
//阻止默认浏览器动作(W3C)
if ( e && e.preventDefault )
e.preventDefault();
//IE中阻止函数器默认动作的方式
else
window.event.returnValue = false;
return false;
}
20. 已知一个元素的ID为DIV,请将该元素的html内容设置为xxxx,字体颜色设置为黑色(不使用第三方框架)
var node = document.getElementById('DIV');
node.innerHTML = 'xxxx';
node.style.color = '#000';
21. 获取当前日期,以2017-01-01这种格式。
Js获取当前日期时间和格式化日期
var myDate = new Date();
myDate.getYear(); //获取当前年份(2位)
myDate.getFullYear(); //获取完整的年份(4位,1970-????)
myDate.getMonth(); //获取当前月份(0-11,0代表1月)
myDate.getDate(); //获取当前日(1-31)
myDate.getDay(); //获取当前星期X(0-6,0代表星期天)
myDate.getTime(); //获取当前时间(从1970.1.1开始的毫秒数)
myDate.getHours(); //获取当前小时数(0-23)
myDate.getMinutes(); //获取当前分钟数(0-59)
myDate.getSeconds(); //获取当前秒数(0-59)
myDate.getMilliseconds(); //获取当前毫秒数(0-999)
myDate.toLocaleDateString(); //获取当前日期
var mytime=myDate.toLocaleTimeString(); //获取当前时间
myDate.toLocaleString( ); //获取日期与时间
var myDate = new Date();
myDate.toLocaleDateString().replace(/\//g, '-'); //获取当前日期
22. 如何居中一个浮动元素
再包裹上一个元素,margin: 0 auto;
23. js中使用typeof能获取几种类型
6种:undefined,boolean,numer,string,object,function
typeof 'sss' /* "string" */
typeof 1 /* "number" */
typeof false /* "boolean" */
typeof {} /* "object" */
typeof [] /* "object" */
typeof null /* "object" */
typeof function s(){} /* "function" */
typeof undefined /* "undefined" */
// ES6多了一个symbol类型
var a = Symbol()
typeof a /* "symbol" */
24. 何时使用 ==== 和 == ?
if(obj.a == null) {
/* (obj.a === null || obj.a === undefined)的简写 */
/* jquery源码推荐 */
}
25. js中哪些内置函数 - 数据封装类对象
Object
Array
Boolean
Number
String
Function
Date
RegExp
Error
26. js按照存储方式区分那些类型,并描述其特点
```
// 值类型 值是复制的,有自己的内存空间,相互之间不会影响
var a = 10;
var b = a;
a = 11;
console.log(b); /* 10 */
// 引用类型 指向同一个内存地址,赋值操作时时指针的相互传递,减少内存开销,
var obj1 = {x: 100};
var obj2 = obj1;
obj1.x = 200
console.log(obj12.x); /* 200 */
```
27. 如何准确判断一个变量是数组类型
```
var arr = [];
arr instanceof Array; // true
typeof arr // object
```
28. 写一个原型链继承的例子
```
// 动物
function Animal() {
this.eat = function () {
console.log('animal eat')
}
}
// 狗
function Dog() {
this.brak = function() {
console.log('dog bark')
}
}
Dog.prototype = new Animal()
// 哈士奇
var hashiqi = new Dog()
```
29. 描述new一个对象的过程
* 创建一个新对象
* this 指向这个新对象
* 执行代码,即对this赋值
* 返回 this
```javascript
function Foo (name, age) {
this.name =name;
this.age = age;
this.calss = 'class-1'
// return this // 默认有这一行
}
var f = new Foo('zhangsan', 20)
```
30. zepto(或其他框架) 源码中如何使用原型链
```javascript
function jQ(selector){
this.elem = document.querySelectorAll(selector)[0];
}
jQ.prototype = {
html: function(strHtml) {
let elem = this.elem;
elem.innerHTML = strHtml;
return this;
},
on: function(type, func) {
let elem = this.elem;
elem.addEventListener(type, func)
return this
}
};
window.$ = function(selector) {
return new jQ(selector);
}
console.log($('#test_demo'));
$('#test_demo').html('<a>111</a>').on('click', function() {
console.log('click');
})
```
31. 闭包
先来一下“闭包”的解释~
一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。闭包的特点:
(1) 作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
(2) 一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
简单的说,javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。闭包有三个特性:
(1) 函数嵌套函数。
(2) 函数内部可以引用外部的参数和变量。
(3)参数和变量不会被垃圾回收机制回收。闭包的好处:
(1) 希望一个变量长期存储在内存中。
(2) 避免全局变量的污染。
(3) 私有成员的存在。-
闭包的缺点:
(1) 常驻内存,增加内存使用量。
(2) 使用不当会很容易造成内存泄露。// 闭包 1. 函数作为返回值 function F1() { var a = 100; // 返回一个函数(函数作为返回值) return function () { console.log(a); } } // f1 得到一个函数 var f1 = F1() var a = 200; f1() // 闭包 2. 函数作为参数来传递 function F1() { var a = 100; return function() { console.log(a) } } var f1 = F1(); function F2(fn) { var a = 300; fn() } F2(f1) // 100
闭包使用场景
// 闭包实际应用中主要封装的变量,收敛权限 function isFirstLoad() { var _list = []; return function (id) { if (_list.indexOf(id) >= 0) { return false } else { return true } } } // 使用 var firstLoad = isFirstLoad() firstLoad(10) // true firstLoad(10) // false firstLoad(20) // true
32. 原生js 创建十个a标签,点击标签提示该a标签的索引
```javascript
for(var i = 0; i < 10; i++) {
(function(i) {
// 函数作用域
var a = document.createElement('a');
a.innerHTML = i + '<br/>';
a.addEventListener('click', function(e) {
e.preventDefault();
alert(i) // 自由变量,要去副作用域获取值
});
document.body.appendChild(a)
})(i)
}
```
33. 获取 2017-06-10 格式的日期
Date.now() // 获取当前毫秒数
var dt = new Date()
dt.getTime() // 获取毫秒数
dt.getFullYear() // 年
dt.getMonth() // 月(0-11)
dt.getDate() // 日(0-31)
dt.getHours() // 小时(0-23)
dt.getMinutes() // 分钟(0-59)
dt.getSeconds() // 秒(0-59)
34. 获取随机数,要求是长度一直的字符串格式
一、预备知识
Math.ceil(n); //向上取整。返回大于等于n的最小整数。
Math.floor(n); //向下取整。返回为n的整数部分。
Math.round(n); //四舍五入。返回为n四舍五入后的整数。
Math.random(n); //0.0 ~ 1.0 之间的一个伪随机数。【包含0,不包含1】 //比如0.8647578968666494
Math.ceil(Math.random()*10); // 获取从1到10的随机整数 ,取0的概率极小。
Math.floor(Math.random()*10); //可均衡获取0到9的随机整数。
Math.round(Math.random()); //可均衡获取0或1的随机整数。(因为random()生成的是0-1的数,四舍五入后只有0或1)
Math.round(Math.random()*10); //基本均衡获取0到10的随机整数,其中获取最小值0和最大值10的几率少一半。
因为结果在0~0.4 为0,0.5到1.4为1...8.5到9.4为9,9.5到9.9为10。所以头尾的分布区间只有其他数字的一半。
var random = Math.random()
var random = random + '0000000000' // 后面加上 10 个零
var random = random.slice(0, 10)
console.log(random)
35. 写一个能遍历对象和数组的通用 forEach 函数
数组API
```
forEach 遍历所有元素
var arr = [1, 2, 3]
arr.forEach(function(item, index) {
// 遍历所有元素
console.log(index, item);
});
every 判断所有元素是否都符合条件
var arr = [1, 2, 3]
arr.every(function(item, index) {
// 判断所有元素是否都小于4
if ( item < 4) {
return true
}
return false
});
some 判断是否有至少一个元素符合条件
var arr = [1, 2, 3]
arr.some(function(item, index) {
// 判断是否有至少一个元素是小于2
if ( item < 2) {
return true
}
return false
});
sort 排序
var arr = [1, 2, 3]
arr.sort(function(a, b) {
return a - b;
// return b - a;
});
map 对元素重新组装,生成新数组
var arr = [1, 2, 3]
var arr2 = arr.map(function(item, index) {
// 对元素重新组装,并返回
return "<b>" + item + "</b>";
});
console.log(arr2);
console.log(arr);
filter 过滤符合条件的元素
var arr = [1, 2, 3]
var arr2 = arr.filter(function(item, index) {
if ( item < 2) {
return true
}
});
console.log(arr2);
console.log(arr);
```
```
function forEach(obj, fn) {
var key
if (obj instanceof Array) {
// 准确判断是不是数组
obj.forEach(function(item, index) {
fn (index, item)
})
} else {
// 不是数组的就是对象
for (key in obj) {
fn(key, obj[key])
}
}
}
```
36. DOM 是哪种基本的数据结构?
树
37. DOM 操作的常用 API 有哪些
-
获取节点,以及获取节点的 Attribute 和 prototype
// 获取DOM节点 var div1 = document.getElementById('div1') // 元素 var divList = document.getElementsByTagName('div') // 元素 var containerList = document.getElementsByClassName('container') // 集合 var pList = document.querySelectorAll('p') // 集合
-
获取父节点 获取子节点
// 获取父节点 var div1 = document.getElementById('div1') // 元素 var parent = div1.parentElement // 获取子节点 var div1 = document.getElementById('div1') // 元素 var parent = div1.childNodes
-
新增节点,删除节点
// 新增节点 var a = document.createElement('a'); a.innerHTML = '我是a标签'; document.body.appendChild(a) // 删除节点 var div1 = document.getElementById('div1') // 元素 var child = div1.childNodes div1.removeChild(child[0])
38. DOM 节点的 attr 和 property 有何区别
- property 只是一个 JS 属性的修改
- attr 是对 html 标签属性的修改
39. 如何检测浏览器的类型
navigator.userAgent
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36"
if (navigator.userAgent.indexof('Chrome')) {
}
40. 拆解url的各部分
```
location.protocol //协议 "https:"
location.host // 域名 "coding.imooc.com"
location.pathname // 路径 "/lesson/115.html"
location.search // 参数 "?user=lxl"
location.hash //哈希 "#mid=5390"
location.href // 完整url "https://coding.imooc.com/lesson/115.html#mid=5390"
```
41. 编写一个通用的事件监听函数
```
function bindEvent(elem, type, selector, fn) {
if (fn == null) {
fn = selector
selector = null
}
elem.addEventListener(type, function(e) {
var target
if (selector) {
// 代理
target = e.target
if (target.matches(selector)) {
fn.call(target, e)
}
} else {
// 不是代理
fn(e)
}
});
}
```
42. 描述DOM事件冒泡流程
// 从内到外
e.stopPropagation() 阻止冒泡
43. 对于一个无线下拉加载图片的页面,如何给每个图片绑定事件
我们设定一种场景,如下代码,一个<div>
中包含了若干个<a>
,而且还能继续增加。那如何快捷方便的为所有的<a>
绑定事件呢?
<div id="div1">
<a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >a1</a>
<a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >a2</a>
<a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >a3</a>
<a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >a4</a>
</div>
<button>点击增加一个 a 标签</button>
这里就会用到事件代理,我们要监听<a>
的事件,但要把具体的事件绑定到<div>
上,然后看事件的触发点,是不是<a>
var div1 = document.getElementById('div1')
div1.addEventListener('click', function (e) {
var target = e.target
if (e.nodeName === 'A') {
alert(target.innerHTML)
}
})
那我们现在完善一下之前写过的通用事件绑定函数,加上事件代理
function bindEvent(elem, type, selector, fn) {
if (fn == null) {
fn = selector
selector = null
}
elem.addEventListener(type, function (e) {
var target
if (selector) {
target = e.target
if (target.matches(selector)) {
fn.call(target, e)
}
} else {
fn(e)
}
})
}
然后这样使用
// 使用代理
var div1 = document.getElementById('div1')
bindEvent(div1, 'click', 'a', function (e) {
console.log(this.innerHTML)
})
// 不适用代理
var a = document.getElementById('a1')
bindEvent(div1, 'click', function (e) {
console.log(a.innerHTML)
})
最后,使用代理的优点
- 使代码简洁
- 减少浏览器的内存占用
44. 手动编写一个 ajax,不依赖第三方库
var xhr = new XMLHttpRequest();
xhr.open('GET', '/api', false)
xhr.onreadystatechange(function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
alert('sas');
}
}
});
xhr.send(null)
45. 跨域的几种实现方式
- jsonp实现原理 https://blog.csdn.net/hansexploration/article/details/80314948
- 服务器端设置 http header
46. 请描述一下 cookie,sessionStorage 和 localStorage 的区别?
-
容量
存储大小:
cookie数据大小不能超过4k。
sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
有期时间:
localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
sessionStorage 数据在当前浏览器窗口关闭后自动删除。
cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭-
是否会携带到 ajax 中
cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。
cookie数据始终在同源的http请求中携带(即使不需要),记会在浏览器和服务器间来回传递。
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。 -
API易用性
cookie 前端通过 ‘‘document.cookie’获取,是个很长的字符串,需要封装方法提取
// 取某个cookie种的数据 function getCookie (name) { var str = document.cookie; var arrStr=str.split("; ") //遍历数组 for (var i = 0; i < arrStr.length; i++) { console.log(arrStr[i]); var arr=arrStr[i].split("=") console.log(arr); if(arr[0]==name){ return arr[1] } } } // 存某个cookie数据 function setCookie (name,val,time) { //存的名称name,存的值val,存的天数time(过期时间) var oDate = new Date(); oDate.setDate(oDate.getDate()+time); document.cookie=name+"="+val+";expires="+oDate;//过期时间 } // 删除指定的数据,如何让cookie失效(过期) function removeCookie(name){ setCookie(name,"",-1); }
47. 从输入url到得到html的详细过程
- 浏览器根据 DNS 服务器得到域名的 IP 地址
- 向这个 IP 的机器发送 http 请求
- 服务器收到、处理并返回 http 请求
- 浏览器得到返回内容
48. window.onload 和 DOMContentLoaded 的区别
* window.onload 是页面的全部资源加载完才会执行,包括图片,视频等
* DOM渲染完即可执行,此时图片,视频还没加载完
49. 性能优化
-
优化原则和方向
原则
多使用内存、缓存或者其他方法
减少 CPU 计算、较少网络方向
加载页面和静态资源
页面渲染
加载资源优化
静态资源的压缩合并(JS代码压缩合并、CSS代码压缩合并、雪碧图)
静态资源缓存(资源名称加 MD5 戳)
使用 CND 让资源加载更快
使用 SSR 后端渲染,数据直接突出到 HTML 中渲染优化
CSS 放前面 JS 放后面
懒加载(图片懒加载、下拉加载更多)
减少DOM 查询,对 DOM 查询做缓存
减少DOM 操作,多个操作尽量合并在一起执行(DocumentFragment)
事件节流
尽早执行操作(DOMContentLoaded-
详细解说
静态资源的压缩合并
如果不合并,每个都会走一遍之前介绍的请求过程<script src="a.js"></script> <script src="b.js"></script> <script src="c.js"></script>
如果压缩了,就只走一遍请求过程
<script src="abc.js"></script>
静态资源缓存
通过连接名称控制缓存<script src="abc_1.js"></script>
只有内容改变的时候,链接名称才会改变
<script src="abc_2.js"></script>
使用 CND 让资源加载更快
<script src="https://cdn.bootcss.com/zepto/1.0rc1/zepto.min.js"></script>
使用 SSR 后端渲染
如果提到 Vue 和 React 时,可以说一下CSS 放前面 JS 放后面
将浏览器渲染的时候,已经提高懒加载
一开始先给为 src 赋值成一个通用的预览图,下拉时候再动态赋值成正式的图片<img src="preview.png" data-realsrc="abc.png"/>
DOM 查询做缓存
两端代码做一下对比var pList = document.getElementsByTagName('p') var i for (i = 0; i < pList.length; i++) { } var i for (i = 0; i < document.getElementsByTagName('p').length; i++) { }
总结:DOM 操作,无论查询还是修改,都是非常耗费性能的,尽量减少
合并 DOM 插入
DOM 操作是非常耗费性能的,因此插入多个标签时,先插入 Fragment 然后再统一插入DOMvar listNode = document.getElementById('list') // 要插入 10 个 li 标签 var frag = document.createDocumentFragment(); var x, li; for(x = 0; x < 10; x++) { li = document.createElement("li"); li.innerHTML = "List item " + x; frag.appendChild(li); } listNode.appendChild(frag);
事件节流
例如要在文字改变时触发一个 change 事件,通过 keyup 来监听。使用节流。var textarea = document.getElementById('text') var timeoutId textarea.addEventListener('keyup', function () { if (timeoutId) { clearTimeout(timeoutId) } timeoutId = setTimeout(function () { // 触发 change 事件 }, 100) })
尽早执行操作
window.addEventListener('load', function () { // 页面的全部资源加载完才会执行,包括图片、视频等 }) document.addEventListener('DOMContentLoaded', function () { // DOM 渲染完即可执行,此时图片、视频还可能没有加载完 }) ```
50. 常见的 web 攻击方式有哪些,简述原理?如何预防?
-
SQL注入
上学的时候就知道有一个“SQL注入”的攻击方式。例如做一个系统的登录界面,输入用户名和密码,提交之后,后端直接拿到数据就拼接 SQL 语句去查询数据库。如果在输入时进行了恶意的 SQL 拼装,那么最后生成的 SQL 就会有问题。但是现在稍微大型的一点系统,都不会这么做,从提交登录信息到最后拿到授权,都经过层层的验证。因此,SQL 注入都只出现在比较低端小型的系统上。
-
XSS攻击
前端最常见的攻击就是 XSS(Cross Site Scripting,跨站脚本攻击),很多大型网站(例如 FaceBook 都被 XSS 攻击过)。举一个例子,我在一个博客网站正常发表一篇文章,输入汉字、英文和图片,完全没有问题。但是如果我写的是恶意的 js 脚本,例如获取到document.cookie然后传输到自己的服务器上,那我这篇博客的每一次浏览,都会执行这个脚本,都会把自己的 cookie 中的信息偷偷传递到我的服务器上来。
预防 XSS 攻击就得对输入的内容进行过滤,过滤掉一切可以执行的脚本和脚本链接。大家可以参考xss.js这个开源工具。
简单总结一下,XSS 其实就是攻击者事先在一个页面埋下攻击代码,让登录用户去访问这个页面,然后偷偷执行代码,拿到当前用户的信息。
-
CSRF/XSRF
还有一个比较常见的攻击就是 CSRF/XSRF(Cross-site request forgery,跨站请求伪造)。它是借用了当前操作者的权限来偷偷的完成某个操作,而不是拿到用户的信息。例如,一个购物网站,购物付费的接口是http://buy.com/pay?id=100,而这个接口在使用时没有任何密码或者 token 的验证,只要打开访问就付费购买了。一个用户已经登录了http://buy.com在选择商品时,突然收到一封邮件,而这封邮件正文有这么一行代码<img src="http://buy.com/pay?id=100"/>,他访问了邮件之后,其实就已经完成了购买。
预防 CSRF 就是加入各个层级的权限验证,例如现在的购物网站,只要涉及到现金交易,肯定输入密码或者指纹才行。
51. 什么是单线程
- 单线程就是同时只做一件事,两段代码不能同时执行
- 原因就是为了避免DOM渲染的冲突
- 异步就是单线程‘‘无奈’’的解决方案,虽然有很多问题
52. 什么是event-loop
* 时间轮询,js异步的解决方案
* 什么是异步队列,何时被放入异步队列
53. 是否用过jquery的Deferred
jQuery 1.5之前ajax只能用success回调;1.5之后就有了.doen(), .fail(), .then() 类似promise的用法
function waitHandle() {
// 定义
var dtd = $.Deferred();
var wait = function (dtd) {
var task = function () {
console.log('执行完成')
// 成功
dtd.resolve()
// 失败
dtd.reject()
}
setTimeout(task, 2000)
// wait 返回
return dtd
}
// 最终返回
return wait(dtd)
}
var w = waitHandle()
w.then(function() {
console.log('ok 1')
}, function() {
console.log('error 1')
}).then(function() {
console.log('ok 2')
}, function() {
console.log('error 2')
})
// // 开放封闭原则
54. 当前异步解决方案
* jquery的Deferred
* Promise
* async 和 await
55. vdom是什么?为何会存在vdom?
* virtual dom ,虚拟dom
* 用js模拟DOM结构
* DOM操作非常“昂贵”
* 将DOM对比操作放在js层,提高效率
56. vdom的如何应用,核心API是什么
57. 介绍一下diff算法
58. mixin和mixins区别
mixin用于全局混入,会影响到每个组件实例,通常插件都是这样做初始化的。
Vue.mixin({
beforeCreate(){
// 会影响到每个组件的beforeCreate钩子函数
}
})
mixins最常用的扩展组件的方式。如果多个组件有相同的业务逻辑,就可将这些逻辑剥离出来,通过mixins混入代码。需要注意:mixins混入的钩子函数会先于组件内的钩子函数执行,并且在遇到同名选项的时候也会有选择性的进行合并。
59. 说一下使用jQuery和使用框架的区别
* 数据和视图分离,解耦
* 数据驱动视图,只关心数据变化,DOM操作被封装
60. 弹性盒子的属性,主轴和交叉轴
https://www.jianshu.com/p/ce5d23ec13aa
61. 上下左右对齐方式
补充:
在弹性盒对象的 <div> 元素中的各项周围留有空白:
div
{
display: flex;
justify-content: space-around;
}
值 | 描述 |
---|---|
flex-start | 默认值。项目位于容器的开头。 |
flex-end | 项目位于容器的结尾。 |
center | 项目位于容器的中心。 |
space-between | 项目位于各行之间留有空白的容器内。 |
space-around | 项目位于各行之前、之间、之后都留有空白的容器内。 |
initial | 设置该属性为它的默认值。请参阅 initial。 |
inherit | 从父元素继承该属性。请参阅 inherit。 |
- flex 方法上下左右居中 子元素无宽高
<div><span>内容所在区域</span></div> <style type="text/css"> *{ margin: 0 ; padding: 0; } span{ border: 1px solid #333; } div{ display: flex; justify-content:center;/*x轴对齐方式*/ align-items:center; /*y轴对滴方式*/ height: 100vh; /**屏幕高度百分百*/ } </style>
62. 同步和异步的区别是什么?分别举一个同步和异步的例子
同步会阻塞代码执行,而异步不会。alert
是同步,setTimeout
是异步
63. 一个关于setTimeout
的笔试题
面试题中,setTimeout
的基本是必会出现的
// 以下代码执行后,打印出来的结果是什么
console.log(1)
setTimeout(function () {
console.log(2)
}, 0)
console.log(3)
setTimeout(function () {
console.log(4)
}, 1000)
console.log(5)
该题目的答案是1 3 5 2 4
,不知道跟你答对了没有。具体的原理,我们后面再详细讲解。
64. 前端使用异步的场景有哪些
- setTimeout setInterval
- 网络请求
- 事件绑定(可以说一下自己的理解)
65. SVG 与 HTML5 的 canvas 优缺点
SVG与Canvas区别
- SVG适用于描述XML中的2D图形的语言
- Canvas随时随地绘制2D图形(使用JavaScript)
- SVG是基于XML的,这意味着每个元素在SVG DOM中都可用。你可以为每个元素添加JavaScript事件处理程序
- 在SVG中,每个绘制的形状都会被记忆为一个对象。如果SVG对象的属性发生变化,浏览器可以自动重新渲染形状。
- Canvas是一像素一像素地渲染。在画布中,一旦图形绘制好了,就会被浏览器遗忘。如果你想改变某一个的位置,整个场景都需要重新绘制,包括可能已经被图形覆盖的任何对象。
Canvas | SVG |
---|---|
与分辨率相关(可以理解为位图,图形放大会失真,看到像素点) | 与分辨率无关(可以理解为矢量图,图形放大不会失真) |
不支持事件处理程序 | 支持事件处理程序 |
文字呈现功能比较简单 | 适合具有大型渲染区域的应用程序(如谷歌地图) |
可以讲生成的图像保存为png或者jpg | 如果复杂的话渲染速度慢(任何使用DOM的东西都会很慢) |
非常适合图形密集性游戏 | 不适合游戏应用程序 |
66. HTML5的新特性
https://www.jianshu.com/p/37c0b1eb4145
67. ```
var b = 0
(function b(){
b=2;
console.log(b)
}
)()
VM518:1 ƒ b(){b=2;console.log(b)}
```
68. 作用域链
当代码在一个环境中执行时,会创建变量对象的一个作用域链(作用域形成的链条)
- 作用域链的前端,始终都是当前执行的代码所在环境的变量对象
- 作用域链中的下一个对象来自于外部环境,而在下一个变量对象则来自下一个外部环境,一直到全局执行环境
- 全局执行环境的变量对象始终都是作用域链上的最后一个对象
69. W3C标准
万维网联盟(外语缩写:W3C)标准不是某一个标准,而是一系列标准的集合。网页主要由三部分组成:结构(Structure)、表现(Presentation)和行为(Behavior)。
70. 协商缓存和强缓存
https://www.jianshu.com/p/9c95db596df5
https://blog.csdn.net/weixin_34306446/article/details/91389238
71. 手写一个防抖函数
function debounce(fn,delay){
var timer = null
// 清除上一次延时器
return function(){
clearTimeout(timer)
// 重新设置一个新的延时器
timer = setTimeout(() => {
fn.call(this)
}, delay);
}
}
72. 节流的函数
/*
节流函数:fn:要被节流的函数,delay:规定的时间
*/
function throttle(fn,delay){
// 记录上一次函数出发的时间
var lastTime = 0
return function(){
// 记录当前函数触发的时间
var nowTime = new Date().getTime()
// 当当前时间减去上一次执行时间大于这个指定间隔时间才让他触发这个函数
if(nowTime - lastTime > delay){
// 绑定this指向
fn.call(this)
//同步时间
lastTime = nowTime
}
}
}
73. 数组去重(要说出空间复杂度)
// 数组去重
function func(arr) {
var newArr = [], len = arr.length;
for (var i = 0; i < len; i++) {
if (newArr.indexOf(arr[i]) === -1) {
newArr.push(arr[i]);
}
}
return newArr;
}
var arr = [1,2,3,1,1,4,6,7]
console.log(arr);
console.log(func(arr));
73. 一个数组[1,2,3,4,5,6,7,9],处理一下,奇数放左,偶数放右边(用for循环,说出优化空间)
74. 写一个反转链表
---这个。。。