面试
1.实现一个函数,判断其是不是会文字符串
function run(input){ if(typeof input !=="string") return false return input.split("").reverse().join("")==input }
2.用两种以上方式实现垂直水平居中
.wrapper{ position:relative; .box{ position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); } } .wrapper{ .box{ disaplay:flex; justify-content:center; align-itemscenter; height:100px; } } .wapper{ display:table; .box{ display:table-cell; vertical-align:middle; } }
3.实现一个点击父元素的区域不包含子区域事件效果
<ul id="ul" style="height:200px;"> <li id="li" style="height:100px;background-color: aquamarine;"></li> </ul> </body> <script> var ul = document.getElementById("ul") var li = document.getElementById("li") ul.onclick = function (e) { e = e || window.event if (e.target.tagName.toLowerCase() != "li") { li.style.background = "yellow" console.log(1); } } </script>
4.请你简单的实现一个双向绑定
<input id="input" /> <script> const data = {}; const input = document.getElementById('input'); Object.defineProperty(data, 'text', { set(value) { input.value = value; this.value = value; console.log(this); } }); input.onchange = function (e) { data.text = e.target.value; } </script>
5.实现Storage,使得该对象为单例,并对localStorage进行封装设置值setItem(key,value)和getItem(key)
var instance = null; class Storage { static getInstance() { if (!instance) { instance = new Storage(); } return instance; } setItem = (key, value) => localStorage.setItem(key, value), getItem = key => localStorage.getItem(key) }
ps:类(class)通过static 关键字定义静态方法,不能再类的实例上调用静态方法,而应通过类本身调用
lass ClassWithStaticMethod { static staticMethod() { return 'static method has been called.'; } } console.log(ClassWithStaticMethod.staticMethod()); // expected output: "static method has been called."
6.form中的input可以设置readyonly和disable,请问二者有什么区别
readyonly不可编辑,但可以选择复制,只可以传递到后台,disabled不能编辑,不能选择,不能复制,之不可传到后台
7.清楚浮动的几种方法
-
给父元素定义高度
-
给父级元素添加overflow:hidden;
-
给浮动元素最后添加一个空的块级元素,并给该块级元素添加{clear:both}
-
给父级元素添加伪元素
.clearfix:after{ content:"."; diaplay:block; height:0; visibility:hidden; clear:both; }
8.src 与href的区别
1.src指向外部资源的位置,指向的内容将会被嵌入到文档中当前标签所在的位置,在请求src资源时会将其指向资源下载并应用到文档中
2.href建立文档链接
9.阐释下面代码执行结果
<script> if (a in window) { var a = 'hello js'; } console.log(a) </script>
解:if并不是一个代码块
1.进行预解析代码,观察到有一个变量声明
2.预解析结束开始执行代码
3.log=>hello.js
console.log( func ); var func = 123; console.log( func ); function func() { console.log( 'Hello js' ); }
解:
变量和函数同时变量同时提升,函数声明是后来上的覆盖了前面的变量提升所以第一个func打印出来的是函数体//
开行运行,之后123又赋值给func所以第二个func打印的是123
ps:先执行变量提升,后面的覆盖前面的,然后一句一句执行
10.比较下面两个代码
function func1 ( num ) { console.log( num ); var num = 456; console.log( num ); } var num = 123; func1( num ); //分析 //1. 进行预解析,观察声明有两个,一个函数声明func1,一个是变量声明var num // func1被预解析记录,并与函数体相连 // var num 被记录 //2. 预解析结束,开始执行代码 // 执行第一句话为:num = 123,对num进行赋值 // 调用func1( num ); // 在进入函数体前,开辟函数内存需要的内存空间,将函数的参数var num = 123进行声明 // 进入函数体,开始执行预解析,观察到有个var num,重复声明,忽略 // 执行函数体,第一个console.log( num ) => 123 // num = 456,对num进行赋值 // 第二个console.log( num ) => 456 // 函数执行结束,回到外层
function func2 () { console.log( num ); var num = 456; console.log( num ); } var num = 123; func2( num ); //分析 //1. 进行预解析, 观察到有两个声明, func2和var num // func2被记录,并与函数体相连 // var num被记录 //2. 预解析结束,开始执行代码 // 执行num = 123,对num进行赋值 // 调用func( num ) // 进入函数体,进行预解析, 记录var num // 执行第一个console.log( num ) => undefined // 执行赋值语句, num = 456 // 执行第二个console.log( num ) => 456
解:同样是两个代码但是一个要求传入形参,一个不要形参为什么差别这么大?其原因在于,形参相当于在函数体中直接使用这个,然后直接套用就好,但是函数内部也有一个预解析()所以会发生变量提升,并且,函数内部的变量一旦发现自己有,就不会向上级索要(闭包)
function func3 () { console.log( num ); num = 456; console.log( num ); } var num = 123; func3( num ); console.log( num ); //分析 //1. 进行预解析, 观察到有两个声明,func3和var num // func3被记录,并与函数体相连 // var num被记录 //2. 预解析借宿,开始执行代码 // num = 123,进行赋值 // 调用func3( num ) // 进入函数体,进行预解析,无需要记录对象,预解析结束 // 执行第一个console.log( num ) => 此时函数的局部作用域内无num,向全局中找,全局num = 123 => 123 // num = 456,进行赋值操作 => 更改全局中的num = 456 // 执行第二个console.log( num ) => 456 // 函数执行完毕,执行第三个console.log( num ) => 456
var num = 123; function f1 () { console.log( num ); } function f2 () { var num = 456; f1(); } f2(); console.log( num ); //分析 //1. 进行预解析,观察到有3个声明,两个函数声明,一个变量声明 // var num被记录 // f1被记录,并与函数体相连 // f2被记录,并与函数体相连 //2. 预解析结束,开始执行代码 // num = 123,进行赋值 // 调用f2(); // 进入f2函数体内,进行预解析, var num被记录 // 进行赋值操作 num = 456 // 调用f1() // 进入f1函数体内,进行预解析,无需要记录对象,预解析结束 // 执行第一个console.log( num ) => 函数体内无num, 向全局作用查找, 全局num = 123 => 123 // 函数执行完毕 // 执行第二个console.log( num ) => 123
解:服了,在函数体中var声明是一个局部变量,不声明反而是一个全局变量
f2(); var num = 123; function f1 () { console.log( num ); } function f2 () { var num = 456; f1(); } console.log( num ); //1. 进行预解析,观察到有3个声明,两个函数声明,一个变量声明 // var num被记录 // f1被记录,并与函数体相连 // f2被记录,并与函数体相连 //2. 预解析结束,开始执行代码 // 调用f2() // 进入f2函数体内,进行预解析, var num被记录 // 进行赋值num = 456 // 调用f1() // 进入f1函数体内,执行第一个console.log( num ) =>函数体内无num,向全局作用域查找,此时num = undefined => undefined // 函数执行完毕 // num = 123,进行赋值 // 执行第二个console.log( num ) => num = 123
11.驼峰命名规则
将骆驼命名规则的字符串转换成使用短横线命名法的字符串, 并且全小写 .例如: 'getElementById'
=> 'get-element-by-id'
function getKebabCase ( str ) { var arr = str.split(''); str = arr.map(function ( item ){ if( item.toUpperCase() === item ){ return '-' + item.toLowerCase(); }else{ return item; } }).join( '' ); return str; } console.log( getKebabCase( 'getElementById' ) ); //get-element-by-id
12.哪些操作会造成内存泄露
内存泄露是指向系统申请了内存后不能释放,使得这片内存不能再被重新申请,以下的操作会造成内存泄露
1.当页面中的元素被移除或替换时,若元素绑定的事件没有被移除,在ie中不会做出处理,此时要手工移除事件,不然会造成内存泄露
2.在IE中,如果循环引用的对象是dom节点,会造成内存泄露
3.闭包时构成循环引用会造成内存泄露
3.在ie中,自动类型转换会造成内存泄露
13.chrome 浏览器中文界面下默认会将小于12px的文本强制按照12px显示,可以通过加入css样式
-webkit-text-size-adjust: none; 解决。
14.盒模型
.IE盒模型:margin content (包含border,padding)
.w3c盒模型:margin,border,padding,content
css3中的box-sizing 属性就是这两种模式,border-box(ie);content-box(w3c)
15.请分别封装添加事件和移除事件的函数,用以解决兼容性问题
function addEvent(ele,eventName,handler){ if(ele.attachEvent){ ele.attachEvent("on"+eventName,function(){ handler.call(ele) //此处使用回调函数call(),让this指向ele }) else if(ele.removeEventListener){ ele.removeEventListener(eventName,handler,false); } } }
16.写一个function,清楚字符串前后的空格(兼容所有浏览器)
if(!String.prototype.trim){ String.prototype.trim=function(){ retun this.replace(/^\s+/,'').replace(/\s+$/,''); } }
17.请写一个函数,用来实现对象的深拷贝
function deepClone(obj){ return JSON.parse(JSON.stringify(obj)) }
18.移动端有哪些原生触摸事件
touch类: touchstart, touchmove, touchend, touchcancel
tap类: tap, longTap, singleTap, doubleTap
swipe类: swipe, swipeLeft, swipeRight, swipeUp, swipeDown
17.请将一个url的search部分参数值与值转换成一个json对象
function getSearch(search){ var item var result={} if(search.indexOf("&)<0){ item=search.split("=") result[item[0]]=item[1]; return JSON.stringify(result) }else{ var splitArray=search.split("&"); for(var i=0;i<splitArray.length;i++){ item=splitArray[i].split("=") result[item[0]]=item[1] } return JSON.stringify(result); } }
19.采用最少的遍历方式完成以下数组的去重
var arr=[ 1, 2, 3, 3, 4, 6, 6, 12, 12] var result=[]; var obj={}; for(let i=0;i<arr.length;i++){ if(!obj[arr[i]]){ obj[arr[i]]=true; result.push(arr[i]); } }
20.请简述下什么是同源策略
同源策略是Netscape公司提出的一个安全策略, 所有支持JavaScript的浏览器都会运用到这个安全策略. 所谓的同源是指域名,协议和端口都一致.只有当同源的情况下,才可以读取Cookie, LocalStorage和IndexDB,发送Ajax请求.浏览器这样做的目的是保证用户的数据安全.
21.简述event.stopImmediatePropagation和event.stopPropagation的不同
event.stopImmediatePropagation:阻止冒泡,且阻止该元素其他同类事件只会触发一次
event.stopPropagation:阻止事件冒泡
document.querySelector("p").addEventListener("click", function(event) { alert("我是p元素上被绑定的第一个监听函数"); }, false); document.querySelector("p").addEventListener("click", function(event) { alert("我是p元素上被绑定的第二个监听函数"); event.stopImmediatePropagation(); //执行stopImmediatePropagation方法,阻止click事件冒泡,并且阻止p元素上绑定的其他click事件的事件监听函数的执行. }, false); document.querySelector("p").addEventListener("click", function(event) { alert("我是p元素上被绑定的第三个监听函数"); //该监听函数排在上个函数后面,该函数不会被执行. }, false); document.querySelector("div").addEventListener("click", function(event) { alert("我是div元素,我是p元素的上层元素"); //p元素的click事件没有向上冒泡,该函数不会被执行. }, false);
22.闭包必须return出来,然后调用,此外闭包是在外函数中申明的所以通过作用域链访问到外层的变量,那么如果我不是在外函数声明的,而是与外函数平级声明,那么此时是不能访问到外函数的变量的,解决方法,用形参,把外函数变量当做形参传进来,然后在里面调用