前端开发面试题 — javascript篇

js

1.介绍js的基本数据类型。

(1)最基本型:Boolean、Number、String
(2)引用类型:object、Array、function
(3)特殊类型:Undefined、Null
(4)ES6 新增:Symbol(创建后独一无二且不可变的数据类型 )

延升:如何判断数据类型?

typeof 运算符
instanceof 运算符
Object.prototype.toString 方法

typeof 123          // "number"
typeof '123'        // "string"
typeof false        // "boolean"
typeof [1,2,3,4]    // "object"
typeof {name:'john', age:34}    // "object"
typeof null         // "object"
typeof undefined    // "undefined"
typeof function f() {}  // "function"

2.介绍js有哪些内置对象?

  • 数据封装类对象:Object、Array、Boolean、Number 和 String
  • 其他对象:Function、Arguments、Math、Date、RegExp、Error

3.说几条写JavaScript的基本规范?

(1)不要在同一行声明多个变量;
(2)请使用 === | !== 来比较true/false或者数值;
(3)使用对象字面量替代new Array这种形式;
(4)不要使用全局函数;
(5)Switch语句必须带有default分支;
(6)函数不应该有时候有返回值,有时候没有返回值;
(7)For循环必须使用大括号;
(8)If语句必须使用大括号;
(9)for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染。

4.JavaScript原型,原型链?有什么特点?

定义:

每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念。

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

特点:

  • JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。

  • 当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的话,
    就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象。

function Func(){}
Func.prototype.name = "Sean";
Func.prototype.getInfo = function() {
    return this.name;
}
var person = new Func();  //参考var person = Object.create(oldObject);
console.log(person.getInfo());  // "Sean" 它拥有了Func的属性和方法
console.log(Func.prototype);   // Func { name="Sean", getInfo=function()}

5.JavaScript有几种类型的值?,你能画一下他们的内存图吗?

(1)栈:原始数据类型(Undefined,Null,Boolean,Number、String)
(2)堆:引用数据类型(对象、数组和函数)

区别:存储位置不同;

  • 原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;

  • 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

内存图:

图例

6.如何实现数组的随机排序?

var arr = [1,2,3,4,5,6,7,8,9,10];

方法一:

function randSort1(arr){
    for(var i = 0,len = arr.length;i < len; i++ ){
        var rand = parseInt(Math.random()*len);
        var temp = arr[rand];
        arr[rand] = arr[i];
        arr[i] = temp;
    }
    return arr;
}

方法二:

function randSort2(arr){
    var mixedArray = [];
    while(arr.length > 0){
        var randomIndex = parseInt(Math.random()*arr.length);
        mixedArray.push(arr[randomIndex]);
        arr.splice(randomIndex, 1);
    }
    return mixedArray;
}

方法三:

arr.sort(function(){
    return Math.random() - 0.5;
})

7.Javascript如何实现继承?

  • 构造继承
  • 原型继承
  • 实例继承
  • 拷贝继承

原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式。

function Parent(){
    this.name = 'wang';
}

function Child(){
    this.age = 28;
}
Child.prototype = new Parent(); //继承了Parent,通过原型

var demo = new Child();
console.log(demo.age); // 28
console.log(demo.name); //wang

8.javascript创建对象的几种方式?

(1)对象字面量的方式

person = {
    firstname:"Mark",
    lastname:"Yun",
    age:25,
    eyecolor:"black"
};

(2)用function来模拟无参的构造函数

function Person(){}
var person = new Person();//定义一个function,如果使用new"实例化",该function可以看作是一个Class
person.name = "Mark";
person.age = "25";
person.work = function(){
    alert(person.name + " hello...");
}
person.work(); //Mark hello...

(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(); // 我叫麦兜,我喜欢coding,是个程序员

(4)用工厂方式来创建(内置对象)

var wcDog = new Object();
wcDog.name = "旺财";
wcDog.age = 3;
wcDog.work = function(){
    alert("我是"+ wcDog.name +",汪汪汪......");
}
wcDog.work(); //我是旺财,汪汪汪......

(5)用原型方式来创建

function Dog(){}
Dog.prototype.name = "旺财";
Dog.prototype.eat = function(){
    alert(this.name+"是个吃货");
}
var wangcai = new Dog();
wangcai.eat(); //旺财是个吃货

(6)用混合方式来创建

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(); //我是凯美瑞,我现在卖27万元

9.Javascript作用链域?

全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找,直至全局函数,这种组织形式就是作用域链。

10.谈谈This对象的理解。

  • this总是指向函数的直接调用者(而非间接调用者);
  • 全局环境下,this始终指向的是window对象;
<script>
    console.log(this);  //指向window对象
</script>
  • 在全局作用域下直接调用函数,this指向window;
function func(){
    console.log(this); //this指向的还是window对象
}
func();
  • 对象函数调用,哪个对象调用就指向哪个对象;
<script>
    var btnOK = document.getElementById("btnOK");
    btnOK.οnclick = function(){
        console.log(this); //this指向的是btnOK对象
    }
</script>
  • 如果有new关键字,this指向new出来的那个对象;
var Show = function(){
    this.myName = "Mr.Cao"; //这里的this指向的是obj对象
}
var obj = new Show();
  • 使用call或apply改变this的指向
var Go = function(){
    this.address = "深圳";
}
var Show = function(){
    console.log(this.address); //深圳
}
var go = new Go();
Show.call(go); //改变Show方法的this指向go对象
  • 箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
  • 在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window;

11.eval是做什么的?

它的功能是把对应的字符串解析成JS代码并运行;
应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。
由JSON字符串转换为JSON对象的时候可以用eval,var obj =eval('('+ str +')');

12.什么是window对象? 什么是document对象?

window对象是指浏览器打开的窗口。
document对象是Documentd对象(HTML 文档对象)的一个只读引用,window对象的一个属性。

13.null,undefined 的区别?

  • null 表示一个对象是“没有值”的值,也就是值为“空”;
    undefined 表示一个变量声明了没有初始化(赋值);

  • undefined不是一个有效的JSON,而null是;

  • undefined的类型(typeof)是undefined;
    null的类型(typeof)是object;

注意:在验证null时,一定要使用 === ,因为 == 无法分别 null 和 undefined

null == undefined  // true
null === undefined // false

14.写一个通用的事件侦听器函数。

markyun.Event = {
    // 页面加载完成后
    readyEvent : function(fn) {
        if (fn == null) {
            fn = document;
        }
        var oldonload = window.onload;
        if (typeof window.onload != 'function') {
            window.onload = fn;
        } else {
            window.onload = function() {
                oldonload();
                fn();
            };
        }
    },
 	// 视能力分别使用dom0||dom2||IE方式 来绑定事件
 	// 参数: 操作的元素,事件名称 ,事件处理程序
 	addEvent : function(element, type, handler) {
 		if (element.addEventListener) {
 			//事件类型、需要执行的函数、是否捕捉
 			element.addEventListener(type, handler, false);
 		} else if (element.attachEvent) {
 			element.attachEvent('on' + type, function() {
 				handler.call(element);
 			});
 		} else {
 			element['on' + type] = handler;
 		}
 	},
 	// 移除事件
 	removeEvent : function(element, type, handler) {
 		if (element.removeEventListener) {
 			element.removeEventListener(type, handler, false);
 		} else if (element.datachEvent) {
 			element.detachEvent('on' + type, handler);
 		} else {
 			element['on' + type] = null;
 		}
 	},
 	// 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
 	stopPropagation : function(ev) {
 		if (ev.stopPropagation) {
 			ev.stopPropagation();
 		} else {
 			ev.cancelBubble = true;
 		}
 	},
 	// 取消事件的默认行为
 	preventDefault : function(event) {
 		if (event.preventDefault) {
 			event.preventDefault();
 		} else {
 			event.returnValue = false;
 		}
 	},
 	// 获取事件目标
 	getTarget : function(event) {
 		return event.target || event.srcElement;
 	},
 	// 获取event对象的引用,取到事件的所有信息,确保随时能使用event;
 	getEvent : function(e) {
 		var ev = e || window.event;
 		if (!ev) {
 			var c = this.getEvent.caller;
 			while (c) {
 				ev = c.arguments[0];
 				if (ev && Event == ev.constructor) {
 					break;
 				}
 				c = c.caller;
 			}
 		}
 		return ev;
 	}
 };

15.事件是?IE与火狐的事件机制有什么区别? 如何阻止冒泡?

(1) 我们在网页中的某个操作(有的操作对应多个事件)。例如:当我们点击一个按钮就会产生一个事件。是可以被 JavaScript 侦测到的行为。
(2)事件处理机制:IE是事件冒泡、Firefox同时支持两种事件模型,也就是:捕获型事件和冒泡型事件;
(3)ev.stopPropagation();(旧ie的方法 ev.cancelBubble = true;)

16.什么是闭包(closure),为什么要用它?

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

闭包的特性:

  • 函数内再嵌套函数
  • 内部函数可以引用外层的参数和变量
  • 参数和变量不会被垃圾回收机制回收

用途:

//li节点的onclick事件都能正确的弹出当前被点击的li索引
<ul id="testUL">
    <li> index = 0</li>
    <li> index = 1</li>
    <li> index = 2</li>
    <li> index = 3</li>
</ul>
<script type="text/javascript">
    var nodes = document.getElementsByTagName("li");
    for(i = 0;i<nodes.length;i+= 1){
        nodes[i].onclick = (function(i){ //不用闭包的话,值每次都是4
            return function() {
                console.log(i); //0 1 2 3
            } 
        })(i);
    }
</script>
function say667() {
 	var num = 666;
 	var sayNumber = function() {
 		console.log(num);
 	}
 	num++;
 	return sayNumber;
}

var sayNumber = say667();
sayNumber(); //667

执行say667()后,say667()闭包内部变量会存在,而闭包内部函数的内部变量不会存在,使得Javascript的垃圾回收机制GC不会收回say667()所占用的资源;因为say667()的内部函数的执行需要依赖say667()中的变量;这就是是闭包作用。

17.javascript 代码中的"use strict;"是什么意思? 使用它区别是什么?

use strict是一种ECMAscript 5 添加的(严格)运行模式,这种模式使得 Javascript 在更严格的条件下运行,使JS编码更加规范化的模式,消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为。

  • 默认支持的糟糕特性都会被禁用,比如不能用with,也不能在意外的情况下给全局变量赋值;
  • 全局变量的显示声明,函数必须声明在顶层,不允许在非函数代码块内声明函数,arguments.callee也不允许使用;
  • 消除代码运行的一些不安全之处,保证代码运行的安全,限制函数中的arguments修改,严格模式下的eval函数的行为和非严格模式的也不相同;
  • 提高编译器效率,增加运行速度;
  • 为未来新版本的Javascript标准化做铺垫。

18.new操作符具体干了什么呢?

(1)创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
(2)属性和方法被加入到 this 引用的对象中。
(3)新创建的对象由 this 所引用,并且最后隐式的返回 this 。

var obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj);

19.Javascript中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是?

hasOwnProperty

javaScript中hasOwnProperty函数方法是返回一个布尔值,指出一个对象是否具有指定名称的属性。此方法无法检查该对象的原型链中是否具有该属性;该属性必须是对象本身的一个成员。

使用方法:

object.hasOwnProperty(proName)
// 其中参数object是必选项。一个对象的实例。
// proName是必选项。一个属性名称的字符串值。

如果 object 具有指定名称的属性,那么JavaScript中hasOwnProperty函数方法返回 true,反之则返回 false。

20.js延迟加载的方式有哪些?

  • defer和async
  • 动态创建DOM方式(用得最多)
  • 按需异步载入js

21.Ajax 是什么? 如何创建一个Ajax?

ajax的全称:Asynchronous Javascript And XML。
异步传输 + js + xml
所谓异步,简单解释就是:向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是不会发生整页刷新的,提高了用户体验。

(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息
(3)设置响应HTTP请求状态变化的函数
(4)发送HTTP请求
(5)获取异步调用返回的数据
(6)使用JavaScript和DOM实现局部刷新

22.Ajax 如何解决浏览器缓存问题?

(1)在ajax发送请求前加上 anyAjaxObj.setRequestHeader("If-Modified-Since","0");
(2)在ajax发送请求前加上 anyAjaxObj.setRequestHeader("Cache-Control","no-cache");
(3)在URL后面加上一个随机数: "fresh=" + Math.random();
(4)在URL后面加上时间戳:"nowtime=" + new Date().getTime();
(5)如果是使用jQuery,$.ajaxSetup({cache:false}),这样页面的所有ajax都会执行这条语句就是不需要保存缓存记录。

23.同步和异步的区别?

  • 同步的概念应该是来自于OS中关于同步的概念:不同进程为协同完成某项工作而在先后次序上调整(通过阻塞,唤醒等方式).同步强调的是顺序性.谁先谁后.异步则不存在这种顺序性.

  • 同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作。
    异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。

24.AMD、CMD规范区别?

  • 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
  • CMD 推崇依赖就近,AMD 推崇依赖前置。
// CMD
define(function(require, exports, module) {
    var a = require('./a')
    a.doSomething()
    // 此处略去 100 行
    var b = require('./b') // 依赖可以就近书写
    b.doSomething()
    // ...
})

// AMD 默认推荐
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
    a.doSomething()
    // 此处略去 100 行
    b.doSomething()
    // ...
})

详细了解可查看博主的另一篇文章 前端模块化

25.DOM操作——怎样添加、移除、移动、复制、创建和查找节点?

(1)创建新节点

createDocumentFragment()    //创建一个DOM片段
createElement()    //创建一个具体的元素
createTextNode()   //创建一个文本节点

(2)添加、移除、替换、插入

appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //在已有的子节点前插入一个新的子节点

(3)查找

getElementsByTagName() //通过标签名称
getElementsByName()    //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
getElementById()       //通过元素Id,唯一性

26.如何判断当前脚本运行在浏览器还是node环境中?

this === window ? 'browser' : 'node';
// 通过判断Global对象是否为window,如果不为window,当前脚本没有运行在浏览器中

27.那些操作会造成内存泄漏?

  • 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。
  • 垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。
  • setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
    闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

28.Webpack热更新实现原理?

(1)Webpack编译期,为需要热更新的 entry 注入热更新代码(EventSource通信)
(2)页面首次打开后,服务端与客户端通过 EventSource 建立通信渠道,把下一次的 hash 返回前端
(3)客户端获取到hash,这个hash将作为下一次请求服务端 hot-update.js 和 hot-update.json的hash
(4)修改页面代码后,Webpack 监听到文件修改后,开始编译,编译完成后,发送 build 消息给客户端
(5)客户端获取到hash,成功后客户端构造hot-update.js script链接,然后插入主文档
(6)hot-update.js 插入成功后,执行hotAPI 的 createRecord 和 reload方法,获取到 Vue 组件的 render方法,重新 render 组件, 继而实现 UI 无刷新更新。

ES6相关

1.Object.is() 与原来的比较操作符“ ===”、“ ==”的区别?

  • 两等号判等,会在比较时进行类型转换;
123 == '123'  // true
null == undefined  // true
1 == true  // true
0 == false  // true
[] == false  // true
  • 三等号判等(判断严格),比较时不进行隐式类型转换,(类型不同则会返回false);
123 === '123'  // false
null === undefined  // false
1 === true  // false
0 === false  // false
[] === false  // false

NaN === NaN  // false
+0 === -0  // true
  • Object.is 在三等号判等的基础上特别处理了 NaN 、-0 和 +0 ,保证 -0 和 +0 不再相同,
    但 Object.is(NaN, NaN) 会返回 true.
Object.is(NaN, NaN)  // true
Object.is(-0, +0)  // false
  • Object.is 应被认为有其特殊的用途,而不能用它认为它比其它的相等对比更宽松或严格。

2.Set 和 Map 数据结构

(1)set它类似于数组,但是成员的值都是唯一的,没有重复的值。
(2)WeakSet 的成员只能是对象,而不能是其他类型的值。

WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
(3)map 值—值对应的关系。“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键,如果Map的键是简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键。

(4)weakmap WeakMap与Map的区别有两点:

  • 首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。
  • 其次,WeakMap的键名所指向的对象,不计入垃圾回收机制。

注意:WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用。

3.Proxy

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

const target = {
    m: function () {
        console.log(this === proxy);
    }
};
const handler = {};
const proxy = new Proxy(target, handler);
target.m() // false
proxy.m()  // true

虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要原因就是在 Proxy 代理的情况下,目标对象内部的this关键字会指向 Proxy 代理。

4.promise

Promise 是异步编程的一种解决方案,Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。

特点:
(1)对象的状态不受外界影响。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。

局限性:

  • 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  • 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  • 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
  • 当接收到一个代表错误的 HTTP 状态码时,从 fetch() 返回的 Promise 不会被标记为 reject, 即使响应的 HTTP 状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。

其他问题

1.get和post区别

  • GET产生一个TCP数据包;POST产生两个TCP数据包。并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。
  • GET在浏览器回退时是无害的,而POST会再次提交请求。
  • GET是表单提交的默认方法。
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • GET的参数放在url中的吗,然而post是放在请求体中的。

2.说一说seo(搜索引擎优化)

对于自身网页而言:

  • 网页头部添加TDK, 即 title、description、keywords 这三个标签。
  • 使用语义化的标签。如main,article,header,footer,nav,aside,section,time,mark,video,audio等。符合 W3C 规范:语义化代码让搜索引擎容易理解网页。
  • 重要的内容不要放在js代码中,搜索引擎不会爬取js代码。
  • 提高网站性能

其他的一些方面:

  • 使用https协议–安全小绿锁。
  • 网址静态化,短网址,伪静态。
  • 增加网站外链。
  • 全站地图sitemap,即告诉搜索引擎怎么爬取你的网站。
    以百度为例,主动提交百度收录,添加robots机器人(其实也就是一个txt文件,告诉百度引擎想让他爬什么,不能爬什么。)

3.页面重构怎么操作?

网站重构:在不改变外部行为的前提下,简化结构、添加可读性,而在网站前端保持一致的行为。
也就是说是在不改变UI的情况下,对网站进行优化,在扩展的同时保持一致的UI。

传统的网站重构

  • 表格(table)布局改为DIV+CSS,使网站前端兼容于现代浏览器(针对于不合规范的CSS、如对IE6有效的)
  • 对于移动平台的优化
  • 针对于SEO进行优化

深层次的网站重构

  • 减少代码间的耦合
  • 让代码保持弹性
  • 严格按规范编写代码
  • 设计可扩展的API
  • 代替旧有的框架、语言(如VB)
  • 增强用户体验

速度的优化

  • 压缩JS、CSS、image等前端资源(通常是由服务器来解决)
  • 程序的性能优化(如数据读写)
  • 采用CDN来加速资源加载
  • 对于JS DOM的优化
  • HTTP服务器的文件缓存

4.什么叫优雅降级和渐进增强?

  • 优雅降级:Web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会针对旧版本的IE进行降级处理了,使之在旧式浏览器上以某种形式降级体验却不至于完全不能用。

如:border-shadow

  • 渐进增强:从被所有浏览器支持的基本功能开始,逐步地添加那些只有新版本浏览器才支持的功能,向页面增加不影响基础浏览器的额外样式和功能的。当浏览器支持时,它们会自动地呈现出来并发挥作用。

如:默认使用flash上传,但如果浏览器支持HTML5的文件上传功能,则使用HTML5实现更好的体验;

5.你有用过哪些前端性能优化的方法?

(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指尽量不使用文件系统作为缓存、减少读写文件次数等。程序优化永远要优化慢的部分,换语言是无法“优化”的。

6.http状态码有那些?分别代表是什么意思?

100 Continue 继续,一般在发送post请求时,已发送了http,header之后服务端将返回此信息,表示确认,之后发送具体参数信息
200 OK 正常返回信息
201 Created 请求成功并且服务器创建了新的资源
202 Accepted 服务器已接受请求,但尚未处理
301 Moved Permanently 请求的网页已永久移动到新位置。
302 Found 临时性重定向。
303 See Other 临时性重定向,且总是使用 GET 请求新的 URI。
304 Not Modified 自从上次请求后,请求的网页未修改过。
400 Bad Request 服务器无法理解请求的格式,客户端不应当尝试再次使用相同的内容发起请求。
401 Unauthorized 请求未授权。
403 Forbidden 禁止访问。
404 Not Found 找不到如何与 URI 相匹配的资源。
500 Internal Server Error 最常见的服务器端错误。
503 Service Unavailable 服务器端暂时无法处理请求(可能是过载或维护)。

7.一个页面从输入 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,执行事件绑定等,页面显示完成。

简洁版:

  • 浏览器根据请求的URL交给DNS域名解析,找到真实IP,向服务器发起请求;
  • 服务器交给后台处理完成后返回数据,浏览器接收文件(HTML、JS、CSS、图象等);
  • 浏览器对加载到的资源(HTML、JS、CSS等)进行语法解析,建立相应的内部数据结构(如HTML的DOM);
  • 载入解析到的资源文件,渲染页面,完成。

高手可以根据自己擅长的领域自由发挥,从URL规范、HTTP协议、DNS、CDN、数据库查询、到浏览器流式解析、CSS规则构建、layout、paint、onload/domready、JS执行、JS API绑定等等;

前端框架

考察前端框架之类的,如自己把握比较好的一门,Vue,ReactReact,Angular,或者基于此类的一些框架,uniapp,ElementUI等等,本文暂时不做此类记录。

posted @ 2021-04-15 14:07  Red-Plum  阅读(103)  评论(0编辑  收藏  举报