总结一下
面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。
还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。
万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。
前端面试题汇总
前言:vue已经放弃维护vue-resource了,然后推荐使用axios,这一推荐不得了了,axios的人气大增啊,在github已经是50多k的star了,axios算是成功打入了vue全家桶了,既然官方这么推荐,我们接下来就来研究一下axios,顺便再啰嗦几句,我们一直在研究这个框架那个框架的,其实说白了,框架其实就是别人的一种编程思想,都是一些大牛总结的一些编程经验,形象一点就比如一辆汽车的高配与低配,都能够跑,但是感觉就是不一样哈,所以多研究别人好的东西能让自己少走很多弯路,还会让自己变得更强,哈哈~~ 加油,骚年!
我们直接用vue-cli创建一个webpack工程(怎么创建一个vue工程我就不bb了哈),然后我们运行我们的vue工程:
接着我们去github上copy一份axios的源码放到我们工程里面。
我们直接把它lib目录的所有文件copy一份:
https://github.com/axios/axios/tree/master/lib
可以看到,我们已经把axios的源码copy进工程了,接下来我们先用一下它,我们先简单用node搭建一个属于自己的服务器(怎么搭建服务器我前面有一篇文章有介绍过,感兴趣的小伙伴可以去看一看node搭建简易服务器,设置跨域访问)
好啦,服务器搭建好了,我们简单的用一下axios:
HelloWorld.vue:
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
import axios from '../lib/axios'
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Axios'
}
},
created () {
axios.get('http://localhost:8090/home').then((res) => {
console.log(res)
}).catch((erro) => {
console.log(erro)
})
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
好啦,我们运行一下项目可能会报这样的错误(如果是直接用vue-cli创建的工程):
这是因为axios的源码用es5写的,我们工程babel配置文件需要修改一下:
.babelrc
{
"presets": [
[
"env",
{
"modules": false,
"targets": {
"browsers": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
}
],
"stage-2"
],
"plugins": [
"transform-vue-jsx",
[
"transform-runtime",
{
"helpers": false,
"polyfill": false
}
]
]
}
好啦,我们再次运行我们的项目:
可以看到,我们已经请求成功了,axios的用法我就不在这里啰嗦了,小伙伴直接去看axios的文档就好了,我们重点研究一下它是怎么工作了。
首先我们找到axios的入口:
axios.js
'use strict';
var utils = require('./utils');
var bind = require('./helpers/bind');
var Axios = require('./core/Axios');
var mergeConfig = require('./core/mergeConfig');
var defaults = require('./defaults');
/**
* Create an instance of Axios
*
* @param {Object} defaultConfig The default config for the instance
* @return {Axios} A new instance of Axios
*/
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
var instance = bind(Axios.prototype.request, context);
// Copy axios.prototype to instance
utils.extend(instance, Axios.prototype, context);
// Copy context to instance
utils.extend(instance, context);
return instance;
}
// Create the default instance to be exported
var axios = createInstance(defaults);
// Expose Axios class to allow class inheritance
axios.Axios = Axios;
// Factory for creating new instances
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
// Expose Cancel & CancelToken
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');
// Expose all/spread
axios.all = function all(promises) {
return Promise.all(promises);
};
axios.spread = require('./helpers/spread');
module.exports = axios;
// Allow use of default import syntax in TypeScript
module.exports.default = axios;
可以看到,入口文件其实没有什么内容,当我们在demo使用get请求的时候,我们走了什么内容呢?
created () {
axios.get('http://localhost:8090/home').then((res) => {
console.log(res)
}).catch((erro) => {
console.log(erro)
})
}
那么axios是一个什么的对象呢?我们看到这么一段代码:
function createInstance(defaultConfig) {
//创建一个Axios对象
var context = new Axios(defaultConfig);
//创建一个axios实例
var instance = bind(Axios.prototype.request, context);
//copy一份Axios的原型给instance对象
utils.extend(instance, Axios.prototype, context);
//让instance继承context的所有属性
utils.extend(instance, context);
return instance;
}
通过源码我们可以看到,其实axios对象也就是返回的instance其实原型就是Axios,所以我们接下来看一下Axios。
/core/Axios.js
'use strict';
var utils = require('./../utils');
var buildURL = require('../helpers/buildURL');
var InterceptorManager = require('./InterceptorManager');
var dispatchRequest = require('./dispatchRequest');
var mergeConfig = require('./mergeConfig');
/**
* Create a new instance of Axios
*
* @param {Object} instanceConfig The default config for the instance
*/
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
/**
* Dispatch a request
*
* @param {Object} config The config specific for this request (merged with this.defaults)
*/
Axios.prototype.request = function request(config) {
/*eslint no-param-reassign:0*/
// Allow for axios('example/url'[, config]) a la fetch API
if (typeof config === 'string') {
config = arguments[1] || {};
config.url = arguments[0];
} else {
config = config || {};
}
config = mergeConfig(this.defaults, config);
config.method = config.method ? config.method.toLowerCase() : 'get';
// Hook up interceptors middleware
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
Axios.prototype.getUri = function getUri(config) {
config = mergeConfig(this.defaults, config);
return buildURL(config.url, config.params, config.paramsSerializer).replace(/^\?/, '');
};
// Provide aliases for supported request methods
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url
}));
};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, data, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url,
data: data
}));
};
});
module.exports = Axios;
代码有点多,我们直接看重点,我们demo中用了get方法,我们来一下Axios中的get方法定义:
// Provide aliases for supported request methods
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url
}));
};
});
Axios.prototype.request = function request(config) {
...
return promise;
};
在官方文档中我们可以看到,除了可以用demo中的:
axios.get('http://localhost:8090/home').then((res) => {
console.log(res)
}).catch((erro) => {
console.log(erro)
})
这种方式访问网络请求外,我们还可以用:
created () {
axios({
url: 'http://localhost:8090/home',
method: 'GET'
}).then((res) => {
console.log(res)
}).catch((erro) => {
console.log(erro)
})
}
通过源码我们发现,不管我们用那种方式请求,我们最后都会走Axios的request方法:
Axios.prototype.request = function request(config) {
/*eslint no-param-reassign:0*/
// Allow for axios('example/url'[, config]) a la fetch API
if (typeof config === 'string') {
config = arguments[1] || {};
config.url = arguments[0];
} else {
config = config || {};
}
config = mergeConfig(this.defaults, config);
config.method = config.method ? config.method.toLowerCase() : 'get';
// Hook up interceptors middleware
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
我们可以看到,request方法直接返回了一个promise对象,所以我们才可以直接通过then拿到返回的结果的。
我们在Axios的request方法中看到这么一段代码:
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
我们可以看到有一个叫chain的数组,chain英文翻译是链条的意思,我们在这可以形象的把它叫做流水线,一个产品从原材料–>最后的产品会通过一个叫chain的流水线,chain数组中的每一个元素都是一个小组,从对request的封装到最后对response的封装,最后返回需要的result。
//流水线的第一个小组默认是dispatchRequest
var chain = [dispatchRequest, undefined];
//原材料
var promise = Promise.resolve(config);
//是否需要对原材料进行质检跟其它操作
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
//是否需要对产品进行包装
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
//启动流水线
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
嘿嘿~感觉自己进过厂一样! 原谅我只能以这样的形式来描述了。
在demo中我们可以看到,我们并没有对原材料跟产品做任何处理:
created () {
axios.get('http://localhost:8090/home').then((res) => {
console.log(res)
}).catch((erro) => {
console.log(erro)
})
}
所以在request中不会走:
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
对于interceptors我们之后再研究了,既然拦截器的代码不走了,我们就重点关注一下dispatchRequest函数,不管有没有拦截器,dispatchRequest方法都会默认执行的:
code/dispatchRequest.js
'use strict';
var utils = require('./../utils');
var transformData = require('./transformData');
var isCancel = require('../cancel/isCancel');
var defaults = require('../defaults');
var isAbsoluteURL = require('./../helpers/isAbsoluteURL');
var combineURLs = require('./../helpers/combineURLs');
/**
* Throws a `Cancel` if cancellation has been requested.
*/
function throwIfCancellationRequested(config) {
if (config.cancelToken) {
config.cancelToken.throwIfRequested();
}
}
/**
* Dispatch a request to the server using the configured adapter.
*
* @param {object} config The config that is to be used for the request
* @returns {Promise} The Promise to be fulfilled
*/
module.exports = function dispatchRequest(config) {
throwIfCancellationRequested(config);
// Support baseURL config
if (config.baseURL && !isAbsoluteURL(config.url)) {
config.url = combineURLs(config.baseURL, config.url);
}
// Ensure headers exist
config.headers = config.headers || {};
// Transform request data
config.data = transformData(
config.data,
config.headers,
config.transformRequest
);
// Flatten headers
config.headers = utils.merge(
config.headers.common || {},
config.headers[config.method] || {},
config.headers || {}
);
utils.forEach(
['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
function cleanHeaderConfig(method) {
delete config.headers[method];
}
);
var adapter = config.adapter || defaults.adapter;
return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// Transform response data
response.data = transformData(
response.data,
response.headers,
config.transformResponse
);
return response;
}, function onAdapterRejection(reason) {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
// Transform response data
if (reason && reason.response) {
reason.response.data = transformData(
reason.response.data,
reason.response.headers,
config.transformResponse
);
}
}
return Promise.reject(reason);
});
};
代码还是有点多,我们看重点:
module.exports = function dispatchRequest(config) {
.....
var adapter = config.adapter || defaults.adapter;
return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// Transform response data
response.data = transformData(
response.data,
response.headers,
config.transformResponse
);
return response;
}, function onAdapterRejection(reason) {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
// Transform response data
if (reason && reason.response) {
reason.response.data = transformData(
reason.response.data,
reason.response.headers,
config.transformResponse
);
}
}
return Promise.reject(reason);
});
};
可以看到,最后直接执行了adapter(config)方法,然后返回了一个promise对象,那么adapter方法又是哪来的呢?
var adapter = config.adapter || defaults.adapter;
可以看到,我们demo中除了传递了一个url外根本就没有传递其它的参数,所以adapter就直接用的是 defaults.adapter,我们去找到它的源码。
defaults.js
'use strict';
var utils = require('./utils');
var normalizeHeaderName = require('./helpers/normalizeHeaderName');
var DEFAULT_CONTENT_TYPE = {
'Content-Type': 'application/x-www-form-urlencoded'
};
function setContentTypeIfUnset(headers, value) {
if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
headers['Content-Type'] = value;
}
}
function getDefaultAdapter() {
var adapter;
// Only Node.JS has a process variable that is of [[Class]] process
if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = require('./adapters/http');
} else if (typeof XMLHttpRequest !== 'undefined') {
// For browsers use XHR adapter
adapter = require('./adapters/xhr');
}
return adapter;
}
var defaults = {
adapter: getDefaultAdapter(),
transformRequest: [function transformRequest(data, headers) {
normalizeHeaderName(headers, 'Accept');
normalizeHeaderName(headers, 'Content-Type');
if (utils.isFormData(data) ||
utils.isArrayBuffer(data) ||
utils.isBuffer(data) ||
utils.isStream(data) ||
utils.isFile(data) ||
utils.isBlob(data)
) {
return data;
}
if (utils.isArrayBufferView(data)) {
return data.buffer;
}
if (utils.isURLSearchParams(data)) {
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
return data.toString();
}
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringify(data);
}
return data;
}],
transformResponse: [function transformResponse(data) {
/*eslint no-param-reassign:0*/
if (typeof data === 'string') {
try {
data = JSON.parse(data);
} catch (e) { /* Ignore */ }
}
return data;
}],
/**
* A timeout in milliseconds to abort a request. If set to 0 (default) a
* timeout is not created.
*/
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: function validateStatus(status) {
return status >= 200 && status < 300;
}
};
defaults.headers = {
common: {
'Accept': 'application/json, text/plain, */*'
}
};
utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) {
defaults.headers[method] = {};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
});
module.exports = defaults;
代码还是有点多,我们直接看adapter属性:
var defaults = {
adapter: getDefaultAdapter()
....
function getDefaultAdapter() {
var adapter;
// Only Node.JS has a process variable that is of [[Class]] process
if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = require('./adapters/http');
} else if (typeof XMLHttpRequest !== 'undefined') {
// For browsers use XHR adapter
adapter = require('./adapters/xhr');
}
return adapter;
}
可以看到,在获取adapter的时候还做了环境的判断,如果是node环境的时候adapter=require(’./adapters/http’);如果是浏览器环境的时候adapter = require(’./adapters/xhr’);因为我们走的是浏览器环境,所以我们重点看adapter = require(’./adapters/xhr’);
adapters/xhr.js:
'use strict';
var utils = require('./../utils');
var settle = require('./../core/settle');
var buildURL = require('./../helpers/buildURL');
var parseHeaders = require('./../helpers/parseHeaders');
var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
var createError = require('../core/createError');
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
var requestData = config.data;
var requestHeaders = config.headers;
if (utils.isFormData(requestData)) {
delete requestHeaders['Content-Type']; // Let the browser set it
}
var request = new XMLHttpRequest();
// HTTP basic authentication
if (config.auth) {
var username = config.auth.username || '';
var password = config.auth.password || '';
requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
}
request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true);
// Set the request timeout in MS
request.timeout = config.timeout;
// Listen for ready state
request.onreadystatechange = function handleLoad() {
if (!request || request.readyState !== 4) {
return;
}
// The request errored out and we didn't get a response, this will be
// handled by onerror instead
// With one exception: request that using file: protocol, most browsers
### 最后
推荐一些系统学习的途径和方法。
![路线图](https://img-blog.csdnimg.cn/img_convert/abffda3a0cfe5b9baa70f132ab55f248.png)
每个Web开发人员必备,很权威很齐全的Web开发文档。作为学习辞典使用,可以查询到每个概念、方法、属性的详细解释,注意使用英文关键字搜索。里面的一些 HTML,CSS,HTTP 技术教程也相当不错。
**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**
HTML 和 CSS:
![html5知识](https://img-blog.csdnimg.cn/img_convert/2ee0d943c2e65e1bf84360c1c8a40cf6.png)
![css基础知识](https://img-blog.csdnimg.cn/img_convert/f660a2fef40322a6e2c45716d4a97e02.png)