前端面试题

文章目录

理论题

前端页面有哪三层构成,分别是什么?作用是什么?
1. 结构层:由 HTML 或 XHTML 之类的标记语言负责创建,仅负责语义的表达。解决了页面“内容是什么”的问题。
2. 表示层:由CSS负责创建,解决了页面“如何显示内容”的问题。
3. 行为层:由脚本负责。解决了页面上“内容应该如何对事件作出反应”的问题。
JavaScript 的组成
JavaScript 由以下三部分组成:
ECMAScript(核心):JavaScript 语言基础
DOM(文档对象模型):规定了访问 HTML 和 XML 的接口
BOM(浏览器对象模型):提供了浏览器窗口之间进行交互的对象和方法
对BFC规范的理解
BFC全称是Block Formatting Context,即块格式化上下文。它是CSS2.1规范定义的,关于CSS渲染定位的一个概念。
BFC是页面CSS 视觉渲染的一部分,用于决定块盒子的布局及浮动相互影响范围的一个区域。
BFC的一个最重要的效果是,让处于BFC内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。
利用BFC可以闭合浮动,防止与浮动元素重叠。
线程与进程的区别
1.一个程序至少有一个进程,一个进程至少有一个线程
2. 线程的划分尺度小于进程,使得多线程程序的并发性高
3. 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
4. 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
5. 多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配
什么叫优雅降级和渐进增强?
渐进增强 progressive enhancement:
针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级 graceful degradation:
一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
区别:
1.优雅降级是从复杂的现状开始,并试图减少用户体验的供给
2.渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要
3.降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带
请解释一下 JavaScript 的同源策略
同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议。
指一段脚本只能读取来自同一来源的窗口和文档的属性。
一个页面上有大量的图片(大型电商网站),加载很慢,你有哪些方法优化这些图片的加载,给用户更好的体验。
1. 图片懒加载,滚动到相应位置才加载图片。
2. 图片预加载,如果为幻灯片、相册等,将当前展示图片的前一张和后一张优先下载。
3. 使用CSSsprite,SVGsprite,Iconfont、Base64等技术,如果图片为css图片的话。
4. 如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提高用户体验。
闭包是什么,有什么特性,对页面有什么影响?
闭包就是能够读取其他函数内部变量的函数。
闭包的实质是一个函数,是一个用于返回局部变量值的函数,因为在全局中,受JavaScript链式作用域结构的影响,父级变量中无法访问到子级的变量值,为了解决这个问题,才使用闭包这个概念。
它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
由于闭包时,变量的值都保存到内存中,会导致页面加载时内存消耗很大,IE会导致内在泄露,因此尽量少用或用时要及时删除变量。
网站重构的理解
重构:在不改变外部行为的前提下,简化结构、添加可读性,而在网站前端保持一致的行为。
1. 使网站前端兼容于现代浏览器(针对于不合规范的CSS、如对IE6有效的)
2. 对于移动平台的优化,针对于SEO进行优化
3. 减少代码间的耦合,让代码保持弹性
4. 压缩或合并JS、CSS、image等前端资源
检测浏览器版本版本有哪些方式
根据 navigator.userAgent // UA.toLowerCase().indexOf(‘chrome’)
根据 window 对象的成员 // ‘ActiveXObject’ in window
区分什么是“客户区坐标”、“页面坐标”、“屏幕坐标”?
elem.offsetLeft:返回元素相对于其定位父级左侧的距离
elem.offsetTop:返回元素相对于其定位父级顶部的距离
elem.getBoundingClientRect():返回一个 DOMRect 对象,包含一组描述边框的只读属性,单位像素
描述浏览器的渲染过程,DOM 树和渲染树的区别
浏览器的渲染过程:

解析 HTML 构建 DOM(DOM 树),并行请求 css/image/js
CSS 文件下载完成,开始构建 CSSOM(CSS 树)
CSSOM 构建结束后,和 DOM 一起生成 Render Tree(渲染树)
布局(Layout):计算出每个节点在屏幕中的位置
显示(Painting):通过显卡把页面画到屏幕上
DOM 树 和 渲染树 的区别:

DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素
渲染树不包括 head 和隐藏元素,大段文本的每一个行都是独立节点,每一个节点都有对应的 css 属性
如何进一步检测引用数据类型
instanceof
constructor 构造函数
hasOwnporperty
isArray 判断是否为数组、 isNaN() 判断是否是NaN
Object.prototype.toString.call(x)(最好的)
documen.write和 innerHTML 的区别?
document.write 指定位置输出
dom.innerHTML 可以重绘指定元素的内容
在JavaScript中使用innerHTML的缺点是什么?
如果在JavaScript中使用innerHTML,缺点是:内容随处可见;不能像“追加到innerHTML”一样使用;即使你使用+ = like“innerHTML = innerHTML +'html'”旧的内容仍然会被html替换;整个innerHTML内容被重新解析并构建成元素,因此它的速度要慢得多;innerHTML不提供验证,因此我们可能会在文档中插入有效的和破坏性的HTML并将其中断。
把 Script 标签 放在页面的最底部的body封闭之前 和封闭之后有什么区别?浏览器会如何解析它们?
如果说放在body的封闭之前,将会阻塞其他资源的加载
如果放在body封闭之后,不会影响body内元素的加载
DOM操作——怎样添加、移除、移动、复制、创建和查找节点。
1.创建新节点
createDocumentFragment() // 创建一个DOM片段
createElement() // 创建一个具体的元素
createTextNode() // 创建一个文本节点
2.添加、移除、替换、插入
appendChild()
removeChild()
replaceChild()
insertBefore() // 在已有的子节点前插入一个新的子节点
3.查找
getElementsByTagName() // 通过标签名称
getElementsByName() // 通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
getElementById() // 通过元素Id,唯一性
split() join() 的区别
前者是将字符串切割成数组的形式,后者是将数组转换成字符串
数组方法pop() push() unshift() shift()
栈方法:
push()尾部添加,返回 数组长度
pop()尾部删除,返回 被删除的元素

队列方法:
unshift()头部添加 ,返回 数组长度
shift()头部删除,返回被删除的元素
JavaScript有几种类型的值?
栈:原始数据类型(Undefined,Null,Boolean,Number,String)
堆:引用数据类型(对象、数组和函数)
 
两种类型的区别是:存储位置不同。
原始数据类型是直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,
所以放入栈中存储;
引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其
在栈中的地址,
取得地址后从堆中获得实体。
Javascript如何实现继承?
1、原型链
2、借用构造函数
3、组合继承(原型链+借用构造函数)
4、原型式继承
5、寄生式继承
6、寄生组合式继承
javascript创建对象的几种方式?
//1.对象字面量的方式
var person={
  firstname:"Mark",
  lastname:"Yun",
  age:25,
  eyecolor:"black"
};

//2.用function来模拟无参的构造函数
function Person(){}
//定义一个function,如果使用new"实例化",该function可以看作是一个Class
var person=new Person();
person.name="Mark";
person.age="25";
person.work=function(){
    alert(person.name+" hello...");
}
person.work();

//3.用function来模拟有参构造函数来实现(用this关键字定义构造的上下文属性)
function Pet(name,age,hobby){
   this.name=name;//this作用域:当前对象
   this.age=age;
   this.hobby=hobby;
   this.eat=function(){
      alert("我叫"+this.name+",我喜欢"+this.hobby+",是个程序员");
   }
}
var maidou = new Pet("麦兜",25,"coding");//实例化、创建对象
maidou.eat();//调用eat方法

//4.使用Object.create()方法
var Animal = {
    type: "Invertebrates", //"无脊椎动物"
    displayType: function() {
        console.log(this.type);
    }
}
var animal1 = Object.create(Animal);
animal1.displayType(); // Invertebrates
 
var fish = Object.create(Animal);
fish.type = "Fishes";
fish.displayType(); // Fishes

//5.用工厂方式来创建(内置对象)
var wcDog = new Object();
wcDog.name="旺财";
wcDog.age=3;
wcDog.work=function(){
   alert("我是"+wcDog.name+",汪汪汪......");
}
wcDog.work();

//6.用原型方式来创建
function Dog(){
 
}
Dog.prototype.name="旺财";
Dog.prototype.eat=function(){
    alert(this.name+"是个吃货");
}
var wangcai =new Dog();
wangcai.eat();

//7.用混合方式来创建(数据类型属性定义在构造函数中,函数类型属性定义在原型上)
function Car(name,price){
    this.name=name;
    this.price=price;
}
Car.prototype.sell=function(){
   alert("我是"+this.name+",我现在卖"+this.price+"万元");
}
var camry =new Car("凯美瑞",27);
camry.sell();
Javascript作用域链?
外层函数无法查看内层函数的内部细节,但内层函数可以查看其外层函数细节,直至全局环境中的细节。
当需要从内层函数查找某一属性或方法时,会现在当前作用域查找,如果没有找到,就会到它的上一层作用域
查找,直至全局环境,这种组织形式就是作用域链。
谈谈This对象的理解。
全局环境中的this,指的是 window
构造函数中的this,指的是实例对象
对象方法中的this,指的是调用这个方法的对象
事件触发中的this,指的是触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window
说明this几种不同的使用场景
1、作为构造函数执行
2、作为对象属性执行
3、作为普通函数执行
4、call、apply、bind
什么是window对象? 什么是document对象?
window对象是指浏览器打开的窗口。
document对象是对HTML文档对象的一个只读引用,window对象的一个属性。
new操作符具体干了什么呢?
1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2、属性和方法被加入到 this 引用的对象中。
3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。
 
var obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
DOM操作——怎样添加、移除、移动、复制、创建和查找节点?
    (1)创建新节点
      createDocumentFragment()    //创建一个DOM片段
      createElement()   //创建一个具体的元素
      createTextNode()   //创建一个文本节点
    (2)添加、移除、替换、插入
      appendChild()
      removeChild()
      replaceChild()
      insertBefore() //在已有的子节点前插入一个新的子节点
    (3)查找
      getElementsByTagName()    //通过标签名称
      getElementsByName()    //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
      getElementById()    //通过元素Id,唯一性
.call() 和 .apply() 的区别?
apply()只有两个参数,第一个参数是调用当前函数的对象,第二个参数是一个数组,里面的值是传入当前调用
的函数的参数。
.cal()可以有多个参数,第一个参数还是调用当前函数的对象,而要传入当前调用的函数的参数是直接用
第2、3、4...个参数传入的。
数组和对象有哪些原生方法
Object: create, toString,valueOf,hasOwnProperty
Array: isArray, splice,forEach,find,concat,pop,push,reverse,shift,slice
你有用过哪些前端性能优化的方法
1.减少http请求次数:CSS Sprites, JS、CSS源码压缩、图片大小控制合适;网页Gzip,CDN托管,data缓存 ,图片服务器。
2.前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数
3.用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。
4.当需要设置的样式很多时设置className而不是直接操作style。
5.少用全局变量、缓存DOM节点查找的结果。减少IO读取操作。
6.避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。
7.图片预加载,将样式表放在顶部,将脚本放在底部  加上时间戳。
8.避免在页面的主体布局中使用table,table要等其中的内容完全下载之后才会显示出来,显示比div+css布局慢。
  对普通的网站有一个统一的思路,就是尽量向前端优化、减少数据库操作、减少磁盘IO。向前端优化指的是,在不影响功能和体验的情况下,能在浏览器执行的不要在服务端执行,能在缓存服务器上直接返回的不要到应用服务器,程序能直接取得的结果不要到外部取得,本机内能取得的数据不要到远程取,内存能取到的不要到磁盘取,缓存中有的不要去数据库查询。减少数据库操作指减少更新次数、缓存结果减少查询次数、将数据库执行的操作尽可能的让你的程序完成(例如join查询),减少磁盘IO指尽量不使用文件系统作为缓存、减少读写文件次数等。程序优化永远要优化慢的部分,换语言是无法“优化”的。
一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?(流程说的越详细越好)
1、浏览器会开启一个线程来处理这个请求,对 URL 分析判断如果是 http 协议就按照 Web 方式来处理;
2、调用浏览器内核中的对应方法,比如 WebView 中的 loadUrl 方法;
3、通过DNS解析获取网址的IP地址,设置 UA 等信息发出第二个GET请求;
4、进行HTTP协议会话,客户端发送报头(请求报头);
5、进入到web服务器上的 Web Server,如 Apache、Tomcat、Node.JS 等服务器;
6、进入部署好的后端应用,如 PHP、Java、JavaScript、Python 等,找到对应的请求处理;
7、处理结束回馈报头,此处如果浏览器访问过,缓存上有对应资源,会与服务器最后修改时间对比,一致则返回304;
8、浏览器开始下载html文档(响应报头,状态码200),同时使用缓存;
9、文档树建立,根据标记请求所需指定MIME类型的文件(比如css、js),同时设置了cookie;
10、页面开始渲染DOM,JS根据DOM API操作DOM,执行事件绑定等,页面显示完成。
什么是事件,什么是事件委托,事件冒泡,事件捕获,如何阻止事件的冒泡?
用户事件:通常在view中处理,程序允许用户通过触发和处理事件的形式沟通,比如单击一个按钮,滚动
屏幕,提交一个表单。
程序事件:应用自身也可以触发和处理一些事件,比如渲染后触发onRender事件等
事件冒泡会从当前触发的事件目标一级一级往上传递,依次触发,直到document为止。
事件捕获会从document开始触发,一级一级往下传递,依次触发,直到真正事件目标为止。
事件委托:即使一个事件本来是要绑定到某个元素上,然而却绑定到了该元素的父(或祖先)元素上,利用
事件冒泡原理,触发执行效果
ES5严格模式
语法: "use strict"; //是一个指令,指示解释器用更严格的方式检查代码 
调用: 针对整个脚本文件:放在脚本文件的第一行 针对单个函数:放在函数体的第一行
脚本文件变通写法:将整个脚本文件放在一个立即执行的匿名函数中
1.变量在赋值前必须声明
2.局部this不会去指向window,赋值什么就指向什么
3.拒绝重复属性和参数
4.不支持with
== 和 === 的不同
前者会自动转换类型,后者不会
前者会判断值,后者会判断值和地址
前端开发有哪些优化问题,从SEO的角度谈
减少请求数量 
减小资源大小 
优化网络连接 
优化资源加载 
减少重绘回流 
性能更好的API 
webpack优化
javascript的本地对象,内置对象和宿主对象分别是什么?
本地对象为Object、Array、Boolean、Number、String、Function、RegExp、Date、Error等可以new实例化
内置对象为Gload Math 等不可以实例化的
宿主为浏览器自带的document,window,BOM,DOM 等宿主对象
Object 是 JavaScript 中所有对象的父对象
JavaScript原型,原型链 ? 有什么特点?
每个对象都会在其内部初始化一个原型属性,这个原型指向的是一个对象,这个对象同样有一个原型属性,这样
一层一层向上,直到Object对象。当我们访问一个对象的属性时,如果当前对象内部不存在这个属性,那么就会
去它的原型上去找这个属性,它的原型又会有自己的原型属性,这样沿着找下去,就是我们平时所说的原型链的
概念。

关系:instance.constructor.prototype = instance.__proto__

特点:
JavaScript对象是通过引用来传递的,我们创建的每个实例对象中并没有一份属于自己的原型副本。
所以当我们修改原型时,与之相关的对象也会继承这一改变。
如何将arguments转为数组?
Object.prototype.slice.call(arguments);

编程题

实现已知或未知宽度的垂直水平居中的方法(5种)
//1.position
 .wrapper {
     position: relative;
 }
 
 .box {
     width: 100px;
     height: 100px;
     position: absolute;
     top: 50%;
     left: 50%;
     margin-top: -50px;
     margin-left: -50px;
 }
 //2.translate
 .box {
    width: 100px;
    height: 100px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
 //3.calc()
.box {
    width: 100px;
    height: 100px;
    position: absolute;
    top: calc(50% - 50px);
    left: calc(50% - 50px);
}
//4.table  不知宽高
.wrapper {
    display: table;
    width: 400px;
    height: 400px;
    border: 1px solid;
}

.box {
    display: table-cell;
    text-align: center;
    vertical-align: middle;
}
//5.flex  不知宽高
.wrapper {
    width: 400px;
    height: 400px;
    border: 1px solid;
    display: flex;
    justify-content: center;
    align-items: center;
}
使用css完成一个两列定宽布局
 <style>
     .left {
         width: 200px;
         height: 300px;
         background-color: #f00;
         float: left;
     }
     
     .right {
         /*减号前后必须有空格*/
         width: calc(100% - 200px);
         height: 300px;
         background-color: #0f0;
         float: left;
     }
 </style>
 <body>
    <div class="left"></div>
    <div class="right"></div>
</body>
兼容浏览器的获取指定元素(elem)的样式属性(name)的方法
function getStyle(elem, name){
	if(window.getComputedStyle){
		return  window.getComputedStyle(elem)[name];
	}else{
		return  elem.currentStyle[name];
	}
}
用js创建10个 a 标签,点击的时候弹出来对应的序号
var i;
for(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);
}
字符串反转,如将 ‘12345678’ 变成 ‘87654321’
var str = '12345678';
str = str.split('').reverse().join('');
判断一个字符串中出现次数最多的字符,统计这个次数
var json = {};
for (var i = 0; i < str.length; i++) {
        if(!json[str.charAt(i)]){
                json[str.charAt(i)] = 1;// json[str[i]] = 1;
        }else{
                json[str.charAt(i)]++;
        }
};
var iMax = 0;
var iIndex = '';
for(var i in json){
        if(json[i]>iMax){
                iMax = json[i];
                iIndex = i;
        }
}
写一个能遍历对象和数组的通用的forEach函数
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]);
        }
    }
}
var arr = [1,2,3];//数组
forEach(arr,function(index,item){
    console.log(index,item);
})
var obj = {x:1,y:2};//对象
forEach(obj,function(key,val){
    console.log(key,val);
})
编写一个数组去重的方法
function unique(arr){
    var result=[];
    for (var i = 0, len = arr.length; i < len; i++) {
        var arri = arr[i];
        if(result.indexOf(arri)<0){
            result.push(arri);
        }
    }
    return result;
}
JavaScript字符串去重的四种方法
//方法一:for遍历
function quchong1(str){
	var newStr="";
	var flag;
	for(var i=0;i<str.length;i++){
		flag=1;
		for(var j=0;j<newStr.length;j++){
			if(str[i]==newStr[j]){
				flag=0;
				break;
			}
		}
		if(flag)  newStr+=str[i];
	}
	return newStr; 
}
//方法二:indexOf(无兼容问题)
function quchong2(str){
	var newStr="";
	for(var i=0;i<str.length;i++){
		if(newStr.indexOf(str[i])==-1){
			newStr+=str[i];
		}
	}
	return newStr;
}
//方法三:search()方法
function quchong3(str){
	var newStr="";
	for(var i=0;i<str.length;i++){
		if(newStr.search(str[i])==-1)	
		newStr+=str[i];	
		
	}
	return newStr;
}
//方法四:对象属性
function quchong4(str){
	var obj={};
	var newStr="";
	for(var i=0;i<str.length;i++){
		if(!obj[str[i]]){
			newStr+=str[i];
			obj[str[i]]=1;
		}
	}
	return newStr;
}
有这样一个URL:http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e,请写一段JS程序提取URL中的各个GET参数(参数名和参数个数不确定),将其按key-value形式返回到一个json结构中,如{a:’1′, b:’2′, c:”, d:’xxx’, e:undefined}。
function serlize(url){
    var result={};
    //1、寻找?后面的字符串
    url=url.substr(url.indexOf("?")+1);
    //2、将字符串用&分隔
    var args=url.split("&");//[“a=1”,”b=2”]
    for (var i = 0, len = args.length; i < len; i++) {
        var arg = args[i];
    var item = arg.split('=');
        //3、对象的键=值
        result[item[0]]= item[1];
    }
    return result;
}
请编写一个JavaScript函数 parseQueryString,它的用途是把URL参数解析为一个对象,请使用BOM获取当前页面的参数
function parseSearch(){
	var search = location.search;
	var obj = {};
	if(search !=""){
		var splits = 
search.slice(1).split("&");//["username=laila","password=123456"]
		console.log(splits);
		for(var i = 0 ;i<splits.length;i++){
			var arr = splits[i].split("=");
			obj[arr[0]] = arr[1];
		}
	}
	console.log(obj)
}
parseSearch();

深度克隆
  function clone(obj) {
            let result = obj instanceof Array ? [] : {}
            for (let key in obj) {
                if (obj[key] instanceof Array) {
                    result[key] = clone(obj[key]);
                } else if (obj[key] instanceof Object) {
                    result[key] = clone(obj[key]);
                } else {
                    result[key] = obj[key];
                }
            }
            return result;
        }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值