1. 前端开发知识点
HTML&CSS:
对Web标准的理解、浏览器内核差异、兼容性、hack、CSS基本功:布局、盒子模型、选择器优先级、
HTML5、CSS3、Flexbox
JavaScript:
数据类型、运算、对象、Function、继承、闭包、作用域、原型链、事件、RegExp、JSON、Ajax、
DOM、BOM、内存泄漏、跨域、异步装载、模板引擎、前端MVC、路由、模块化、Canvas、ECMAScript 6、Nodejs
其他:
移动端、响应式、自动化构建、HTTP、离线存储、WEB安全、优化、重构、团队协作、可维护、易用性、SEO、UED、架构、职业生涯、快速学习能力
1.1. 前端面试
一面:页面布局、css 盒模型、DOM 事件、HTTP 协议、面向对象、原型链、算法、安全、通信二面:vue 源码、优缺点、原理、生命周期三面:业务负责人,职业生涯特色业务,角色,推动了、改变了什么终面:HR 面试,沟通、性格、潜力
抽象设计能力、项目把控能力、经验。
1.2. 面试准备
- 职位描述 JD 分析
- 业务分析或实战模拟
- 技术栈准备
- 自我介绍
1.3. 问题
1.3.1. 对 Node 的优点和缺点提出了自己的看法
优点:
- Node 是基于事件驱动和无阻塞的,所以非常适合处理并发请求,因此构建在 Node 上的代理服务器相比其他技术实现(如 Ruby)的服务器表现要好得多。
- 客户端和服务端统一语言 javascript
缺点:
早期 Node 是一个相对新的开源项目,所以不太稳定,它总是一直在变,而且缺少足够多的第三方库支持。看起来,就像是 Ruby/Rails 当年的样子。
1.3.2. .net 技术迁移
- ORM: node 和 前端可以借鉴
- 强类型: typescript
- razor 引擎,比 ejs,jade 都好用
1.3.3. "attribute" 和 "property" 的区别是什么?
.property, getAttribute。大部分情况值一样,但 getAttribute('checked') == 'checked', ele.checked == true
1.3.4. HTML5 的离线储存怎么使用,工作原理
在用户没有与因特网连接时,可以正常访问站点或应用,在用户与因特网连接时,更新用户机器上的缓存文件。
原理:HTML5 的离线存储是基于一个新建的 .appcache 文件的缓存机制(不是存储技术),通过这个文件上的解析清单离线存储资源,这些资源就会像 cookie 一样被存储了下来。之后当网络在处于离线状态下时,浏览器会通过被离线存储的数据进行页面展示。
在线的情况下,浏览器发现 html 头部有 manifest 属性,它会请求 manifest 文件,如果是第一次访问 app,那么浏览器就会根据 manifest 文件的内容下载相应的资源并且进行离线存储。如果已经访问过 app 并且资源已经离线存储了,那么浏览器就会使用离线的资源加载页面,然后浏览器会对比新的 manifest 文件与旧的 manifest 文件,如果文件没有发生改变,就不做任何操作,如果文件改变了,那么就会重新下载文件中的资源并进行离线存储。离线的情况下,浏览器就直接使用离线存储的资源。
如何使用
- 页面头部像下面一样加入一个 manifest 的属性:
<html manifest="cache.manifest">
在 cache.manifest 文件的编写离线存储的资源;
CACHE MANIFEST #v0.11 CACHE: js/app.js css/style.css NETWORK: resource/logo.png FALLBACK: // offline.html在离线状态时,操作window.applicationCache进行需求实现。
自动化工具: (http://yanhaijing.com/html/2014/12/28/html5-manifest/)
manifest 文件中的 cache 部分不能使用通配符,必须手动指定,这实在太让人不可理解,文件一多,就成了体力活了,这里介绍的 grunt-manifest 能自动生成 manifest 文件的目的。grunt-manifest 依赖 grunt
如下的命令可以安装 grunt-manifest,并加入到依赖文件。
npm install grunt-manifest --save-dev
如下的代码,可以在 grunt 中载入 grunt-manifest,然后便可使用。
grunt.loadNpmTasks('grunt-manifest');
使用 grunt-manifest 的一个典型的配置文件如下所示:
grunt.initConfig({
manifest: {
generate: {
options: {
basePath: "../",
cache: ["js/app.js", "css/style.css"]
network: ["http://*", "https://*"],
fallback: ["/ /offline.html"],
exclude: ["js/jquery.min.js"],
preferOnline: true,
verbose: true,
timestamp: true
},
src: [
"some_files/*.html",
"js/*.min.js",
"css/*.css"
],
dest: "index.manifest"
}
}
});
其中 options 定义生成 manifest 的一些自定义参数,src 是要生成的文件,dest 是输出文件。
options 下有很多参数,主要参数如下:
- basePath 设置出入文件的根目录
- cache 手动添加缓存文件
- network 手动添加网络文件
- fallback 手动添加后备文件
- exclude 设置不添加到 cache 的文件
- verbose 是否添加版权信息
- timestamp 是否添加时间戳
- 这里有 Basejs 的配置文件和生成的 manifest 文件的例子。
1.3.5. What's the difference between feature detection, feature inference, and using the UA string?
Feature Detection (✅)
Feature Detection is to verify if a feature works in a particular browser or not. The feature can be either a CSS property or a Java Script Method. A good example is a modern HTML5 feature Location
.
if (navigator.geolocation) {
// detect users location here B-) and do something awesome
}
Feature Inference 推理
Feature Inference is to assume that a CSS property or JS method is available in all the browsers, by verifying it in a single browser. The fact is it can or it cannot be available. For ex. the text()
function is implemented in Chrome, but it is not implemented in Firefox which will give out an error eventually when used. So we have to be careful.
UA String
Identifies your operating system, browser and its version via navigator.userAgent
. These “string text of data” contains information of the browser environment you are targeting.
navigator.userAgent;
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71
1.3.6. FOUC (Flash of Unstyled Content)
由于 external css 没有加载完成导致页面使用浏览器默认样式去显示页面。加载好后样式回归。
避免方法:
把 external css 放到页面 head 中而不是 body 后面。head 中 css 会阻止 DOM 解析。
代码控制
<!-- Prevent FOUC (flash of unstyled content) - http://johnpolacek.com/2012/10/03/help-prevent-fouc/ -->
<style>
.no-fouc {display: none;}
</style>
<script>
document.documentElement.className = 'no-fouc';
document.addEventListener('DOMContentLoaded', function(){
document.querySelector('.no-fouc').classList.remove('no-fouc')
})
</script>
1.3.7. How many resources will a browser download from a given domain at a time? Traditionally, why has it been better to serve site assets from multiple domains?
IE7 allowed only two concurrent connections per host. But most browsers today allow more than that. IE8 allows 6 concurrent connections, Chrome allows 6, and Firefox allows 8.
多个 subdomain 查询也需要时间。Let's say you have 24 images on a page. Well, few things in life are free and there's such a thing as death by parallelization. If you host your images in 4 different subdomains, then that means that every single image could theoretically be downloaded in parallel. However, it also means that there are 3 additional DNS lookups involved. And a DNS lookup could be 100 ms, 150 ms, or sometimes longer. This added delay could easily offset any benefit of parallel downloads. You can see real-world examples of this by testing sites with http://www.webpagetest.org/
Of course the best solution is to use CSS sprites when possible to cut down on the number of requests.
Most of the U.S. top ten web sites do domain sharding. What’s the optimal number? Yahoo! released a study that recommends sharding across at least two, but no more than four, domains. Above four, performance actually degrades.
Note however that this was written in 2009. And in 2011 he posted a comment...
Since newer browsers open more connections per domain, it’s probably better to revise the number downwards. I think 2 is a good compromise, but that’s just a hunch. It’d be great if some production property ran a test to determine the optimal number. You should also keep in mind that the big reason it's even necessary for the big sites like Yahoo and Amazon to do domain sharding is that their sites are so dynamic. The images are attached to products or stories which are displayed dynamically. So it's not feasible for them to use CSS sprites as aggressively as would be optimal.
A site like StackOverflow, however, is light on these sorts of images and they have cut down on the number of requests so much that they don't need to do sharding. A big step towards making that happen is their usage of this sprites.png image...
http 2.0 时代使用多个 subdomain 没必要了,反而性能不会提升。。Perhaps the strongest argument against domain sharding is that it’s unnecessary in the world of SPDY (as well as HTTP 2.0
). In fact, domain sharding probably hurts performance under SPDY. SPDY supports concurrent requests (send all the request headers early) as well as request prioritization. Sharding across multiple domains diminishes these benefits. SPDY is supported by Chrome, Firefox, Opera, and IE 11. If your traffic is dominated by those browsers, you might want to skip domain sharding.
1.3.8. Describe z-index and how stacking context is formed
z-index 需要配合 position (非 static) 使用。值越大,相应的 layer 位置越高。z-index 的使用场景之一是我做模态框的时候,这种我把它叫天马派,有最高层级,可能 z-index 设置 999;还有些是 低空飞行派,z-index 从 1 - 10。但我不建议乱用 z-index,其实在 html 结构写的合理的时候,大部分情况下层级上下关系根据 html 结果确定好了,不需要为人加入 z-index 去干涉合理的层级结构。认为加入可能导致 z-index 混乱。我之前有个项目就是大家随意设置 z-index。10,999, 500 等。我是觉得 z-index 对于低空飞行派,1-5 就够用了。过多了说明 html 结构不合理。
stacking context:简单理解就是具有 z 轴方向 属性的元素。该元素有层级属性,或者里面 children 有层级。
stacking context 如何形成:
- html 标签
- Element with a position value
"absolute" or "relative"
andz-index
value other than "auto". - Element with a position value
"fixed" or "sticky"
(sticky for all mobile browsers, but not older desktop). - Element that is a child of a flex (
flexbox
) container, withz-index
value other than "auto". - Element with a
opacity
value less than 1 (See the specification for opacity). - Element with any of the following properties with value other than "none":
transform
- perspective
- clip-path
- mask / mask-image / mask-border
特点:
同级别的 div 之间层级关系由 z-index 决定。某个 div 里面 children 的层级和该 div 的兄弟没有层级关系。
div 1 2 3 层级关系有他们的 z-index 决定,div 4 5 6 的关系由 456 决定。
DIV #1
DIV #2
DIV #3
DIV #4
DIV #5
DIV #6
1.3.9. 页面可见性(Page Visibility API) 可以有哪些用途?
通过 visibilityState 的值检测页面当前是否可见,以及打开网页的时间等; 在页面被切换到其他后台进程的时候,自动暂停音乐或视频的播放;
1.3.10. 对象到字符串的转换步骤
- 如果对象有
toString()
方法,javascript 调用它。如果返回一个原始值(primitive value 如:string number boolean),将这个值转换为字符串作为结果 - 如果对象没有
toString()
方法或者返回值不是原始值,javascript 寻找对象的valueOf()
方法,如果存在就调用它,返回结果是原始值则转为字符串作为结果 - 否则,javascript 不能从
toString()
或者valueOf()
获得一个原始值,此时 throws a TypeError
1.3.11. 函数内部 arguments 特性, 如何将它转换为数组
- arguments 是所有函数中都包含的一个局部变量,是一个类数组对象,对应函数调用时的实参。如果函数定义同名参数会在调用时覆盖默认对象
- arguments[index] 分别对应函数调用时的实参,并且通过 arguments 修改实参时会同时修改实参
- arguments.length 为实参的个数(Function.length 表示形参长度)
- arguments.callee 为当前正在执行的函数本身,使用这个属性进行递归调用时需注意 this 的变化。匿名函数递归调用使用。严格模式下不能用 callee
- arguments.caller 为调用当前函数的函数(已被遗弃)
转换为数组:
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
var args = Array.from(arguments);
var args = [...arguments];
1.3.12. 说几条写 JavaScript 的基本规范?
- 不要在同一行声明多个变量。
- 请使用
===/!==
来比较 true/false 或者数值 - 使用对象字面量替代 new Array 这种形式
- 不要使用全局函数。
- Switch 语句必须带有 default 分支
- 函数不应该有时候有返回值,有时候没有返回值。
- For 循环必须使用大括号
- If 语句必须使用大括号
- for-in 循环中的变量 应该使用 var 关键字明确限定作用域,从而避免作用域污染。
1.4. Test
// Load the test dependencies
var app = require('../../server'),
request = require('supertest'),
should = require('should'),
mongoose = require('mongoose'),
User = mongoose.model('User'),
Article = mongoose.model('Article');
// Define global test variables
var user, article;
// Create an 'Articles' controller test suite
describe('Article Controller Unit Tests:', function() {
// Define a pre-tests function
beforeEach(function(done) {
// Create a new 'User' model instance
user = new User({
firstName: 'Full',
lastName: 'Name',
displayName: 'Full Name',
email: 'test@test.com',
username: 'username',
password: 'password',
});
// Save the new 'User' model instance
user.save(function() {
article = new Article({
title: 'Article Title',
content: 'Article Content',
user: user,
});
article.save(function(err) {
done();
});
});
});
// Test the 'Article' GET methods
describe('Testing the GET methods', function() {
it('Should be able to get the list of articles', function(done) {
// Create a SuperTest request
request(app)
.get('/api/articles/')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
// res.body.should.have.lengthOf(1).and.be.an.Array; //should.js
res.body.should.be.an.instanceof(Array).and.have.lengthOf(1); // should.js
// res.body.should.be.an.Array.and.have.lengthOf(1); // this doesn't work in late should.js since Array cannot chain
res.body[0].should.have.property('title', article.title); // here is should.js
res.body[0].should.have.property('content', article.content); // here is should.js
done();
});
});
it('Should be able to get the specific article', function(done) {
// Create a SuperTest request
request(app)
.get('/api/articles/' + article.id)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
// res.body.should.be.an.Object.and.have.property('title', article.title); // here is should.js
// res.body.should.have.property('content', article.content); // here is should.js
done();
});
});
});
// Define a post-tests function
afterEach(function(done) {
// Clean the database
Article.remove(function() {
User.remove(function() {
done();
});
});
});
});