2018面试总结第一轮
头条面试题卷一
JS里的New干了什么
let obj = new Base();
这样代码的结果是什么,我们在Javascript引擎中看到的对象模型是:
new操作符具体干了什么呢?其实很简单,就干了三件事情。
let obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
第一行,我们创建了一个空对象obj
第二行,我们将这个空对象的__proto__成员指向了Base函数对象prototype成员对象
第三行,我们将Base函数对象的this指针替换成obj,然后再调用Base函数,于是我们就给obj对象赋值了一个id成员变量,这个成员变量的值是”base”。
如果我们给Base.prototype的对象添加一些函数会有什么效果呢?
例如代码如下:
Base.prototype.toString = function() {
return this.id;
}
那么当我们使用new创建一个新对象的时候,根据__proto__的特性,toString这个方法也可以做新对象的方法被访问到。于是我们看到了:
构造子中,我们来设置‘类’的成员变量(例如:例子中的id),构造子对象prototype中我们来设置‘类’的公共方法。于是通过函数对象和Javascript特有的__proto__与prototype成员及new操作符,模拟出类和类实例化的效果。
Position定位属性
static默认定位
relative相对定位
absolute绝对定位
fixed固定定位
sticky粘性定位
HTML中meta标签的作用
<meta> 元素可提供有关某个 HTML 元素的元信息 (meta-information),比如描述、针对搜索引擎的关键词以及刷新频率。
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" /> <meta name="format-detection"content="telephone=no, email=no" /> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> <meta name="apple-mobile-web-app-capable" content="yes" /><!-- 删除苹果默认的工具栏和菜单栏 --> <meta name="apple-mobile-web-app-status-bar-style" content="black" /><!-- 设置苹果工具栏颜色 --> <meta name="format-detection" content="telphone=no, email=no" /><!-- 忽略页面中的数字识别为电话,忽略email识别 --> <!-- 启用360浏览器的极速模式(webkit) --> <meta name="renderer" content="webkit"> <!-- 避免IE使用兼容模式 --> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 --> <meta name="HandheldFriendly" content="true"> <!-- 微软的老式浏览器 --> <meta name="MobileOptimized" content="320"> <!-- uc强制竖屏 --> <meta name="screen-orientation" content="portrait"> <!-- QQ强制竖屏 --> <meta name="x5-orientation" content="portrait"> <!-- UC强制全屏 --> <meta name="full-screen" content="yes"> <!-- QQ强制全屏 --> <meta name="x5-fullscreen" content="true"> <!-- UC应用模式 --> <meta name="browsermode" content="application"> <!-- QQ应用模式 --> <meta name="x5-page-mode" content="app"> <!-- windows phone 点击无高光 --> <meta name="msapplication-tap-highlight" content="no"> <!-- 适应移动端end -->
web中实现长连接的方式
ajax 参考链接
websocket 参考链接
iframe
DOM的删除,移除,复制,插入,查询方法
//查找节点 document.getElementById("id");//通过id查找,返回唯一的节点,如果有多个将会返回第一个,在IE6、7中有个bug,会返回name值相同的元素,所有要做一个兼容 document.getElementsByClassName("class");//通过class查找,返回节点数组 document.getElementsByTagName("div");
document.querySelector(); //方法返回文档中匹配指定 CSS 选择器的一个元素
document.querySelectorAll();
//创建节点 document.createDocumentFragment();//创建内存文档碎片 document.createElement();//创建元素 document.createTextNode();//创建文本节点 //添加节点 var ele = document.getElementById("my_div"); var oldEle = document.createElement("p"); var newEle=document.createElement("div"); ele.appendChild(oldEle); //移除 ele.removeChild(oldEle); //替换 ele.replaceChild(newEle,oldEle); //插入 ele.insertBefore(oldEle,newEle);//在newEle之前插入 oldEle节点 //复制节点 var cEle = oldEle.cloneNode(true);//深度复制,复制节点下面所有的子节点 cEle = oldEle.cloneNode(false);//只复制当前节点,不复制子节点 //移动节点 var cloneEle = oldEle.cloneNode(true);//被移动的节点 document.removeChild(oldEle);//删除原节点
浏览器缓存机制有哪几种
http缓存详解参考链接
exports 和 module.exports 的区别
“原理很简单,即 module.exports 指向新的对象时,exports 断开了与 module.exports 的引用,那么通过 exports = module.exports 让 exports 重新指向 module.exports 即可。” 这一段有点画蛇添足。引用官网的一句 “如果一个新的值被赋值给 exports,它就不再绑定到 module.exports”。
当你搞不明白export和module.export的关系的时候,就一直使用module.export好了。export是module.export的引用,然后export是个局部变量,module是个全局变量。
原生实现Jsonp
1 function ajax(params) { 2 3 params = params || {}; 4 5 params.data = params.data || {}; 6 7 var json = params.jsonp ? jsonp(params) : json(params); 8 9 10 11 // jsonp请求 12 13 function jsonp(params) { 14 15 //创建script标签并加入到页面中 16 17 var callbackName = params.jsonp; 18 19 var head = document.getElementsByTagName('head')[0]; 20 21 // 设置传递给后台的回调参数名 22 23 params.data['callback'] = callbackName; 24 25 var data = formatParams(params.data); 26 27 var script = document.createElement('script'); 28 29 head.appendChild(script); 30 31 32 33 //创建jsonp回调函数 34 35 window[callbackName] = function(json) { 36 37 head.removeChild(script); 38 39 clearTimeout(script.timer); 40 41 window[callbackName] = null; 42 43 params.success && params.success(json); 44 45 }; 46 47 48 49 //发送请求 50 51 script.src = params.url + '?' + data; 52 53 54 55 //为了得知此次请求是否成功,设置超时处理 56 57 if(params.time) { 58 59 script.timer = setTimeout(function() { 60 61 window[callbackName] = null; 62 63 head.removeChild(script); 64 65 params.error && params.error({ 66 67 message: '超时' 68 69 }); 70 71 }, time); 72 73 } 74 75 };
<script type="text/javascript"> //定义一个发送Jsonp请求的函数 function jsonp(obj) { //定义一个处理Jsonp返回数据的回调函数 window["callback"] = function(object) { obj.success(JSON.parse(object)); } var script = document.createElement("script"); //组合请求URL script.src = obj.url + "?fn=callback"; for(key in obj.data){ script.src +="&" + key + "=" + obj.data[key]; } //将创建的新节点添加到BOM树上 document.getElementsByTagName("body")[0].appendChild(script); } </script> <script type="text/javascript"> //调用Jsonp函数发送jsonp请求 jsonp({ url:"http://localhost/index.php", data:{ name:"小明", }, success:function(obj) { alert("性别" + obj.sex); } }); </script>
Html5新增input类型
- url
- number
- range
- Date pickers (date, month, week, time, datetime, datetime-local)
- search
- color
BFC是什么,怎么生成
BFC 定义
BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。
BFC布局规则:
- 内部的Box会在垂直方向,一个接一个地放置。
- Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
- 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
- BFC的区域不会与float box重叠。
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- 计算BFC的高度时,浮动元素也参与计算
JS继承
Vue原理
双向绑定
1 <body> 2 <div id="app"> 3 <input type="text" id="txt"> 4 <p id="show-txt"></p> 5 </div> 6 <script> 7 var obj = {} 8 Object.defineProperty(obj, 'txt', { 9 get: function () { 10 return obj 11 }, 12 set: function (newValue) { 13 document.getElementById('txt').value = newValue 14 document.getElementById('show-txt').innerHTML = newValue 15 } 16 }) 17 document.addEventListener('keyup', function (e) { 18 obj.txt = e.target.value 19 }) 20 </script> 21 </body>
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。如果不指定configurable, writable, enumerable ,则这些属性默认值为false,如果不指定value, get, set,则这些属性默认值为undefined
1 语法: Object.defineProperty(obj, prop, descriptor) 2 obj: 需要被操作的目标对象 3 prop: 目标对象需要定义或修改的属性的名称 4 descriptor: 将被定义或修改的属性的描述符 5 6 var obj = new Object(); 7 8 Object.defineProperty(obj, 'name', { 9 configurable: false, 10 writable: true, 11 enumerable: true, 12 value: '张三' 13 }) 14 15 console.log(obj.name) //张三
头条面试题卷二
1 if (!Function.prototype.binds) { 2 Function.prototype.binds = function (ctx) { 3 if (typeof this !== 'function') { 4 throw new TypeError("NOT_A_FUNCTION -- this is not callable") 5 } 6 var _this = this 7 var slice = Array.prototype.slice 8 var formerArgs = slice.call(arguments, 1) 9 // 定义一个中间函数,用于作为继承的中间值 10 var fun = function () {} 11 var fBound = function (){ 12 let laterArgs = slice.call(arguments, 0) 13 return _this.apply(ctx, formerArgs.concat(laterArgs)) 14 } 15 // 先让 fun 的原型方法指向 _this 即原函数的原型方法,继承 _this 的属性 16 fun.prototype = _this.prototype 17 // 再将 fBound 即要返回的新函数的原型方法指向 fun 的实例化对象 18 // 这样,既能让 fBound 继承 _this 的属性,在修改其原型链时,又不会影响到 _this 的原型链 19 fBound.prototype = new fun() 20 return fBound 21 } 22 }
1px边框解决方案
1 .div::after { 2 content: ''; 3 width: 200%; 4 height: 200%; 5 position: absolute; 6 top: 0; 7 left: 0; 8 border: 1px solid #bfbfbf; 9 border-radius: 4px; 10 -webkit-transform: scale(0.5,0.5); 11 transform: scale(0.5,0.5); 12 -webkit-transform-origin: top left; 13 }
Map数据结构
它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
map()方法
map()是数组的一个方法,它创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。map()里面的处理函数接受三个参数,分别指代当前元素、当前元素的索引、数组本身。
1 /**** 原生map() ****/ 2 var arrTmp = [1,2,3]; 3 var arrDouble = arrTmp.map(function(num){ 4 return num*2; 5 }) 6 // arrDouble -> [2,4,6] 7 8 //注意,使用map()时实际传递了3个参数: 9 arr.map(function(currentValue, index, array){ 10 // currentValue -> 数组中正在处理的当前元素 11 // index -> 数组中正在处理的当前元素的索引 12 // array -> 指向map方法被调用的数组 13 }) 14 15 ["1", "2", "3.5"].map(parseInt); // 结果不是[1, 2, 3],而是[1, NaN, NaN] 16 ["1", "2", "3.5"].map(function(num){ return parseInt(num)}); //得到正确结果[1, 2, 3] 17 18 //使用map()重组数组 19 var kvArray = [{key: 1, value: 10}, {key: 2, value: 20}, {key: 3, value: 30}]; 20 var reformattedArray = kvArray.map(function(obj) { var rObj = {}; rObj[obj.key] = obj.value; return rObj; }); 21 // kvArray不变,reformattedArray -> [{1: 10}, {2: 20}, {3: 30}],
扩展运算符
自定义事件(MDN)
你了解前端路由吗?
1 class Routers { 2 constructor() { 3 this.routes = {}; 4 this.currentUrl = ''; 5 this.refresh = this.refresh.bind(this); 6 window.addEventListener('load', this.refresh, false); 7 window.addEventListener('hashchange', this.refresh, false); 8 } 9 10 route(path, callback) { 11 this.routes[path] = callback || function() {}; 12 } 13 14 refresh() { 15 this.currentUrl = location.hash.slice(1) || '/'; 16 this.routes[this.currentUrl](); 17 } 18 } 19 20 window.Router = new Routers(); 21 var content = document.querySelector('body'); 22 // change Page anything 23 function changeBgColor(color) { 24 content.style.backgroundColor = color; 25 } 26 Router.route('/', function() { 27 changeBgColor('yellow'); 28 }); 29 Router.route('/blue', function() { 30 changeBgColor('blue'); 31 }); 32 Router.route('/green', function() { 33 changeBgColor('green'); 34 });
1 class Routers { 2 constructor() { 3 this.routes = {}; 4 // 在初始化时监听popstate事件 5 this._bindPopState(); 6 } 7 // 初始化路由 8 init(path) { 9 history.replaceState({path: path}, null, path); 10 this.routes[path] && this.routes[path](); 11 } 12 // 将路径和对应回调函数加入hashMap储存 13 route(path, callback) { 14 this.routes[path] = callback || function() {}; 15 } 16 17 // 触发路由对应回调 18 go(path) { 19 history.pushState({path: path}, null, path); 20 this.routes[path] && this.routes[path](); 21 } 22 // 监听popstate事件 23 _bindPopState() { 24 window.addEventListener('popstate', e => { 25 const path = e.state && e.state.path; 26 this.routes[path] && this.routes[path](); 27 }); 28 } 29 }
请你实现一个深克隆
阮一峰版的快速排序完全是错的
XSS 中文名为跨站脚本, 是发生在目标用户的浏览器层面上的,当渲染DOM树的过程成发生了不在预期内执行的JS代码时,就发生了XSS攻击。
既然React/Vue可以用Event Bus进行组件通信,你可以实现下吗?
class EventEmeitter { constructor() { this._events = this._events || new Map(); // 储存事件/回调键值对 this._maxListeners = this._maxListeners || 10; // 设立监听上限 } } // 触发名为type的事件 EventEmeitter.prototype.emit = function(type, ...args) { let handler; // 从储存事件键值对的this._events中获取对应事件回调函数 handler = this._events.get(type); if (args.length > 0) { handler.apply(this, args); } else { handler.call(this); } return true; }; // 监听名为type的事件 EventEmeitter.prototype.addListener = function(type, fn) { // 将type事件以及对应的fn函数放入this._events中储存 if (!this._events.get(type)) { this._events.set(type, fn); } };