JavaScript面试题集锦
1.js基础
1.eval是做什么的?
它的功能是把对应的字符串解析成JS代码并运行;
应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。
由JSON字符串转换为JSON对象的时候可以用eval,var obj =eval(‘(‘+ str +’)’);
2.什么是window对象? 什么是document对象?
window对象是指浏览器打开的窗口。
document对象是Document对象(HTML 文档对象)的一个只读引用,window对象的一个属性。
3.null,undefined 的区别?。
null 表示一个对象是“没有值”的值,也就是值为“空”;
undefined 表示一个变量声明了没有初始化(赋值);
undefined不是一个有效的JSON,而null是;
undefined的类型(typeof)是undefined;
null的类型(typeof)是object;
Javascript将未赋值的变量默认值设为undefined;
Javascript从来不会将变量设为null。它是用来让程序员表明某个用var声明的变量时没有值的。
typeof undefined
//"undefined"
undefined :是一个表示"无"的原始值或者说表示"缺少值",就是此处应该有一个值,但是还没有定义。当尝试读取时会返回 undefined;
例如变量被声明了,但没有赋值时,就等于undefined
typeof null
//"object"
null : 是一个对象(空对象, 没有任何属性和方法);
例如作为函数的参数,表示该函数的参数不是对象;
注意:
在验证null时,一定要使用 === ,因为 == 无法分别 null 和 undefined
null == undefined // true
null === undefined // false
再来一个例子:
null
Q:有张三这个人么?
A:有!
Q:张三有房子么?
A:没有!
undefined
Q:有张三这个人么?
A:有!
Q: 张三有多少岁?
A: 不知道(没有被告诉)
[“1”, “2”, “3”].map(parseInt) 答案是多少?
parseInt() 函数能解析一个字符串,并返回一个整数,需要两个参数 (val, radix),
其中 radix 表示要解析的数字的基数。【该值介于 2 ~ 36 之间,并且字符串中的数字不能大于radix才能正确返回数字结果值】;
但此处 map 传了 3 个 (element, index, array),我们重写parseInt函数测试一下是否符合上面的规则。
function parseInt(str, radix) {
return str+'-'+radix;
};
var a=[“1”, “2”, “3”];
a.map(parseInt); // [“1-0”, “2-1”, “3-2”] 不能大于radix
因为二进制里面,没有数字3,导致出现超范围的radix赋值和不合法的进制解析,才会返回NaN
所以[“1”, “2”, “3”].map(parseInt) 答案也就是:[1, NaN, NaN]
5.事件是?IE与火狐的事件机制有什么区别? 如何阻止冒泡?
1. 我们在网页中的某个操作(有的操作对应多个事件)。例如:当我们点击一个按钮就会产生一个事件。是可以被 JavaScript 侦测到的行为。
事件处理机制:I.E.是事件冒泡、Firefox同时支持两种事件模型,也就是:捕获型事件和冒泡型事件;
ev.stopPropagation();(旧ie的方法 ev.cancelBubble = true;)
6.javascript 代码中的”use strict”;是什么意思 ? 使用它区别是什么?
use strict是一种ECMAscript 5 添加的(严格)运行模式,这种模式使得 Javascript 在更严格的条件下运行,
使JS编码更加规范化的模式,消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为。
默认支持的糟糕特性都会被禁用,比如不能用with,也不能在意外的情况下给全局变量赋值;
全局变量的显示声明,函数必须声明在顶层,不允许在非函数代码块内声明函数,arguments.callee也不允许使用;
消除代码运行的一些不安全之处,保证代码运行的安全,限制函数中的arguments修改,严格模式下的eval函数的行为和非严格模式的也不相同;
提高编译器效率,增加运行速度;
为未来新版本的Javascript标准化做铺垫。
7.Javascript中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是?
hasOwnProperty
javaScript中hasOwnProperty函数方法是返回一个布尔值,指出一个对象是否具有指定名称的属性。此方法无法检查该对象的原型链中是否具有该属性;该属性必须是对象本身的一个成员。
使用方法:
object.hasOwnProperty(proName)
其中参数object是必选项。一个对象的实例。
proName是必选项。一个属性名称的字符串值。
如果 object 具有指定名称的属性,那么JavaScript中hasOwnProperty函数方法返回 true,反之则返回 false。
8.JSON 的了解?
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小
如:{“age”:”12”, “name”:”back”}
JSON字符串转换为JSON对象:
var obj =eval(‘(‘+ str +’)’);
var obj = str.parseJSON();
var obj = JSON.parse(str);
JSON对象转换为JSON字符串:
var last=obj.toJSONString();
var last=JSON.stringify(obj);
9.js延迟加载的方式有哪些?
defer和async、动态创建DOM方式(用得最多)、按需异步载入js
10.如何判断当前脚本运行在浏览器还是node环境中?(阿里)
this === window ? ‘browser’ : ‘node’;
通过判断Global对象是否为window,如果不为window,当前脚本没有运行在浏览器中
11.javascript的typeof返回哪些数据类型
alert(typeof [1, 2]); //object
alert(typeof 'leipeng'); //string
var i = true;
alert(typeof i); //boolean
alert(typeof 1); //number
var a;
alert(typeof a); //undefined
function a(){;};
alert(typeof a) //function
12.例举3种强制类型转换和2种隐式类型转换?
强制(parseInt(),parseFloat(),Number())
隐式(== ,!=)
13.split() 、join() 的区别
前者是切割成数组的形式,后者是将数组转换成字符串
14.数组方法pop() push() unshift() shift()
push()尾部添加 pop()尾部删除
unshift()头部添加 shift()头部删除
map() : 遍历数组中的元素, 返回一个新数组(包含回调函数返回的数据)
filter():遍历数组中的元素, 返回一个新数组(包含回调函数返回true的元素)
15.事件绑定和普通事件有什么区别
1) 普通添加事件的方法:
var btn = document.getElementById(“hello”);
btn.onclick = function(){
alert(1);
}
btn.onclick = function(){
alert(2);
}
执行上面的代码只会alert 2
事件绑定方式添加事件:
var btn = document.getElementById(“hello”);
btn.addEventListener(“click”,function(){
alert(1);
},false);
btn.addEventListener(“click”,function(){
alert(2);
},false);
执行上面的代码会先alert 1 再 alert 2
普通添加事件的方法不支持添加多个事件,最下面的事件会覆盖上面的,而事件绑定 (addEventListener)方式添加事件可以添加多个。
addEventListener不兼容低版本IE
普通事件无法取消
addEventLisntener还支持事件冒泡+事件捕获
IE和DOM事件流的区别
1.执行顺序不一样、
2.参数不一样
3.事件加不加on
4.this指向问题
17.IE和标准下有哪些兼容性的写法
var ev = ev || window.event
document.documentElement.clientWidth || document.body.clientWidth
var target = ev.srcElement||ev.target
18.如何阻止事件冒泡和事件默认行为
//阻止事件冒泡
if(typeof ev.stopPropagation==’function’) { //标准的
ev.stopPropagation();
} else { //非标准IE
window.event.cancelBubble = true;
}
//阻止事件默认行为
return false
window.onload 和document ready的区别
window.onload 是在dom文档树加载完和所有文件加载完之后执行一个函数 document.ready原生中没有这个方法,jquery中有 $().ready(function),在dom文档树加 载完之后执行一个函数(注意,这里面的文档树加载完不代表全部文件加载完)。
$(document).ready要比window.onload先执行
window.onload只能出来一次,$(document).ready可以出现多次
20.”==”和“===”的不同
前者会自动转换类型
后者不会
21.JavaScript是一门什么样的语言,它有哪些特点?
javaScript一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML网页上使用,用来给HTML网页增加动态功能。JavaScript兼容于ECMA标准,因此也称为ECMAScript。
基本特点
是一种解释性脚本语言(代码不进行预编译)。
主要用来向HTML(标准通用标记语言下的一个应用)页面添加交互行为。
可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。
跨平台特性,在绝大多数浏览器的支持下,可以在多种平台下运行(如Windows、Linux、Mac、Android、iOS等)。
22.JavaScript的数据类型都有什么?
基本数据类型:String,boolean,Number,Undefined, Null
引用数据类型:Object, Array, Function
那么问题来了,如何判断某变量是否为数组数据类型?
方法一.判断其是否具有“数组性质”,如slice()方法。可自己给该变量定义slice方法, 故有时会失效
方法二.obj instanceof Array 在某些IE版本中不正确
方法三.方法一二皆有漏洞,在ECMA Script5中定义了新方法Array.isArray(), 保证其兼容 性,最好的方法如下:
if(typeof Array.isArray==="undefined"){
Array.isArray = function(arg){
return Object.prototype.toString.call(arg)==="[object Array]"
};
}
23.当一个DOM节点被点击时候,我们希望能够执行一个函数,应该怎么做?
直接在DOM里绑定事件:
在JS里通过onclick绑定:xxx.onclick = test
通过事件添加进行绑定:addEventListener(xxx, ‘click’, test)
那么问题来了,Javascript的事件流模型都有什么?
“事件冒泡”:事件开始由最具体的元素接受,然后逐级向上传播
“事件捕捉”:事件由最不具体的节点先接收,然后逐级向下,一直到最具体的
“DOM事件流”:三个阶段:事件捕捉,目标阶段,事件冒泡
24.看下列代码输出为何?解释原因。
var a;
alert(typeof a); // undefined
alert(b); // 报错
解释:Undefined是一个只有一个值的数据类型,这个值就是“undefined”,在使用var 声明变量但并未对其赋值进行初始化时,这个变量的值就是undefined。而b由于未声 明将报错。注意未申明的变量和声明了未赋值的是不一样的。
25.看下列代码,输出什么?解释原因。
var undefined;
undefined == null; // true
1 == true; // true
2 == true; // false
0 == false; // true
0 == ‘’; // true
NaN == NaN; // false
[] == false; // true
[] == ![]; // true // true == false 打印false
undefined与null相等,但不恒等(===)
一个是number一个是string时,会尝试将string转换为number
尝试将boolean转换为number,0或1
尝试将Object转换成number或string,取决于另外一个对比量的类型
所以,对于0、空字符串的判断,建议使用 “===” 。“===”会先判断两边的值类型, 类型不匹配时为false。
那么问题来了,看下面的代码,输出什么,foo的值为什么?
var foo = “11”+2-“1”;
console.log(foo);
console.log(typeof foo);
执行完后foo的值为111,foo的类型为String。
已知数组 var stringArr = [“This”,“ is”, “Baidu”, “Campus” ], Alert出 “This is Baidu Campus”;
alert(stringArray.join(“”))
已知有字符串foo=”get-element-by-id”,写一个function将其转化成驼峰表示法”getElementById”
function combo(msg){
var arr=msg.split("-");
for(var i=1;i<arr.length;i++){
arr[i]=arr[i].charAt(0).toUpperCase()+arr[i]
.substr(1,arr[i].length-1);
}
msg=arr.join("");
return msg;
}
输出今天的日期,以YYYY-MM-DD的方式,比如今天是2014年9月26日,则输出2014-09-26
var d = new Date();
// 获取年,getFullYear()返回4位的数字
var year = d.getFullYear();
// 获取月,月份比较特殊,0是1月,11是12月
var month = d.getMonth() + 1;
var d = new Date();
// 获取年,getFullYear()返回4位的数字
var year = d.getFullYear();
// 获取月,月份比较特殊,0是1月,11是12月
var month = d.getMonth() + 1;
将字符串”{$id}{$name}”中的{$id}替换成10,{$name}替换成Tony (使用正则表达式)
“{$id}{$id}_{$name}“.replace(/{\$id}/g, ‘10’).replace(/{\$name}/g, ‘Tony’);
为了保证页面输出安全,我们经常需要对一些特殊的字符进行转义,请写一个函数escapeHtml,将<, >, &, “进行转义
function escapeHtml(str) {
return str.replace(/[<>”&]/g, function(match) {
switch (match) {
case “<”:
return “<”;
case “>”:
return “>”;
case “&”:
return “&”;
case “\””:
return “"”;
}
});
}
foo = foo||bar ,这行代码是什么意思?为什么要这样写?
如果foo存在,值不变,否则把bar的值赋给foo。
短路表达式:作为”&&”和”||”操作符的操作数表达式,这些表达式在进行求值时, 只要最终的结果已经可以确定是真或假,求值过程便告终止,这称之为短路求值。
看下列代码,将会输出什么?(变量声明提升)
var foo = 1;
(function(){
console.log(foo);
var foo = 2;
console.log(foo);
})()
答案:输出undefined 和 2。上面代码相当于:
var foo = 1;
(function(){
var foo;
console.log(foo); //undefined
foo = 2;
console.log(foo); // 2;
})()
函数声明与变量声明会被JavaScript引擎隐式地提升到当前作用域的顶部,但是只提升名称不会提升赋值部分。
用js实现随机选取10–100之间的10个数字,存入一个数组,并排序。
function randomNub(aArray, len, min, max) {
if (len >= (max - min)) {
return '超过' + min + '-' + max + '之间的个数范围' + (max - min - 1) + '个的总数';
}
if (aArray.length >= len) {
aArray.sort(function(a, b) {
return a - b
});
return aArray;
}
var nowNub = parseInt(Math.random() * (max - min - 1)) + (min + 1);
for (var j = 0; j < aArray.length; j++) {
if (nowNub == aArray[j]) {
randomNub(aArray, len, min, max);
return;
}
}
aArray.push(nowNub);
randomNub(aArray, len, min, max);
return aArray;
var arr=[];
randomNub(arr,10,10,100);
34.把两个数组合并,并删除第二个元素。
var array1 = [‘a’,’b’,’c’];
var bArray = [‘d’,’e’,’f’];
var cArray = array1.concat(bArray);
cArray.splice(1,1);
35.有这样一个URL:http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e,请写一段JS程序提取URL中的各个GET参数(参数名和参数个数不确定),将其按key-value形式返回到一个json结构中,如{a:’1′, b:’2′, c:”, d:’xxx’, e:undefined}。
function serilizeUrl(url) {
var urlObject = {};
if (/\?/.test(url)) {
var urlString = url.substring(url.indexOf("?") + 1);
var urlArray = urlString.split("&");
for (var i = 0, len = urlArray.length; i < len; i++) {
var urlItem = urlArray[i];
var item = urlItem.split("=");
urlObject[item[0]] = item[1];
}
return urlObject;
}
return null;
}
36.正则表达式构造函数var reg=new RegExp(“xxx”)与正则表达字面量var reg=//有什么不同?匹配邮箱的正则表达式?
当使用RegExp()构造函数的时候,不仅需要转义引号(即\”表示”),并且还需要双反斜杠(即\表示一个\)。使用正则表达字面量的效率更高。
邮箱的正则匹配:
var regMail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/;
37.写一个function,清除字符串前后的空格。
if (!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+/, "").replace(/\s+$/,"");
}
}
//测试
var str = “ \t\n test string “.trim();
alert(str == “test string”); // alerts “true”
38.以下两个变量a和b,a+b的哪个结果是NaN?
A、var a=undefined; b=NaN
B、var a= ‘123’; b=NaN X
C、var a =undefined , b =NaN
D、var a=NaN , b=’undefined’ X
39.下面的JavaScript语句中,( )实现检索当前页面中的表单元素中的所有文本框,并将它们全部清空
A. for(vari=0;i< form1.elements.length;i++) {
if(form1.elements.type==”text”)
form1.elements.value=””;}
B. for(vari=0;i<document.forms.length;i++) {
if(forms[0].elements.type==”text”)
forms[0].elements.value=””;
}
C. if(document.form.elements.type==”text”)
form.elements.value=””;
D. for(vari=0;i<document.forms.length; i++){
for(var j=0;j<document.forms.elements.length; j++){
if(document.forms.elements[j].type==”text”)
document.forms.elements[j].value=””;
}
}
40.typeof运算符返回值中有一个跟javascript数据类型不一致,它是?如何判断是不是数组?
Array,Array.isArray(data)
前端面试题:
1. 一个200*200的div在不同分辨率屏幕上下左右居中,用css实现
div
{
position:absolute;
width:200px;
height:200px;
top:50%;
left:50%;
margin-left:-100px;
height:-100px;
z-index:1000;
}
写一个左中右布局占满屏幕,其中左右两块是固定宽度200 ,中间自适应宽,要求先加载中间块,请写出结构及样式:
<h3>实现三列宽度自适应布局</h3> <div id = "left">我是左边</div> <div id = "right">我是右边</div> <div id = "center">我是中间</div>
html,body{ margin: 0px;width: 100%; }
h3{height: 100px;margin:20px 0 0;}
left,#right{width: 200px;height: 200px; background-color: #ffe6b8;position: absolute;top:120px;}
left{left:0px;}
right{right: 0px;}
center{margin:2px 210px ;background-color: #eee;height: 200px; }
- 阐述清楚浮动的几种方式(常见问题)
1.父级div定义 height
原理:父级div手动定义height,就解决了父级div无法自动获取到高度的问题。
优点:简单、代码少、容易掌握
缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级div不一样时,会产生问题
2.父级div定义 overflow:hidden
原理:必须定义width或zoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度
优点:简单、代码少、浏览器支持好
- 结尾处加空div标签 clear:both
原理:添加一个空div,利用css提高的clear:both清除浮动,让父级div能自动获取到高度
优点:简单、代码少、浏览器支持好、不容易出现怪问题
缺点:不少初学者不理解原理;如果页面浮动布局多,就要增加很多空div,让人感觉很不好
- 解释css sprites ,如何使用?
CSS Sprites其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位,background-position可以用数字能精确的定位出背景图片的位置。
CSS Sprites为一些大型的网站节约了带宽,让提高了用户的加载速度和用户体验,不需要加载更多的图片
- 如何用原生js给一个按钮绑定两个onclick事件?
Var btn=document.getElementById(‘btn’);
//事件监听 绑定多个事件
var btn4 = document.getElementById(“btn4”);
btn4.addEventListener(“click”,hello1);
btn4.addEventListener(“click”,hello2);
function hello1(){
alert(“hello 1”);
}
function hello2(){
alert(“hello 2”);
}
- 拖拽会用到哪些事件
· dragstart:拖拽开始时在被拖拽元素上触发此事件,监听器需要设置拖拽所需数据,从操作系统拖拽文件到浏览器时不触发此事件.
· dragenter:拖拽鼠标进入元素时在该元素上触发,用于给拖放元素设置视觉反馈,如高亮
· dragover:拖拽时鼠标在目标元素上移动时触发.监听器通过阻止浏览器默认行为设置元素为可拖放元素.
· dragleave:拖拽时鼠标移出目标元素时在目标元素上触发.此时监听器可以取消掉前面设置的视觉效果.
· drag:拖拽期间在被拖拽元素上连续触发
· drop:鼠标在拖放目标上释放时,在拖放目标上触发.此时监听器需要收集数据并且执行所需操作.如果是从操作系统拖放文件到浏览器,需要取消浏览器默认行为.
· dragend:鼠标在拖放目标上释放时,在拖拽元素上触发.将元素从浏览器拖放到操作系统时不会触发此事件.
- 请列举jquery中的选择器:
- Javascript中的定时器有哪些?他们的区别及用法是什么?
setTimeout 只执行一次
setInterval 会一直重复执行
9.请描述一下 cookies sessionStorage和localstorage区别
相同点:都存储在客户端
不同点:1.存储大小
· cookie数据大小不能超过4k。
· sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
2.有效时间
· localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
· sessionStorage 数据在当前浏览器窗口关闭后自动删除。
· cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
- 数据与服务器之间的交互方式
· cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端
· sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
10.计算一个数组arr所有元素的和
var arr1=[1,2,3,4,5,6,7,8,9];
var sum1=0;
for (var i=0;i<=arr1.length;i++) {
if (typeof arr1[i]==”number”) {
sum1+=arr1[i];
}
}
document.write(sum1);
//====================================
function sum2(arr){
var all=0;
for (var i=0;i<arr.length;i++) {
if (typeof arr[i]==”number”) {
all+=arr[i];
}
}
return all;
}
document.write(sum2([1,2,3,4]));
11.编写一个方法去掉数组里面 重复的内容 var arr=[1,2,3,4,5,1,2,3]
一个数组去重的简单实现
var arr = [‘abc’,’abcd’,’sss’,’2’,’d’,’t’,’2’,’ss’,’f’,’22’,’d’];
//定义一个新的数组
var s = [];
//遍历数组
for(var i = 0;i<arr.length;i++){
if(s.indexOf(arr[i]) == -1){ //判断在s数组中是否存在,不存在则push到s数组中
s.push(arr[i]);
}
}
console.log(s);
//输出结果:[“abc”, “abcd”, “sss”, “2”, “d”, “t”, “ss”, “f”, “22”]
方法二:用sort() 然后相邻比较也可以实现
12.document.write和innerHTML的区别:
document.write是直接写入到页面的内容流,如果在写之前没有调用document.open, 浏览器会自动调用open。每次写完关闭之后重新调用该函数,会导致页面被重写。
innerHTML则是DOM页面元素的一个属性,代表该元素的html内容。你可以精确到某一个具体的元素来进行更改。如果想修改document的内容,则需要修改document.documentElement.innerElement。
innerHTML将内容写入某个DOM节点,不会导致页面全部重绘
innerHTML很多情况下都优于document.write,其原因在于其允许更精确的控制要刷新页面的那一个部分。
13.ajax的步骤
什么是ajax?
ajax(异步javascript xml) 能够刷新局部网页数据而不是重新加载整个网页。
如何使用ajax?
第一步,创建xmlhttprequest对象,var xmlhttp =new XMLHttpRequest();XMLHttpRequest对象用来和服务器交换数据。
var xhttp;
if (window.XMLHttpRequest) {
//现代主流浏览器
xhttp = new XMLHttpRequest();
} else {
// 针对浏览器,比如IE5或IE6
xhttp = new ActiveXObject(“Microsoft.XMLHTTP”);
}
第二步,使用xmlhttprequest对象的open()和send()方法发送资源请求给服务器。
第三步,使用xmlhttprequest对象的responseText或responseXML属性获得服务器的响应。
第四步,onreadystatechange函数,当发送请求到服务器,我们想要服务器响应执行一些功能就需要使用onreadystatechange函数,每次xmlhttprequest对象的readyState发生改变都会触发onreadystatechange函数
14.xml和json的区别,请用四个词语来形容
· JSON相对于XML来讲,数据的体积小,传递的速度更快些
· JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互
· XML对数据描述性比较好;
· JSON的速度要远远快于XML
15.清楚浮动的方法?(多次出现在面试题)
1.父级div定义 height
原理:父级div手动定义height,就解决了父级div无法自动获取到高度的问题。
优点:简单、代码少、容易掌握
缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级div不一样时,会产生问题
2,结尾处加空div标签 clear:both
原理:添加一个空div,利用css提高的clear:both清除浮动,让父级div能自动获取到高度
优点:简单、代码少、浏览器支持好、不容易出现怪问题
缺点:不少初学者不理解原理;如果页面浮动布局多,就要增加很多空div,让人感觉很不好
3,父级div定义 伪类:after 和 zoom
原理:IE8以上和非IE浏览器才支持:after,原理和方法2有点类似,zoom(IE转有属性)可解决ie6,ie7浮动问题
优点:浏览器支持好、不容易出现怪问题(目前:大型网站都有使用,如:腾迅,网易,新浪等等)
缺点:代码多、不少初学者不理解原理,要两句代码结合使用才能让主流浏览器都支持
4,父级div定义 overflow:hidden
原理:必须定义width或zoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度
优点:简单、代码少、浏览器支持好
缺点:不能和position配合使用,因为超出的尺寸的会被隐藏。
16.box-sizing常用的属性有哪些?分别有什么作用?
属性值
· box-sizing:content-box
· box-sizing:border-box
· box-sizing:inherit
content-box
· 这是box-sizing的默认属性值
· 是CSS2.1中规定的宽度高度的显示行为
· 在CSS中定义的宽度和高度就对应到元素的内容框
· 在CSS中定义的宽度和高度之外绘制元素的内边距和边框
border-box
· 在CSS中微元素设定的宽度和高度就决定了元素的边框盒
· 即为元素在设置内边距和边框是在已经设定好的宽度和高度之内进行绘制
· CSS中设定的宽度和高度减去边框和内间距才能得到元素内容所占的实际宽度和高度
(Q1)box-sizing: content-box|border-box|inherit;
(Q2)content-box:宽度和高度分别应用到元素的内容框。在宽度和高度之外绘制元素的内边距和边框(元素默认效果)。
border-box:元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。
17.css选择器有哪些,选择器的权重的优先级
选择器类型
1、ID #id
2、class .class
3、标签 p
4、通用 *
5、属性 [type=”text”]
6、伪类 :hover
7、伪元素 ::first-line
8、子选择器、相邻选择器
三、权重计算规则
第一等:代表内联样式,如: style=””,权值为1000。
第二等:代表ID选择器,如:#content,权值为0100。
第三等:代表类,伪类和属性选择器,如.content,权值为0010。
第四等:代表类型选择器和伪元素选择器,如div p,权值为0001。
通配符、子选择器、相邻选择器等的。如*、>、+,权值为0000。
继承的样式没有权值。
块级元素水平垂直居中的方法有哪些(三个方法)
让div等块级元素水平和垂直都居中,即永远处于屏幕的正中央,当我们做如登录块时非常有用!
实现一、原理:要让div等块级元素水平和垂直居中,必需知道该div等块级元素的宽度和高度,然后设置位置为绝对位置,距离页面窗口左边框和上边框的距离设置为50%,这个50%就是指页面窗口的宽度和高度的50%,最后将该div等块级元素分别左移和上移,左移和上移的大小就是该div等块级元素宽度和高度的一半。
CSS代码:
.mycss{
width:300px;
height:200px;
position:absolute;
left:50%;
top:50%;
margin:-100px 0 0 -150px }
实现二原理:利用CSS的margin设置为auto让浏览器自己帮我们水平和垂直居中。
CSS代码:
.mycss{
position: absolute;
left: 0px;
right: 0;
top: 0;
bottom: 0;
margin: auto;
height: 200px;
width: 300px;
}
jQuery实现水平和垂直居中
原理:jQuery实现水平和垂直居中的原理就是通过jQuery设置div等块级元素的CSS,获取div等块级元素的左、上的边距偏移量,边距偏移量的算法就是用页面窗口 的宽度减去该div等块级元素的宽度,得到的值再除以2即左偏移量,右偏移量算法相同。注意div等块级元素的CSS设置要在resize()方法中完成,就是每次改变窗口大 小时,都要执行设置div等块级元素的CSS。
jquery代码:
$(window).resize(function(){
$(".myblock").css({
position: "absolute",
left: ($(window).width() - $(".myblock").outerWidth())/2,
top: ($(window).height() - $(".myblock").outerHeight())/2 });
});
此外在页面载入时,就需要调用resize()方法
$(function(){
$(window).resize();
});
19.三个盒子,左右定宽,中间自适应有几种方法
第一种:左右侧采用浮动 中间采用margin-left 和 margin-right 方法。
代码如下:
<div style="width:150px; float:left; background:#6FF">这是左侧的内容 固定宽度</div>
<div style="margin-left:150px;margin-right:200px; background-color:#9F3">中间内容,自适应宽度</div>
</div>
第二种:左右两侧采用绝对定位 中间同样采用margin-left margin-right方法:
第三种负的margin
使用这种方法就稍微复杂了一些了,使用的是负的margin值,而且html标签也增加了,先来看其代码吧:
main {
float: left;
width: 100%;
}
mainContainer {
margin: 0 230px;
height: 200px;
background: green;
}
left {
float: left;
margin-left: -100%;
width: 230px}
right {
float: left;
margin-left: -230px;
width: 230px;
}
left .inner,
right .inner {
background: orange;
margin: 0 10px;
height: 200px;
}
20.js有几种数据类型,其中基本数据类型有哪些
五种基本类型: Undefined、Null、Boolean、Number和String。
1中复杂的数据类型————Object,Object本质上是由一组无序的名值对组成的。
Object、Array和Function则属于引用类型
21.undefined 和 null 区别
null: Null类型,代表“空值”,代表一个空对象指针,使用typeof运算得到 “object”,所以你可以认为它是一个特殊的对象值。
undefined: Undefined类型,当一个声明了一个变量未初始化时,得到的就是undefined。
null是javascript的关键字,可以认为是对象类型,它是一个空对象指针,和其它语言一样都是代表“空值”,不过 undefined 却是javascript才有的。undefined是在ECMAScript第三版引入的,为了区分空指针对象和未初始化的变量,它是一个预定义的全局变量。没有返回值的函数返回为undefined,没有实参的形参也是undefined。
javaScript权威指南: null 和 undefined 都表示“值的空缺”,你可以认为undefined是表示系统级的、出乎意料的或类似错误的值的空缺,而null是表示程序级的、正常的或在意料之中的值的空缺。
22.http 和 https 有何区别?如何灵活使用?
http是HTTP协议运行在TCP之上。所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。
https是HTTP运行在SSL/TLS之上,SSL/TLS运行在TCP之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。此外客户端可以验证服务器端的身份,如果配置了客户端验证,服务器方也可以验证客户端的身份
23.常见的HTTP状态码
2开头 (请求成功)表示成功处理了请求的状态代码。
200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201 (已创建) 请求成功并且服务器创建了新的资源。
202 (已接受) 服务器已接受请求,但尚未处理。
203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206 (部分内容) 服务器成功处理了部分 GET 请求。
3开头 (请求被重定向)表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。
300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
4开头 (请求错误)这些状态代码表示请求可能出错,妨碍了服务器的处理。
400 (错误请求) 服务器不理解请求的语法。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
405 (方法禁用) 禁用请求中指定的方法。
406 (不接受) 无法使用请求的内容特性响应请求的网页。
407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408 (请求超时) 服务器等候请求时发生超时。
409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417 (未满足期望值) 服务器未满足”期望”请求标头字段的要求。
5开头(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。
500 (服务器内部错误) 服务器遇到错误,无法完成请求。
501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
如何进行网站性能优化
1. 从用户角度而言,优化能够让页面加载得更快、对用户的操作响应得更及时,能够给用户提供更为友好的体验。
2. 从服务商角度而言,优化能够减少页面请求数、或者减小请求所占带宽,能够节省可观的资源。
总之,恰当的优化不仅能够改善站点的用户体验并且能够节省相当的资源利用。
前端优化的途径有很多,按粒度大致可以分为两类,第一类是页面级别的优化,例如 HTTP请求数、脚本的无阻塞加载、内联脚本的位置优化等 ;第二类则是代码级别的优化,例如 Javascript中的DOM 操作优化、CSS选择符优化、图片优化以及 HTML结构优化等等。另外,本着提高投入产出比的目的,后文提到的各种优化策略大致按照投入产出比从大到小的顺序排列。
一、页面级优化
1. JavaScript 压缩和模块打包
2. 按需加载资源
3. 在使用 DOM 操作库时用上 array-ids
4. 缓存
5. 启用 HTTP/2
6. 应用性能分析
7. 使用负载均衡方案
8. 为了更快的启动时间考虑一下同构
9. 使用索引加速数据库查询
10. 使用更快的转译方案
11. 避免或最小化 JavaScript 和 CSS 的使用而阻塞渲染
12. 用于未来的一个建议:使用 service workers + 流
13. 图片编码优化react和vue有哪些不同,说说你对这两个框架的看法
相同点
· 都支持服务器端渲染
· 都有Virtual DOM,组件化开发,通过props参数进行父子组件数据的传递,都实现webComponent规范
· 数据驱动视图
· 都有支持native的方案,React的React native,Vue的weex
不同点
· React严格上只针对MVC的view层,Vue则是MVVM模式
· virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制
· 组件写法不一样, React推荐的做法是 JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即’all in js’; Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html,css,jd写在同一个文件;
· 数据绑定: vue实现了数据的双向绑定,react数据流动是单向的
· state对象在react应用中不可变的,需要使用setState方法更新状态;在vue中,state对象不是必须的,数据由data属性在vue对象中管理
26.什么是mvvm mvc是什么区别 原理
一、MVC(Model-View-Controller)
MVC是比较直观的架构模式,用户操作->View(负责接收用户的输入操作)->Controller(业务逻辑处理)->Model(数据持久化)->View(将结果反馈给View)。
MVC使用非常广泛,比如JavaEE中的SSH框架
三、MVVM(Model-View-ViewModel)
如果说MVP是对MVC的进一步改进,那么MVVM则是思想的完全变革。它是将“数据模型数据双向绑定”的思想作为核心,因此在View和Model之间没有联系,通过ViewModel进行交互,而且Model和ViewModel之间的交互是双向的,因此视图的数据的变化会同时修改数据源,而数据源数据的变化也会立即反应view。
27.px和em的区别
px表示像素 (计算机屏幕上的一个点:1px = 1/96in),是绝对单位,不会因为其他元素的尺寸变化而变化;
·
·
em表示相对于父元素的字体大小。em是相对单位 ,没有一个固定的度量值,而是由其他元素尺寸来决定的相对值。
28.优雅降级和渐进增强
渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行 hack 使其可以在低版本浏览器上正常浏览。
其实渐进增强和优雅降级并非什么新概念,只是旧的概念换了一个新的说法。在传统软件开发中,经常会提到向上兼容和向下兼容的概念。渐进增强相当于向上兼容,而优雅降级相当于向下兼容
29.eval()的作用
把字符串参数解析成JS代码并运行,并返回执行的结果;
eval(“2+3”);//执行加运算,并返回运算值。
eval(“varage=10”);//声明一个age变量
eval的作用域
functiona(){
eval(“var x=1”); //等效于 var x=1;
console.log(x); //输出1
}
a();
console.log(x);//错误 x没有定
- JS哪些操作会造成内存泄露
1)意外的全局变量引起的内存泄露
function leak(){
leak=”xxx”;//leak成为一个全局变量,不会被回收
}
2)闭包引起的内存泄露
3)3)没有清理的DOM元素引用
4)被遗忘的定时器或者回调 5)子元素存在引起的内存泄露
- 浏览器缓存有哪些,通常缓存有哪几种
一、http缓存
二、websql
cookie
localstorage
sessionstorage
flash缓存
32:bootstrap响应式实现的原理
百分比布局+媒体查询
33.关于JS事件冒泡与JS事件代理(事件委托)
事件作为DOM操作重要的一环,需要大家好好理解和运用,今天特意看了一下事件冒泡和事件代理的相关资料,感触颇深,也深感自己的无知不知道多浪费了多少内存,废话不多说进入正题:
1.事件冒泡:
通俗易懂的来讲,就是当一个子元素的事件被触发的时候(如onclick事件),该事件会从事件源(被点击的子元素)开始逐级向上传播,触发父级元素的点击事件。
2.事件委托
事件委托,首先按字面的意思就能看你出来,是将事件交由别人来执行,再联想到上面讲的事件冒泡,是不是想到了?对,就是将子元素的事件通过冒泡的形式交由父元素来执行。下面经过详细的例子来说明事件委托:
有可能在开发的时候会遇到这种情况:如导航每一个栏目都要加一个事件,你可能会通过遍历来给每个栏目添加事件:
事件委托是怎
var ul = document.getElementById(‘parentUl’);
ul.οnclick=function (event) {
var e = event||window.event,
source = e.target || e.srcElement;//target表示在事件冒泡中触发事件的源元素,在IE中是srcElement
if(source.nodeName.toLowerCase() == “li”){ //判断只有li触发的才会输出内容
alert(source.innerHTML);
}
stopPropagation(e); //阻止继续冒泡
};
function addElement() {
var li = document.createElement(‘li’);
li.innerHTML=”我是新孩子”;
ul.appendChild(li);
}
- CSS样式覆盖规则
规则一:由于继承而发生样式冲突时,最近祖先获胜。
规则二:继承的样式和直接指定的样式冲突时,直接指定的样式获胜
规则三:直接指定的样式发生冲突时,样式权值高者获胜。
样式的权值取决于样式的选择器,权值定义如下表。
CSS选择器
权值
标签选择器
1
类选择器
10
ID选择器
100
内联样式
1000
伪元素(:first-child等)
1
伪类(:link等)
10
可以看到,内联样式的权值>>ID选择器>>类选择器>>标签选择器,除此以外,后代选择器的权值为每项权值之和,比如”#nav .current a”的权值为100 + 10 + 1 = 111。
规则四:样式权值相同时,后者获胜。
规则五:!important的样式属性不被覆盖。
!important可以看做是万不得已的时候,打破上述四个规则的”金手指”。如果你一定要采用某个样式属性,而不让它被覆盖的,可以在属性值后加上!important,以规则四的例子为例,”.byline a {color:red !important;}”可以强行使链接显示红色。大多数情况下都可以通过其他方式来控制样式的覆盖,不能滥用!important。
- 介绍一下box-sizing属性
兼容问题
首先,box-sizing属性在FireFox中存在兼容问题,所以需要使用-moz-box-sizing做一下兼容。
属性值
· box-sizing:content-box
· box-sizing:border-box
· box-sizing:inherit
content-box
· 这是box-sizing的默认属性值
· 是CSS2.1中规定的宽度高度的显示行为
· 在CSS中定义的宽度和高度就对应到元素的内容框
· 在CSS中定义的宽度和高度之外绘制元素的内边距和边框
border-box
· 在CSS中微元素设定的宽度和高度就决定了元素的边框盒
· 即为元素在设置内边距和边框是在已经设定好的宽度和高度之内进行绘制
· CSS中设定的宽度和高度减去边框和内间距才能得到元素内容所占的实际宽度和高度
- css选择符有哪些?优先级算法如何计算?(常见)
37. 请简要描述margin重合问题,及解决方式
1.同向margin的重叠:
1图片的margin-top与3图片的margin-top发生重叠,2图片的margin-bottom与3图片的margin-bottom发生重叠。这时候重叠之后的margin值由发生重叠两片的最大值决定;如果其中一个出现负值,则由最大的正边距减去绝对值最大的负边距,如果没有最大正边距,则由0减去绝对值最大的负边距。
解决同向重叠的方法:
(1)在最外层的div中加入overflow:hidden;zoom:1
(2)在最外层加入padding:1px;属性
(3)在最外层加入:border:1px solid #cacbcc;
2.异向重叠问题:
1图片的margin-bottom与2图片的margin-top发生重叠,这时候重叠之后的margin值由发生重叠两图片的最大值的决定的。
解决异向重叠问题:
float:left(只能解决IE6浏览器中的异向重叠问题,可以解决IE8以上、chorme、firefox、opera下的同向重叠问题)
38:position的值,relative\absolute\fixed分别相对于进行谁定位,有什么区别,什么时候用?
39.解释下CSS sprites,以及你要如何在页面或网站中使用它。
CSS Sprites其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background-repeat”,“background-position”的组合进行背景定位,background-position可以用数字能精确的定位出背景图片的位置
40.什么是闭包,如何使用它,为什么要使用它?
包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
使用闭包的注意点:
· 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
· 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
41.请解释JSONP的工作原理,以及它为什么不是真正的AJAX。
JSONP (JSON with Padding)是一个简单高效的跨域方式,HTML中的script标签可以加载并执行其他域的javascript,于是我们可以通过script标记来动态加载其他域的资源。例如我要从域A的页面pageA加载域B的数据,那么在域B的页面pageB中我以JavaScript的形式声明pageA需要的数据,然后在 pageA中用script标签把pageB加载进来,那么pageB中的脚本就会得以执行。JSONP在此基础上加入了回调函数,pageB加载完之后会执行pageA中定义的函数,所需要的数据会以参数的形式传递给该函数。JSONP易于实现,但是也会存在一些安全隐患,如果第三方的脚本随意地执行,那么它就可以篡改页面内容,截获敏感数据。但是在受信任的双方传递数据,JSONP是非常合适的选择。
AJAX是不跨域的,而JSONP是一个是跨域的,还有就是二者接收参数形式不一样!
42.请解释一下JavaScript的同源策略。
在客户端编程语言中,如javascript和 ActionScript,同源策略是一个很重要的安全理念,它在保证数据的安全性方面有着重要的意义。同源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和操作另外一个域的绝大部分属性和方法。那么什么叫相同域,什么叫不同的域呢?当两个域具有相同的协议, 相同的端口,相同的host,那么我们就可以认为它们是相同的域。同源策略还应该对一些特殊情况做处理,比如限制file协议下脚本的访问权限。本地的HTML文件在浏览器中是通过file协议打开的,如果脚本能通过file协议访问到硬盘上其它任意文件,就会出现安全隐患,目前IE8还有这样的隐患。
43.怎样添加、移除、移动、复制、创建和查找节点?
1)创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
2)添加、移除、替换、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //插入
3)查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
44.谈谈垃圾回收机制方式及内存管理
回收机制方式
1、定义和用法:垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。
2、原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。
3、实例如下:
function fn1() {
var obj = {name: 'hanzichi', age: 10};
}
function fn2() {
var obj = {name:'hanzichi', age: 10};
return obj;
}var a = fn1();var b = fn2();
fn1中定义的obj为局部变量,而当调用结束后,出了fn1的环境,那么该块内存会被js引擎中的垃圾回收器自动释放;在fn2被调用的过程中,返回的对象被全局变量b所指向,所以该块内存并不会被释放。
4、垃圾回收策略:标记清除(较为常用)和引用计数。
标记清除:
定义和用法:当变量进入环境时,将变量标记”进入环境”,当变量离开环境时,标记为:”离开环境”。某一个时刻,垃圾回收器会过滤掉环境中的变量,以及被环境变量引用的变量,剩下的就是被视为准备回收的变量。
到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。
引用计数:
定义和用法:引用计数是跟踪记录每个值被引用的次数。
基本原理:就是变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象。
45、jQuery的事件委托方法bind 、live、delegate、on之间有什么区别?
(1)、bind 【jQuery 1.3之前】
定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数;
语法:bind(type,[data],function(eventObject));
特点:
(1)、适用于页面元素静态绑定。只能给调用它的时候已经存在的元素绑定事件,不能给未来新增的元素绑定事件。
(2)、当页面加载完的时候,你才可以进行bind(),所以可能产生效率问题。
实例如下:$( “#members li a” ).bind( “click”, function( e ) {} );
(2)、live 【jQuery 1.3之后】
定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数;
语法:live(type, [data], fn);
特点:
(1)、live方法并没有将监听器绑定到自己(this)身上,而是绑定到了this.context上了。
(2)、live正是利用了事件委托机制来完成事件的监听处理,把节点的处理委托给了document,新添加的元素不必再绑定一次监听器。
(3)、使用live()方法但却只能放在直接选择的元素后面,不能在层级比较深,连缀的DOM遍历方法后面使用,即$(“ul””).live…可以,但$(“body”).find(“ul”).live…不行;
实例如下:$( document ).on( “click”, “#members li a”, function( e ) {} );
(3)、delegate 【jQuery 1.4.2中引入】
定义和用法:将监听事件绑定在就近的父级元素上
语法:delegate(selector,type,[data],fn)
特点:
(1)、选择就近的父级元素,因为事件可以更快的冒泡上去,能够在第一时间进行处理。
(2)、更精确的小范围使用事件代理,性能优于.live()。可以用在动态添加的元素上。
实例如下:
$(“#info_table”).delegate(“td”,”click”,function(){/显示更多信息/});
$(“table”).find(“#info”).delegate(“td”,”click”,function(){/显示更多信息/});
(4)、on 【1.7版本整合了之前的三种方式的新事件绑定机制】
定义和用法:将监听事件绑定到指定元素上。
语法:on(type,[selector],[data],fn)
实例如下:$(“#info_table”).on(“click”,”td”,function(){/显示更多信息/});参数的位置写法与delegate不一样。
说明:on方法是当前JQuery推荐使用的事件绑定方法,附加只运行一次就删除函数的方法是one()。
总结:.bind(), .live(), .delegate(),.on()分别对应的相反事件为:.unbind(),.die(), .undelegate(),.off()
46、px和em的区别
相同点:px和em都是长度单位;
异同点:px的值是固定的,指定是多少就是多少,计算比较容易。em得值不是固定的,并且em会继承父级元素的字体大小。
浏览器的默认字体高都是16px。所以未经调整的浏览器都符合: 1em=16px。那么12px=0.75em, 10px=0.625em。
47、浏览器的内核分别是什么?
IE: trident内核
Firefox:gecko内核
Safari:webkit内核
Opera:以前是presto内核,Opera现已改用Google Chrome的Blink内核
Chrome:Blink(基于webkit,Google与Opera Software共同开发)
48、什么叫优雅降级和渐进增强?
渐进增强 progressive enhancement:
针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级 graceful degradation:
一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
区别:
a. 优雅降级是从复杂的现状开始,并试图减少用户体验的供给
b. 渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要
c. 降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带
49、sessionStorage 、localStorage 和 cookie 之间的区别
共同点:用于浏览器端存储的缓存数据
不同点:
(1)、存储内容是否发送到服务器端:当设置了Cookie后,数据会发送到服务器端,造成一定的宽带浪费;
web storage,会将数据保存到本地,不会造成宽带浪费;
(2)、数据存储大小不同:Cookie数据不能超过4K,适用于会话标识;web storage数据存储可以达到5M;
(3)、数据存储的有效期限不同:cookie只在设置了Cookid过期时间之前一直有效,即使关闭窗口或者浏览器;
sessionStorage,仅在关闭浏览器之前有效;localStorage,数据存储永久有效;
(4)、作用域不同:cookie和localStorage是在同源同窗口中都是共享的;sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;
50、浏览器是如何渲染页面的?
渲染的流程如下:
1.解析HTML文件,创建DOM树。
自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)。
2.解析CSS。优先级:浏览器默认设置<用户设置<外部样式<内联样式<HTML中的style样式;
3.将CSS与DOM合并,构建渲染树(Render Tree)
4.布局和绘制,重绘(repaint)和重排(reflow)
51:js的基本数据类型
JavaScript中有五种基本数据类型,它们分别是:undefined,null,boolean,number,string。
还有一种复杂数据类型-object。
52:事件委托
事件委托就是利用的DOM事件的事件捕获阶段。把具体dom上发生的事件,委托给更大范围的dom去处理。好比送信员,如果每次都把信件送给每一户,非常繁琐。但是如果交给一个大范围的管理者,比如小区的传达室,那么事情会变得非常简单。事件委托就类似这种原理,我页面中有很多按钮,如果不使用事件委托,我只能在每个按钮上注册事件。非常麻烦。但如果我把事件注册在一个大范围的div(假设所有的按钮都在这个div中),那么我只要注册一次事件,就可以处理所有按钮(只要按钮包含在上述div中)事件的响应了
53:CSS3新增了很多的属性,下面一起来分析一下新增的一些属性:
1.CSS3边框:
· border-radius:CSS3圆角边框。在 CSS2 中添加圆角矩形需要技巧,我们必须为每个圆角使用不同的图片,在 CSS3 中,创建圆角是非常容易的,在 CSS3 中,border-radius 属性用于创建圆角。border:2px solid;
· box-shadow:CSS3边框阴影。在 CSS3 中,box-shadow 用于向方框添加阴影。box-shadow:10px 10px 5px #888888;
· border-image:CSS3边框图片。通过 CSS3 的 border-image 属性,您可以使用图片来创建边框。border-image:url(border.png) 30 30 round;
2.CSS3背景:
· background-size: 属性规定背景图片的尺寸。在 CSS3 之前,背景图片的尺寸是由图片的实际尺寸决定的。在 CSS3 中,可以规定背景图片的尺寸,这就允许我们在不同的环境中重复使用背景图片。您能够以像素或百分比规定尺寸。如果以百分比规定尺寸,那么尺寸相对于父元素的宽度和高度。
· background-origin :属性规定背景图片的定位区域。背景图片可以放置于 content-box、padding-box 或 border-box 区域。
3.CSS3文字效果:
· text-shadow:在 CSS3 中,text-shadow 可向文本应用阴影。text-shadow:5px 5px 5px #FFFFFF;
· word-wrap :单词太长的话就可能无法超出某个区域,允许对长单词进行拆分,并换行到下一行:p{word-wrap:break-word;}
4.CSS3 2D转换:
transform:通过 CSS3 转换,我们能够对元素进行移动、缩放、转动、拉长或拉伸。
· translate():元素从其当前位置移动,根据给定的 left(x 坐标) 和 top(y 坐标) 位置参数:transform:translate(50px,100px);值 translate(50px,100px) 把元素从左侧移动 50 像素,从顶端移动 100 像素。
· rotate():元素顺时针旋转给定的角度。允许负值,元素将逆时针旋转。transform:rotate(30deg);值 rotate(30deg) 把元素顺时针旋转 30 度。
· scale():元素的尺寸会增加或减少,根据给定的宽度(X 轴)和高度(Y 轴)参数:transform:scale(2,4);值 scale(2,4) 把宽度转换为原始尺寸的 2 倍,把高度转换为原始高x() 5.CSS3 3D转换:
· rotateX():元素围绕其 X 轴以给定的度数进行旋转。transform:rotateX(120deg);
· rotateY():元素围绕其 Y 轴以给定的度数进行旋转。transform:rotateY(120deg);
6.CSS3 过渡:当元素从一种样式变换为另一种样式时为元素添加效果。
7.CSS3动画:通过 CSS3,我们能够创建动画,这可以在许多网页中取代动画图片、Flash 动画以及 JavaScript。
8.CSS3多列:
· column-count:属性规定元素应该被分隔的列数。
· column-gap:属性规定列之间的间隔。
· column-rule :属性设置列之间的宽度、样式和颜色规则。
9.CSS3用户界面:
· resize:属性规定是否可由用户调整元素尺寸。
· box-sizing:属性允许您以确切的方式定义适应某个区域的具体内容。
· outline-offset :属性对轮廓进行偏移,并在超出边框边缘的位置绘制轮廓。
54:从输入url到显示页面,都经历了什么
第一步:客户机提出域名解析请求,并将该请求发送给本地的域名服务器。
第二步:当本地的域名服务器收到请求后,就先查询本地的缓存,如果有该纪录项,则本地的域名服务器就直接把查询的结果返回。
第三步:如果本地的缓存中没有该纪录,则本地域名服务器就直接把请求发给根域名服务器,然后根域名服务器再返回给本地域名服务器一个所查询域(根的子域)的主域名服务器的地址。
第四步:本地服务器再向上一步返回的域名服务器发送请求,然后接受请求的服务器查询自己的缓存,如果没有该纪录,则返回相关的下级的域名服务器的地址。
第五步:重复第四步,直到找到正确的纪录。
第2种解释:
一般会经历以下几个过程:
1、首先,在浏览器地址栏中输入url
2、浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操作。
3、在发送http请求前,需要域名解析(DNS解析)(DNS(域名系统,Domain Name System)是互联网的一项核心服务,它作为可以将域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网,而不用去记住IP地址。),解析获取相应的IP地址。
4、浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。(TCP即传输控制协议。TCP连接是互联网连接协议集的一种。)
5、握手成功后,浏览器向服务器发送http请求,请求数据包。
6、服务器处理收到的请求,将数据返回至浏览器
7、浏览器收到HTTP响应
8、读取页面内容,浏览器渲染,解析html源码
9、生成Dom树、解析css样式、js交互
10、客户端和服务器交互
11、ajax查询
55:对标签有什么理解
什么是meta标签?
引自下W3school的定义说明一下。
元数据(metadata)是关于数据的信息。
标签提供关于 HTML 文档的元数据。元数据不会显示在页面上,但是对于机器是可读的。
典型的情况是,meta 元素被用于规定页面的描述、关键词、文档的作者、最后修改时间以及其他元数据。
标签始终位于 head 元素中。
元数据可用于浏览器(如何显示内容或重新加载页面),搜索引擎(关键词),或其他 web 服务。
其实对上面的概念简单总结下就是: 标签提供关于 HTML 文档的元数据。它不会显示在页面上,但是对于机器是可读的。可用于浏览器(如何显示内容或重新加载页面),搜索引擎(关键词),或其他 web 服务。
meta的作用
meta里的数据是供机器解读的,告诉机器该如何解析这个页面,还有一个用途是可以添加服务器发送到浏览器的http头部内容
56:new操作符到底到了什么
先看代码
[javascript] view plain copy
var Func=function(){
};
var func=new Func ();
new共经过了4几个阶段
1、创建一个空对象
[javascript] view plain copy
- varobj=new Object();
2、设置原型链
[javascript] view plain copy
- obj.proto= Func.prototype;
3、让Func中的this指向obj,并执行Func的函数体。
[javascript] view plain copy
- var result =Func.call(obj);
4、判断Func的返回值类型:
如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象。
[javascript] view plain copy
if (typeof(result) == “object”){
func=result;
}
else{
func=obj;;
}
57:h5新特性
HTML5新特性 —— 新特性
(1)新的语义标签和属性
(2)表单新特性
(3)视频和音频
(4)Canvas绘图
(5)SVG绘图
(6)地理定位
(7)拖放API
58:vue的生命周期
58:请写出你对闭包的理解,并列出简单的理解
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
闭包有三个特性:
1.函数嵌套函数
2.函数内部可以引用外部的参数和变量
3.参数和变量不会被垃圾回收机制回收
59:display none visibility hidden区别?
1.display:none是彻底消失,不在文档流中占位,浏览器也不会解析该元素;visibility:hidden是视觉上消失了,可以理解为透明度为0的效果,在文档流中占位,浏览器会解析该元素;
2.使用visibility:hidden比display:none性能上要好,display:none切换显示时visibility,页面产生回流(当页面中的一部分元素需要改变规模尺寸、布局、显示隐藏等,页面重新构建,此时就是回流。所有页面第一次加载时需要产生一次回流),而visibility切换是否显示时则不会引起回流。
60:JavaScript中如何检测一个变量是一个String类型?请写出函数实现
typeof(obj) === “string”
typeof obj === “string”
obj.constructor === String
61:如何理解闭包?
1、定义和用法:当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,如果返回的这个函数在外部被执行,就产生了闭包。
2、表现形式:使函数外部能够调用函数内部定义的变量。
3、实例如下:
(1)、根据作用域链的规则,底层作用域没有声明的变量,会向上一级找,找到就返回,没找到就一直找,直到window的变量,没有就返回undefined。这里明显count 是函数内部的flag2 的那个count 。
var count=10; //全局作用域 标记为flag1function add(){
var count=0; //函数全局作用域 标记为flag2
return function(){
count+=1; //函数的内部作用域 alert(count);
}
}var s = add()
s();//输出1
s();//输出2
4、变量的作用域
要理解闭包,首先必须理解Javascript特殊的变量作用域。
变量的作用域分类:全局变量和局部变量。
特点:
1、函数内部可以读取函数外部的全局变量;在函数外部无法读取函数内的局部变量。
2、函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!
5、使用闭包的注意点
1)滥用闭包,会造成内存泄漏:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)会改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
62:谈谈垃圾回收机制方式及内存管理
回收机制方式
1、定义和用法:垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。
2、原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。
3、实例如下:
function fn1() {
var obj = {name: 'hanzichi', age: 10};
}
function fn2() {
var obj = {name:'hanzichi', age: 10};
return obj;
}var a = fn1();var b = fn2();
fn1中定义的obj为局部变量,而当调用结束后,出了fn1的环境,那么该块内存会被js引擎中的垃圾回收器自动释放;在fn2被调用的过程中,返回的对象被全局变量b所指向,所以该块内存并不会被释放。
4、垃圾回收策略:标记清除(较为常用)和引用计数。
标记清除:
定义和用法:当变量进入环境时,将变量标记”进入环境”,当变量离开环境时,标记为:”离开环境”。某一个时刻,垃圾回收器会过滤掉环境中的变量,以及被环境变量引用的变量,剩下的就是被视为准备回收的变量。
到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。
引用计数:
定义和用法:引用计数是跟踪记录每个值被引用的次数。
基本原理:就是变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象。
63:判断一个字符串中出现次数最多的字符,统计这个次数
var str = ‘asdfssaaasasasasaa’;
var json = {};
for (var i = 0; i < str.length; i++) {
if(!json[str.charAt(i)]){
json[str.charAt(i)] = 1;
}else{
json[str.charAt(i)]++;
}
};var iMax = 0;var iIndex = ‘’;for(var i in json){
if(json[i]>iMax){
iMax = json[i];
iIndex = i;
}
} console.log(‘出现次数最多的是:’+iIndex+’出现’+iMax+’次’);
64、$(document).ready()方法和window.onload有什么区别?
(1)、window.onload方法是在网页中所有的元素(包括元素的所有关联文件)完全加载到浏览器后才执行的。
(2)、$(document).ready() 方法可以在DOM载入就绪时就对其进行操纵,并调用执行绑定的函数。
65、 jquery中$.get()提交和$.post()提交有区别吗?
相同点:都是异步请求的方式来获取服务端的数据;
异同点:
1、请求方式不同:$.get() 方法使用GET方法来进行异步请求的。$.post() 方法使用POST方法来进行异步请求的。
2、参数传递方式不同:get请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器的,这种传递是对用户不可见的。
3、数据传输大小不同:get方式传输的数据大小不能超过2KB 而POST要大的多
4、安全问题: GET 方式请求的数据会被浏览器缓存起来,因此有安全问题。
66、jQuery的事件委托方法bind 、live、delegate、on之间有什么区别?(常见)
(1)、bind 【jQuery 1.3之前】
定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数;
语法:bind(type,[data],function(eventObject));
特点:
(1)、适用于页面元素静态绑定。只能给调用它的时候已经存在的元素绑定事件,不能给未来新增的元素绑定事件。
(2)、当页面加载完的时候,你才可以进行bind(),所以可能产生效率问题。
实例如下:$( “#members li a” ).bind( “click”, function( e ) {} );
(2)、live 【jQuery 1.3之后】
定义和用法:主要用于给选择到的元素上绑定特定事件类型的监听函数;
语法:live(type, [data], fn);
特点:
(1)、live方法并没有将监听器绑定到自己(this)身上,而是绑定到了this.context上了。
(2)、live正是利用了事件委托机制来完成事件的监听处理,把节点的处理委托给了document,新添加的元素不必再绑定一次监听器。
(3)、使用live()方法但却只能放在直接选择的元素后面,不能在层级比较深,连缀的DOM遍历方法后面使用,即$(“ul””).live…可以,但$(“body”).find(“ul”).live…不行;
实例如下:$( document ).on( “click”, “#members li a”, function( e ) {} );
(3)、delegate 【jQuery 1.4.2中引入】
定义和用法:将监听事件绑定在就近的父级元素上
语法:delegate(selector,type,[data],fn)
特点:
(1)、选择就近的父级元素,因为事件可以更快的冒泡上去,能够在第一时间进行处理。
(2)、更精确的小范围使用事件代理,性能优于.live()。可以用在动态添加的元素上。
实例如下:
$(“#info_table”).delegate(“td”,”click”,function(){/显示更多信息/});
$(“table”).find(“#info”).delegate(“td”,”click”,function(){/显示更多信息/});
(4)、on 【1.7版本整合了之前的三种方式的新事件绑定机制】
定义和用法:将监听事件绑定到指定元素上。
语法:on(type,[selector],[data],fn)
实例如下:$(“#info_table”).on(“click”,”td”,function(){/显示更多信息/});参数的位置写法与delegate不一样。
说明:on方法是当前JQuery推荐使用的事件绑定方法,附加只运行一次就删除函数的方法是one()。
总结:.bind(), .live(), .delegate(),.on()分别对应的相反事件为:.unbind(),.die(), .undelegate(),.off()
67、px和em的区别(常见)
相同点:px和em都是长度单位;
异同点:px的值是固定的,指定是多少就是多少,计算比较容易。em得值不是固定的,并且em会继承父级元素的字体大小。
浏览器的默认字体高都是16px。所以未经调整的浏览器都符合: 1em=16px。那么12px=0.75em, 10px=0.625em。
68、浏览器的内核分别是什么?
IE: trident内核
Firefox:gecko内核
Safari:webkit内核
Opera:以前是presto内核,Opera现已改用Google Chrome的Blink内核
Chrome:Blink(基于webkit,Google与Opera Software共同开发)
69、什么叫优雅降级和渐进增强?(常见)
渐进增强 progressive enhancement:
针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级 graceful degradation:
一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
区别:
a. 优雅降级是从复杂的现状开始,并试图减少用户体验的供给
b. 渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要
c. 降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带
70、sessionStorage 、localStorage 和 cookie 之间的区别(常见)
共同点:用于浏览器端存储的缓存数据
不同点:
(1)、存储内容是否发送到服务器端:当设置了Cookie后,数据会发送到服务器端,造成一定的宽带浪费;
web storage,会将数据保存到本地,不会造成宽带浪费;
(2)、数据存储大小不同:Cookie数据不能超过4K,适用于会话标识;web storage数据存储可以达到5M;
(3)、数据存储的有效期限不同:cookie只在设置了Cookid过期时间之前一直有效,即使关闭窗口或者浏览器;
sessionStorage,仅在关闭浏览器之前有效;localStorage,数据存储永久有效;
(4)、作用域不同:cookie和localStorage是在同源同窗口中都是共享的;sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;
————————————————
版权声明:本文为CSDN博主「小胖梅」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xm1037782843/article/details/80708533
**position的值, relative和absolute分别是相对于谁进行定位的?
§ absolute :生成绝对定位的元素, 相对于最近一级的 定位不是 static 的父元素来进行定位。
§ fixed (老IE不支持)生成绝对定位的元素,通常相对于浏览器窗口或 frame 进行定位。
§ relative 生成相对定位的元素,相对于其在普通流中的位置进行定位。
§ static 默认值。没有定位,元素出现在正常的流中
§ sticky 生成粘性定位的元素,容器的位置根据正常文档流计算得出
如何解决跨域问题
JSONP:
原理是:动态插入script标签,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。
由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求。
优点是兼容性好,简单易用,支持浏览器与服务器双向通信。缺点是只支持GET请求。
JSONP:json+padding(内填充),顾名思义,就是把JSON填充到一个盒子里
CORS:
服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
通过修改document.domain来跨子域
将子域和主域的document.domain设为同一个主域.前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域
主域相同的使用document.domain
使用window.name来进行跨域
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的
使用HTML5中新引进的window.postMessage方法来跨域传送数据
还有flash、在服务器上设置代理页面等跨域方式。个人认为window.name的方法既不复杂,也能兼容到几乎所有浏览器,这真是极好的一种跨域方法。
XML和JSON的区别?
(1).数据体积方面。
JSON相对于XML来讲,数据的体积小,传递的速度更快些。
(2).数据交互方面。
JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互。
(3).数据描述方面。
JSON对数据的描述性比XML较差。
(4).传输速度方面。
JSON的速度要远远快于XML。
谈谈你对webpack的看法
WebPack 是一个模块打包工具,你可以使用WebPack管理你的模块依赖,并编绎输出模块们所需的静态文件。它能够很好地管理、打包Web开发中所用到的HTML、JavaScript、CSS以及各种静态文件(图片、字体等),让开发过程更加高效。对于不同类型的资源,webpack有对应的模块加载器。webpack模块打包器会分析模块间的依赖关系,最后 生成了优化且合并后的静态资源。
webpack的两大特色:
1.code splitting(可以自动完成)
2.loader 可以处理各种类型的静态文件,并且支持串联操作
webpack 是以commonJS的形式来书写脚本滴,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。
webpack具有requireJs和browserify的功能,但仍有很多自己的新特性:
1. 对 CommonJS 、 AMD、ES6的语法做了兼容
2. 对js、css、图片等资源文件都支持打包
3. 串联式模块加载器以及插件机制,让其具有更好的灵活性和扩展性,例如提供对CoffeeScript、ES6的支持
4. 有独立的配置文件webpack.config.js
5. 可以将代码切割成不同的chunk,实现按需加载,降低了初始化时间
6. 支持 SourceUrls 和SourceMaps,易于调试
7. 具有强大的Plugin接口,大多是内部插件,使用起来比较灵活
8.webpack 使用异步 IO 并具有多级缓存。这使得 webpack 很快且在增量编译上更加快
说说TCP传输的三次握手四次挥手策略
为了准确无误地把数据送达目标处,TCP协议采用了三次握手策略。用TCP协议把数据包送出去后,TCP不会对传送 后的情况置之不理,它一定会向对方确认是否成功送达。握手过程中使用了TCP的标志:SYN和ACK。
发送端首先发送一个带SYN标志的数据包给对方。接收端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息。 最后,发送端再回传一个带ACK标志的数据包,代表“握手”结束。 若在握手过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包。
断开一个TCP连接则需要“四次握手”:
§ 第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不 会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可 以接受数据。
§ 第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。
§ 第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。
§ 第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。
TCP和UDP的区别
TCP(Transmission Control Protocol,传输控制协议)是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接。一个TCP连接必须要经过三次“对话”才能建立起来
UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去!
UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境。
说说你对作用域链的理解
作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。
创建ajax过程
(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
(3)设置响应HTTP请求状态变化的函数.
(4)发送HTTP请求.
(5)获取异步调用返回的数据.
(6)使用JavaScript和DOM实现局部刷新.
渐进增强和优雅降级
渐进增强 :针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级 :一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
常见web安全及防护原理
sql注入原理
就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
总的来说有以下几点:
1.永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双”-“进行转换等。
2.永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。
3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4.不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息。
XSS原理及防范
Xss(cross-site scripting)攻击指的是攻击者往Web页面里插入恶意 html标签或者javascript代码。比如:攻击者在论坛中放一个
看似安全的链接,骗取用户点击后,窃取cookie中的用户私密信息;或者攻击者在论坛中加一个恶意表单,
当用户提交表单的时候,却把信息传送到攻击者的服务器中,而不是用户原本以为的信任站点。
XSS防范方法
首先代码里对用户输入的地方和变量都需要仔细检查长度和对”<”,”>”,”;”,”’”等字符做过滤;其次任何内容写到页面之前都必须加以encode,避免不小心把html tag 弄出来。这一个层面做好,至少可以堵住超过一半的XSS 攻击。
首先,避免直接在cookie 中泄露用户隐私,例如email、密码等等。
其次,通过使cookie 和系统ip 绑定来降低cookie 泄露后的危险。这样攻击者得到的cookie 没有实际价值,不可能拿来重放。
如果网站不需要再浏览器端对cookie 进行操作,可以在Set-Cookie 末尾加上HttpOnly 来防止javascript 代码直接获取cookie 。
尽量采用POST 而非GET 提交表单
XSS与CSRF有什么区别吗?
XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。
要完成一次CSRF攻击,受害者必须依次完成两个步骤:
登录受信任网站A,并在本地生成Cookie。
在不登出A的情况下,访问危险网站B。
CSRF的防御
§ 服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。
§ 通过验证码的方法
Web Worker 和webSocket
worker主线程:
1.通过 worker = new Worker( url ) 加载一个JS文件来创建一个worker,同时返回一个worker实例。
2.通过worker.postMessage( data) 方法来向worker发送数据。
3.绑定worker.onmessage方法来接收worker发送过来的数据。
4.可以使用 worker.terminate() 来终止一个worker的执行。
WebSocket是Web应用程序的传输协议,它提供了双向的,按序到达的数据流。他是一个Html5协议,WebSocket的连接是持久的,他通过在客户端和服务器之间保持双工连接,服务器的更新可以被及时推送给客户端,而不需要客户端以一定时间间隔去轮询。
HTTP和HTTPS
HTTP协议通常承载于TCP协议之上,在HTTP和TCP之间添加一个安全协议层(SSL或TSL),这个时候,就成了我们常说的HTTPS。
默认HTTP的端口号为80,HTTPS的端口号为443。
为什么HTTPS安全
因为网络请求需要中间有很多的服务器路由器的转发。中间的节点都可能篡改信息,而如果使用HTTPS,密钥在你和终点站才有。https之所以比http安全,是因为他利用ssl/tls协议传输。它包含证书,卸载,流量转发,负载均衡,页面适配,浏览器适配,refer传递等。保障了传输过程的安全性
对前端模块化的认识
AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
AMD 是提前执行,CMD 是延迟执行。
AMD推荐的风格通过返回一个对象做为模块对象,CommonJS的风格通过对module.exports或exports的属性赋值来达到暴露模块对象的目的。
CMD模块方式
define(function(require, exports,module) {
// 模块代码
});
Javascript垃圾回收方法
标记清除(mark and sweep)
这是JavaScript最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”。
垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了
引用计数(reference counting)
在低版本IE中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1,当这个值的引用次数变为0的时 候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间。
在IE中虽然JavaScript对象通过标记清除的方式进行垃圾回收,但BOM与DOM对象却是通过引用计数回收垃圾的,
也就是说只要涉及BOM及DOM就会出现循环引用问题。
你觉得前端工程的价值体现在哪
为简化用户使用提供技术支持(交互部分)
为多个浏览器兼容性提供支持
为提高用户浏览速度(浏览器性能)提供支持
为跨平台或者其他基于webkit或其他渲染引擎的应用提供支持
为展示数据提供支持(数据接口)
谈谈性能优化问题
代码层面:避免使用css表达式,避免使用高级选择器,通配选择器。
缓存利用:缓存Ajax,使用CDN,使用外部js和css文件以便缓存,添加Expires头,服务端配置Etag,减少DNS查找等
请求数量:合并样式和脚本,使用css图片精灵,初始首屏之外的图片资源按需加载,静态资源延迟加载。
请求带宽:压缩文件,开启GZIP,
代码层面的优化
用hash-table来优化查找
少用全局变量
用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能
用setTimeout来避免页面失去响应
缓存DOM节点查找的结果
避免使用CSS Expression
避免全局查询
避免使用with(with会创建自己的作用域,会增加作用域链长度)
多个变量声明合并
避免图片和iFrame等的空Src。空Src会重新加载当前页面,影响速度和效率
尽量避免写在HTML标签中写Style属性
移动端性能优化
尽量使用css3动画,开启硬件加速。
适当使用touch事件代替click事件。
避免使用css3渐变阴影效果。
可以用transform: translateZ(0)来开启硬件加速。
不滥用Float。Float在渲染时计算量比较大,尽量减少使用
不滥用Web字体。Web字体需要下载,解析,重绘当前页面,尽量减少使用。
合理使用requestAnimationFrame动画代替setTimeout
CSS中的属性(CSS3 transitions、CSS3 3D transforms、Opacity、Canvas、WebGL、Video)会触发GPU渲染,请合理使用。过渡使用会引发手机过耗电增加
PC端的在移动端同样适用
相关阅读:如何做到一秒渲染一个移动页面
什么是Etag?
当发送一个服务器请求时,浏览器首先会进行缓存过期判断。浏览器根据缓存过期时间判断缓存文件是否过期。
情景一:若没有过期,则不向服务器发送请求,直接使用缓存中的结果,此时我们在浏览器控制台中可以看到 200 OK(from cache) ,此时的情况就是完全使用缓存,浏览器和服务器没有任何交互的。
情景二:若已过期,则向服务器发送请求,此时请求中会带上①中设置的文件修改时间,和Etag
然后,进行资源更新判断。服务器根据浏览器传过来的文件修改时间,判断自浏览器上一次请求之后,文件是不是没有被修改过;根据Etag,判断文件内容自上一次请求之后,有没有发生变化
情形一:若两种判断的结论都是文件没有被修改过,则服务器就不给浏览器发index.html的内容了,直接告诉它,文件没有被修改过,你用你那边的缓存吧—— 304 Not Modified,此时浏览器就会从本地缓存中获取index.html的内容。此时的情况叫协议缓存,浏览器和服务器之间有一次请求交互。
情形二:若修改时间和文件内容判断有任意一个没有通过,则服务器会受理此次请求,之后的操作同①
① 只有get请求会被缓存,post请求不会
Expires和Cache-Control
Expires要求客户端和服务端的时钟严格同步。HTTP1.1引入Cache-Control来克服Expires头的限制。如果max-age和Expires同时出现,则max-age有更高的优先级。
Cache-Control:no-cache, private, max-age=0
ETag: abcde
Expires: Thu, 15 Apr 201420:00:00 GMT
Pragma: private
Last-Modified:$now //RFC1123 format
ETag应用:
Etag由服务器端生成,客户端通过If-Match或者说If-None-Match这个条件判断请求来验证资源是否修改。常见的是使用If-None-Match。请求一个文件的流程可能如下:
====第一次请求===
1.客户端发起 HTTP GET 请求一个文件;
2.服务器处理请求,返回文件内容和一堆Header,当然包括Etag(例如”2e681a-6-5d044840”)(假设服务器支持Etag生成和已经开启了Etag).状态码200
====第二次请求===
客户端发起 HTTP GET 请求一个文件,注意这个时候客户端同时发送一个If-None-Match头,这个头的内容就是第一次请求时服务器返回的Etag:2e681a-6-5d0448402.服务器判断发送过来的Etag和计算出来的Etag匹配,因此If-None-Match为False,不返回200,返回304,客户端继续使用本地缓存;流程很简单,问题是,如果服务器又设置了Cache-Control:max-age和Expires呢,怎么办
答案是同时使用,也就是说在完全匹配If-Modified-Since和If-None-Match即检查完修改时间和Etag之后,
服务器才能返回304.(不要陷入到底使用谁的问题怪圈)
为什么使用Etag请求头?
Etag 主要为了解决 Last-Modified 无法解决的一些问题。
栈和队列的区别?
栈的插入和删除操作都是在一端进行的,而队列的操作却是在两端进行的。
队列先进先出,栈先进后出。
栈只允许在表尾一端进行插入和删除,而队列只允许在表尾一端进行插入,在表头一端进行删除
栈和堆的区别?
栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。
堆(数据结构):堆可以被看成是一棵树,如:堆排序;
栈(数据结构):一种先进后出的数据结构。
快速 排序的思想并实现一个快排?
“快速排序”的思想很简单,整个排序过程只需要三步:
(1)在数据集之中,找一个基准点
(2)建立两个数组,分别存储左边和右边的数组
(3)利用递归进行下次比较
functionquickSort(arr){
if(arr.length<=1){
return arr;//如果数组只有一个数,就直接返回;
}
var num = Math.floor(arr.length/2);//找到中间数的索引值,如果是浮点数,则向下取整
var numValue =arr.splice(num,1);//找到中间数的值
var left = [];
var right = [];
for(var i=0;i
}
else{
right.push(arr[i]);//基准点的右边的数传到右边数组
}
}
returnquickSort(left).concat([numValue],quickSort(right));//递归不断重复比较
}
alert(quickSort([32,45,37,16,2,87]));//弹出“2,16,32,37,45,87”
你觉得jQuery或zepto源码有哪些写的好的地方
(答案仅供参考)
jQuery源码封装在一个匿名函数的自执行环境中,有助于防止变量的全局污染,然后通过传入window对象参数,可以使window对象作为局部变量使用,好处是当jquery中访问window对象的时候,就不用将作用域链退回到顶层作用域了,从而可以更快的访问window对象。同样,传入undefined参数,可以缩短查找undefined时的作用域链。
(function( window, undefined ) {
//用一个函数域包起来,就是所谓的沙箱
//在这里边var定义的变量,属于这个函数域内的局部变量,避免污染全局
//把当前沙箱需要的外部变量通过函数参数引入进来
//只要保证参数对内提供的接口的一致性,你还可以随意替换传进来的这个参数
window.jQuery = window.$ = jQuery;
})( window );
jquery将一些原型属性和方法封装在了jquery.prototype中,为了缩短名称,又赋值给了jquery.fn,这是很形象的写法。
有一些数组或对象的方法经常能使用到,jQuery将其保存为局部变量以提高访问速度。
jquery实现的链式调用可以节约代码,所返回的都是同一个对象,可以提高代码效率。
ES6的了解
新增模板字符串(为JavaScript提供了简单的字符串插值功能)、箭头函数(操作符左边为输入的参数,而右边则是进行的操作以及返回的值Inputs=>outputs。)、for-of(用来遍历数据—例如数组中的值。)arguments对象可被不定参数和默认参数完美代替。ES6将promise对象纳入规范,提供了原生的Promise对象。增加了let和const命令,用来声明变量。增加了块级作用域。let命令实际上就增加了块级作用域。ES6规定,var命令和function命令声明的全局变量,属于全局对象的属性;let命令、const命令、class命令声明的全局变量,不属于全局对象的属性。。还有就是引入module模块的概念
js继承方式及其优缺点
原型链继承的缺点
一是字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。
借用构造函数(类式继承)
借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起。所以我们需要原型链+借用构造函数的模式,这种模式称为组合继承
组合式继承
组合式继承是比较常用的一种继承方法,其背后的思路是 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性。
关于Http 2.0 你知道多少?
HTTP/2引入了“服务端推(server push)”的概念,它允许服务端在客户端需要数据之前就主动地将数据发送到客户端缓存中,从而提高性能。
HTTP/2提供更多的加密支持
HTTP/2使用多路技术,允许多个消息在一个连接上同时交差。
它增加了头压缩(header compression),因此即使非常小的请求,其请求和响应的header都只会占用很小比例的带宽。
defer和async
defer并行加载js文件,会按照页面上script标签的顺序执行
async并行加载js文件,下载完成立即执行,不会按照页面上script标签的顺序执行
谈谈浮动和清除浮动
浮动的框可以向左或向右移动,直到他的外边缘碰到包含框或另一个浮动框的边框为止。由于浮动框不在文档的普通流中,所以文档的普通流的块框表现得就像浮动框不存在一样。浮动的块框会漂浮在文档普通流的块框上。
如何评价AngularJS和BackboneJS
backbone具有依赖性,依赖underscore.js。Backbone + Underscore + jQuery(or Zepto) 就比一个AngularJS 多出了2 次HTTP请求.
Backbone的Model没有与UI视图数据绑定,而是需要在View中自行操作DOM来更新或读取UI数据。AngularJS与此相反,Model直接与UI视图绑定,Model与UI视图的关系,通过directive封装,AngularJS内置的通用directive,就能实现大部分操作了,也就是说,基本不必关心Model与UI视图的关系,直接操作Model就行了,UI视图自动更新。
AngularJS的directive,你输入特定数据,他就能输出相应UI视图。是一个比较完善的前端MVW框架,包含模板,数据双向绑定,路由,模块化,服务,依赖注入等所有功能,模板功能强大丰富,并且是声明式的,自带了丰富的 Angular 指令。
用过哪些设计模式?
工厂模式:
主要好处就是可以消除对象间的耦合,通过使用工程方法而不是new关键字。将所有实例化的代码集中在一个位置防止代码重复。
工厂模式解决了重复实例化的问题 ,但还有一个问题,那就是识别问题,因为根本无法搞清楚他们到底是哪个对象的实例。
function createObject(name,age,profession){//集中实例化的函数var obj = newObject();
obj.name =name;
obj.age = age;
obj.profession= profession;
obj.move =function () {
returnthis.name + ‘ at ‘ + this.age + ‘ engaged in ‘ + this.profession;
};
return obj;
}
var test1 = createObject(‘trigkit4’,22,’programmer’);//第一个实例var test2 =createObject(‘mike’,25,’engineer’);//第二个实例
构造函数模式
使用构造函数的方法 ,即解决了重复实例化的问题 ,又解决了对象识别的问题,该模式与工厂模式的不同之处在于:
1.构造函数方法没有显示的创建对象 (new Object());
2.直接将属性和方法赋值给 this 对象;
3.没有 renturn 语句。
说说你对闭包的理解
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念
闭包有三个特性:
1.函数嵌套函数
2.函数内部可以引用外部的参数和变量
3.参数和变量不会被垃圾回收机制回收
请你谈谈Cookie的弊端
cookie虽然在持久保存客户端数据提供了方便,分担了服务器存储的负担,但还是有很多局限性的。
第一:每个特定的域名下最多生成20个cookie
1.IE6或更低版本最多20个cookie
2.IE7和之后的版本最后可以有50个cookie。
3.Firefox最多50个cookie
4.chrome和Safari没有做硬性限制
IE和Opera 会清理近期最少使用的cookie,Firefox会随机清理cookie。
cookie的最大大约为4096字节,为了兼容性,一般不能超过4095字节。
IE 提供了一种存储可以持久化用户数据,叫做userdata,从IE5.0就开始支持。每个数据最多128K,每个域名下最多1M。这个持久化数据放在缓存中,如果缓存没有清理,那么会一直存在。
优点:极高的扩展性和可用性
1.通过良好的编程,控制保存在cookie中的session对象的大小。
2.通过加密和安全传输技术(SSL),减少cookie被破解的可能性。
3.只在cookie中存放不敏感数据,即使被盗也不会有重大损失。
4.控制cookie的生命期,使之不会永远有效。偷盗者很可能拿到一个过期的cookie。
缺点:
1.Cookie数量和长度的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉.
2.安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。即使加密也与事无补,因为拦截者并不需要知道cookie的意义,他只要原样转发cookie就可以达到目的了。
3.有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。
浏览器本地存储
在较高版本的浏览器中,js提供了sessionStorage和globalStorage。在HTML5中提供了localStorage来取代globalStorage。
html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage。
sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。
而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。
web storage和cookie的区别
Web Storage的概念和cookie相似,区别是它是为了更大容量存储设计的。Cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可以跨域调用。
除此之外,Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie。
但是cookie也是不可以或缺的:cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生
浏览器的支持除了IE7及以下不支持外,其他标准浏览器都完全支持(ie及FF需在web服务器里运行),值得一提的是IE总是办好事,例如IE7、IE6中的userData其实就是javascript本地存储的解决方案。通过简单的代码封装可以统一到所有的浏览器都支持web storage。
localStorage和sessionStorage都具有相同的操作方法,例如setItem、getItem和removeItem等
cookie 和session 的区别:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中
display:none和visibility:hidden的区别?
display:none 隐藏对应的元素,在文档布局中不再给它分配空间,它各边的元素会合拢,就当他从来不存在。
visibility:hidden 隐藏对应的元素,但是在文档布局中仍保留原来的空间。
CSS中link 和@import的区别是?
(1) link属于HTML标签,而@import是CSS提供的;
(2) 页面被加载的时,link会同时被加载,而@import被引用的CSS会等到引用它的CSS文件被加载完再加载;
(3) import只在IE5以上才能识别,而link是HTML标签,无兼容问题;
(4) link方式的样式的权重 高于@import的权重.
position:absolute和float属性的异同
§ 共同点:对内联元素设置float和absolute属性,可以让元素脱离文档流,并且可以设置其宽高。
§ 不同点:float仍会占据位置,absolute会覆盖文档流中的其他元素。
介绍一下box-sizing属性?
box-sizing属性主要用来控制元素的盒模型的解析模式。默认值是content-box。
§ content-box:让元素维持W3C的标准盒模型。元素的宽度/高度由border + padding + content的宽度/高度决定,设置width/height属性指的是content部分的宽/高
§ border-box:让元素维持IE传统盒模型(IE6以下版本和IE6~7的怪异模式)。设置width/height属性指的是border + padding + content
标准浏览器下,按照W3C规范对盒模型解析,一旦修改了元素的边框或内距,就会影响元素的盒子尺寸,就不得不重新计算元素的盒子尺寸,从而影响整个页面的布局。
CSS 选择符有哪些?哪些属性可以继承?优先级算法如何计算? CSS3新增伪类有那些?
1.id选择器( # myid)
2.类选择器(.myclassname)
3.标签选择器(div, h1, p)
4.相邻选择器(h1 + p)
5.子选择器(ul > li)
6.后代选择器(lia)
7.通配符选择器( )
8.属性选择器(a[rel = “external”])
9.伪类选择器(a: hover, li:nth-child)
优先级为:
!important > id > class > tag
important 比 内联优先级高,但内联比 id 要高
CSS3新增伪类举例:
p:first-of-type选择属于其父元素的首个
元素的每个
元素。
p:last-of-type 选择属于其父元素的最后
元素的每个
元素。
p:only-of-type 选择属于其父元素唯一的
元素的每个
元素。
p:only-child 选择属于其父元素的唯一子元素的每个
元素。
p:nth-child(2) 选择属于其父元素的第二个子元素的每个
元素。
:enabled :disabled控制表单控件的禁用状态。
:checked 单选框或复选框被选中。
CSS3有哪些新特性?
CSS3实现圆角(border-radius),阴影(box-shadow),
对文字加特效(text-shadow、),线性渐变(gradient),旋转(transform)
transform:rotate(9deg) scale(0.85,0.90)translate(0px,-30px) skew(-9deg,0deg);//旋转,缩放,定位,倾斜
增加了更多的CSS选择器 多背景 rgba
在CSS3中唯一引入的伪元素是::selection.
媒体查询,多栏布局
border-image
CSS3中新增了一种盒模型计算方式:box-sizing。盒模型默认的值是content-box, 新增的值是padding-box和border-box,几种盒模型计算元素宽高的区别如下:
content-box(默认)
布局所占宽度Width:
Width = width + padding-left + padding-right + border-left + border-right
布局所占高度Height:
Height = height + padding-top + padding-bottom + border-top + border-bottom
padding-box
布局所占宽度Width:
Width = width(包含padding-left + padding-right) + border-top + border-bottom
布局所占高度Height:
Height = height(包含padding-top + padding-bottom) + border-top + border-bottom
border-box
布局所占宽度Width:
Width = width(包含padding-left + padding-right + border-left + border-right)
布局所占高度Height:
Height = height(包含padding-top + padding-bottom + border-top + border-bottom)
对BFC规范的理解?
BFC,块级格式化上下文,一个创建了新的BFC的盒子是独立布局的,盒子里面的子元素的样式不会影响到外面的元素。在同一个BFC中的两个毗邻的块级盒在垂直方向(和布局方向有关系)的margin会发生折叠。
(W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行布局,以及与其他元素的关系和相互作用。
说说你对语义化的理解?
1,去掉或者丢失样式的时候能够让页面呈现出清晰的结构
2,有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;
3,方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;
4,便于团队开发和维护,语义化更具可读性,是下一步吧网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化。
Doctype作用? 严格模式与混杂模式如何区分?它们有何意义?
1)、<!DOCTYPE> 声明位于文档中的最前面,处于 标签之前。告知浏览器以何种模式来渲染文档。
2)、严格模式的排版和 JS 运作模式是 以该浏览器支持的最高标准运行。
3)、在混杂模式中,页面以宽松的向后兼容的方式显示。模拟老式浏览器的行为以防止站点无法工作。
4)、DOCTYPE不存在或格式不正确会导致文档以混杂模式呈现。
你知道多少种Doctype文档类型?
该标签可声明三种 DTD 类型,分别表示严格版本、过渡版本以及基于框架的 HTML 文档。
HTML 4.01 规定了三种文档类型:Strict、Transitional 以及 Frameset。
XHTML 1.0 规定了三种 XML 文档类型:Strict、Transitional 以及 Frameset。
Standards (标准)模式(也就是严格呈现模式)用于呈现遵循最新标准的网页,而 Quirks
(包容)模式(也就是松散呈现模式或者兼容模式)用于呈现为传统浏览器而设计的网页。
HTML与XHTML——二者有什么区别
区别:
1.所有的标记都必须要有一个相应的结束标记
2.所有标签的元素和属性的名字都必须使用小写
3.所有的XML标记都必须合理嵌套
4.所有的属性必须用引号””括起来
5.把所有<和&特殊符号用编码表示
6.给所有属性赋一个值
7.不要在注释内容中使“—”
8.图片必须有说明文字
常见兼容性问题?
png24位的图片在iE6浏览器上出现背景,解决方案是做成PNG8.也可以引用一段脚本处理.
浏览器默认的margin和padding不同。解决方案是加一个全局的{margin:0;padding:0;}来统一。
IE6双边距bug:块属性标签float后,又有横行的margin情况下,在ie6显示margin比设置的大。
浮动ie产生的双倍距离(IE6双边距问题:在IE6下,如果对元素设置了浮动,同时又设置了margin-left或margin-right,margin值会加倍。)
#box{ float:left; width:10px; margin:0 0 0 100px;}
这种情况之下IE会产生20px的距离,解决方案是在float的标签样式控制中加入
display:inline;将其转化为行内属性。(这个符号只有ie6会识别)
渐进识别的方式,从总体中逐渐排除局部。
首先,巧妙的使用“\9”这一标记,将IE游览器从所有情况中分离出来。
接着,再次使用“+”将IE8和IE7、IE6分离开来,这样IE8已经独立识别。
css
.bb{
background-color:#f1ee18;/所有识别/
.background-color:#00deff\9; /IE6、7、8识别/
+background-color:#a200ff;/IE6、7识别/
background-color:#1e0bd1;/IE6识别/
}
怪异模式问题:漏写DTD声明,Firefox仍然会按照标准模式来解析网页,但在IE中会触发
怪异模式。为避免怪异模式给我们带来不必要的麻烦,最好养成书写DTD声明的好习惯。现在
可以使用html5推荐的写法:<doctype html>
上下margin重合问题
ie和ff都存在,相邻的两个div的margin-left和margin-right不会重合,但是margin-top和margin-bottom却会发生重合。
解决方法,养成良好的代码编写习惯,同时采用margin-top或者同时采用margin-bottom。
解释下浮动和它的工作原理?清除浮动的技巧
浮动元素脱离文档流,不占据空间。浮动元素碰到包含它的边框或者浮动元素的边框停留。
1.使用空标签清除浮动。
这种方法是在所有浮动标签后面添加一个空标签 定义cssclear:both. 弊端就是增加了无意义标签。
2.使用overflow。
给包含浮动元素的父标签添加css属性 overflow:auto; zoom:1; zoom:1用于兼容IE6。
3.使用after伪对象清除浮动。
该方法只适用于非IE浏览器。具体写法可参照以下示例。使用中需注意以下几点。一、该方法中必须为需要清除浮动元素的伪对象中设置 height:0,否则该元素会比实际高出若干像素;
浮动元素引起的问题和解决办法?
浮动元素引起的问题:
(1)父元素的高度无法被撑开,影响与父元素同级的元素
(2)与浮动元素同级的非浮动元素(内联元素)会跟随其后
(3)若非第一个元素浮动,则该元素之前的元素也需要浮动,否则会影响页面显示的结构
解决方法:
使用CSS中的clear:both;属性来清除元素的浮动可解决2、3问题,对于问题1,添加如下样式,给父元素添加clearfix样式:
.clearfix:after{content:”.”;display: block;height:0;clear: both;visibility: hidden;}
.clearfix{display: inline-block;} / for IE/Mac /
清除浮动的几种方法:
1,额外标签法,
2,使用after伪类
#parent:after{
content:”.”;
height:0;
visibility:hidden;
display:block;
clear:both;
}
3,浮动外部元素
4,设置overflow为hidden或者auto
DOM操作——怎样添加、移除、移动、复制、创建和查找节点。
1)创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
2)添加、移除、替换、插入
appendChild()
removeChild()
replaceChild()
insertBefore() //并没有insertAfter()
3)查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值(IE容错能力较强,
会得到一个数组,其中包括id等于name值的)
getElementById() //通过元素Id,唯一性
html5有哪些新特性、移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5?
HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。
拖拽释放(Drag and drop) API
语义化更好的内容标签(header,nav,footer,aside,article,section)
音频、视频API(audio,video)
画布(Canvas) API
地理(Geolocation) API
本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
sessionStorage 的数据在浏览器关闭后自动删除
表单控件,calendar、date、time、email、url、search
新的技术webworker, websocket,Geolocation
移除的元素
纯表现的元素:basefont,big,center,font, s,strike,tt,u;
对可用性产生负面影响的元素:frame,frameset,noframes;
支持HTML5新标签:
IE8/IE7/IE6支持通过document.createElement方法产生的标签,
可以利用这一特性让这些浏览器支持HTML5新标签,
当然最好的方式是直接使用成熟的框架、使用最多的是html5shim框架
如何区分: DOCTYPE声明\新增的结构元素\功能元素
如何实现浏览器内多个标签页之间的通信?
调用localstorge、cookies等本地存储方式
什么是 FOUC(无样式内容闪烁)?你如何来避免 FOUC?
FOUC - FlashOf Unstyled Content 文档样式闪烁
而引用CSS文件的@import就是造成这个问题的罪魁祸首。IE会先加载整个HTML文档的DOM,然后再去导入外部的CSS文件,因此,在页面DOM加载完成到CSS导入完成中间会有一段时间页面上的内容是没有样式的,这段时间的长短跟网速,电脑速度都有关系。
解决方法简单的出奇,只要在之间加入一个或者
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
remote.js文件代码如下:
localHandler({“result”:”我是远程js带来的数据”});
1
运行之后查看结果,页面成功弹出提示窗口,显示本地函数被跨域的远程js调用成功,并且还接收到了远程js带来的数据。
很欣喜,跨域远程获取数据的目的基本实现了,但是又一个问题出现了,我怎么让远程js知道它应该调用的本地函数叫什么名字呢?毕竟是jsonp的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同啊?我们接着往下看。
3、聪明的开发者很容易想到,只要服务端提供的js脚本是动态生成的就行了呗,这样调用者可以传一个参数过去告诉服务端 “我想要一段调用XXX函数的js代码,请你返回给我”,于是服务器就可以按照客户端的需求来生成js脚本并响应了。
看jsonp.html页面的代码:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这次的代码变化比较大,不再直接把远程js文件写死,而是编码实现动态查询,而这也正是jsonp客户端实现的核心部分,本例中的重点也就在于如何完成jsonp调用的全过程。
我们看到调用的url中传递了一个code参数,告诉服务器我要查的是CA1998次航班的信息,而callback参数则告诉服务器,我的本地回调函数叫做flightHandler,所以请把查询结果传入这个函数中进行调用。
OK,服务器很聪明,这个叫做flightResult.aspx的页面生成了一段这样的代码提供给jsonp.html
(服务端的实现这里就不演示了,与你选用的语言无关,说到底就是拼接字符串):
HTML 代码
flightHandler({
“code”: “CA1998”,
“price”: 1780,
“tickets”: 5
});
1
2
3
4
5
我们看到,传递给flightHandler函数的是一个json,它描述了航班的基本信息。运行一下页面,成功弹出提示窗口,jsonp的执行全过程顺利完成!
4、到这里为止的话,相信你已经能够理解jsonp的客户端实现原理了吧?剩下的就是如何把代码封装一下,以便于与用户界面交互,从而实现多次和重复调用。
jQuery如何实现jsonp调用?
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script type=”text/javascript” src=jquery.min.js”>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
这里针对ajax与jsonp的异同再做一些补充说明:
1、ajax和jsonp这两种技术在调用方式上”看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装。
2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加script标签来调用服务器提供的js脚本。
3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。
4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。
总而言之,jsonp不是ajax的一个特例,哪怕jquery等巨头把jsonp封装进了ajax,也不能改变这一点!
2、手写单链表查找倒数第k个节点
1、为了找出倒数第k个元素,最容易想到的办法是首先遍历一遍单链表,求出整个单链表的长度n,然后将倒数第k个,转换为正数第n-k个,接下来遍历一次就可以得到结果。但是该方法存在一个问题,即需要对链表进行两次遍历,第一次遍历用于求解单链表的长度,第二次遍历用于查找正数第n-k个元素。
这种思路的时间复杂度是O(n),但需要遍历链表两次。
2、如果我们在遍历时维持两个指针,第一个指针从链表的头指针开始遍历,在第k-1步之前,第二个指针保持不动;在第k-1步开始,第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在k-1,当第一个(走在前面的)指针到达链表的尾结点时,第二个指针(走在后面的)指针正好是倒数第k个结点。这种思路只需要遍历链表一次。对于很长的链表,只需要把每个结点从硬盘导入到内存一次。因此这一方法的时间效率前面的方法要高。
class Node{
Node next=null;
int data;
public Node(int data){
this.data=data;
}
}
public class MyLinkedList {
Node head=null;//链表头的引用<br /> public Node findElem(Node head,int k){<br /> if(k<1||k>this.length()){<br /> return null;<br /> }<br /> Node p1=head;<br /> Node p2=head;<br /> for(int i=0;i<k;i++)<br /> p1=p1.next;<br /> while(p1!=null){<br /> p1=p1.next;<br /> p2=p2.next;<br /> }<br /> return p2;<br /> }<br /> public static void main(String[] args) {
MyLinkedList list=new MyLinkedList();<br /> list.addNode(1);<br /> list.addNode(2);<br /> list.addNode(3);<br /> list.addNode(4);<br /> list.addNode(5);<br /> MyLinkedList p=new MyLinkedList();<br /> p.head=list.findElem(list.head, 3);<br /> p.printList();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
3、http请求头,请求体,cookie在哪个里面?url在哪里面?
参考菜鸟教程HTTP专栏:http://www.runoob.com/http/http-tutorial.html
人人三面的时候问我http请求头都有哪些值,答不上来。。GG
客户端请求消息
服务器响应消息
HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
实例
下面实例是一点典型的使用GET来传递数据的实例:
客户端请求:
GET /hello.txt HTTP/1.1
User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
Host: www.example.com
Accept-Language: en, mi
1
2
3
4
服务端响应:
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: “34aa387-d-1568eb00”
Accept-Ranges: bytes
Content-Length: 51
Vary: Accept-Encoding
Content-Type: text/plain
1
2
3
4
5
6
7
8
9
输出结果:
Hello World! My payload includes a trailing CRLF.
1
4、原型链的解释
饿了么面试的时候问到了,用友也问到了。没答好,GG.
5、对闭包的理解,实现一个暴露内部变量,而且外部可以访问修改的函数
闭包的作用:
匿名自执行函数、缓存、实现封装(主要作用)、实现面向对象中的对象
var person = function(){
//变量作用域为函数内部,外部无法访问
var name = “default”;
return {
getName : function(){
return name;
},
setName : function(newName){
name = newName;
}
}
}();
print(person.name);//直接访问,结果为undefined
print(person.getName());
person.setName(“a”);
print(person.getName());
//得到结果如下:
undefined
default
a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
6、基本的数据类型
5个简单数据类型(基本数据类型)+ 1个复杂数据类型
undefiend, number string null boolean + object
ES6 新增Symbol
7、基本的两列自适应布局
左定右适应:
div1{
width: 100px;
display: inline-block;
background-color: black;
}
#div2{
display: inline-block;
position: absolute;
left: 100px;
right: 0px;
background-color: red;
}
1
2
3
4
5
6
7
8
9
10
11
12
8、unix中常用的命令行
虽然上过linux课,但是命令忘得差不多了 尴尬。。。
9、OSI模型,HTTP,TCP,UDP分别在哪些层
这个可以参考我另一个博客:
http://blog.csdn.net/qq_22944825/article/details/78160659
OSI:物理层-数据链路层-网络层-传输层-会话层-表现层-应用层
10、解释平衡二叉树,以及在数据结构中的应用(红黑树)
11、快排的时间复杂度和空间复杂度
一个特别好的总结的博客:
http://web.jobbole.com/87968/
12、手写一个jQuery插件
1、$.extend(src)
该方法就是将src合并到jquery的全局对象中去,如:
$.extend({
hello:function(){alert(‘hello’);}
});
1
2
3
2、$.fn.extend(src)
该方法将src合并到jquery的实例对象中去,如:
$.fn.extend({
hello:function(){alert(‘hello’);}
});
1
2
3
13、在jquery方法和原型上面添加方法的区别和实现,以及jquery对象的实现
参考上一个问题答案~
使用jquery的第一件事就是要使用jquery对象,jquery对象和javascript中的DOM对象是不同的。
什么是jquery对象?jquery将一个DOM对象转化为jquery对象后就可以使用jquery类库提供的各种函数。可以将jquery对象理解为一个类,并且封装了很多的方法,而且可以动态的通过加载插件扩展这个类,类似于C#中的分布类partial class。
除了jQuery工具函数,jQuery的操作都是从jQuery对象开始。比如:
attr(key,value)
$(“#myphoto”).attr(“src”,”/pic/1.jpg”);
1
2
3
4
5
jQuery对象是一个特殊的集合对象。即使只有一个元素,jQuery对象仍然是一个集合。说其特殊是因为实际上jQuery对象是包含一个集合对象和各种函数的类。
14、手写一个递归函数
function fact(num) {
if (num <= 1) {
return 1;
} else {
return num * fact(num - 1);
}
}
1
2
3
4
5
6
7
以下代码可导致出错:
var anotherFact = fact;
fact = null;
alert(antherFact(4)); //出错
1
2
3
由于fact已经不是函数了,所以出错。
用arguments.callee可解决问题,这是一个指向正在执行的函数的指针,arguments.callee返回正在被执行的对现象。
新的函数为:
function fact(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1); //此处更改了。
}
}
var anotherFact = fact;
fact = null;
alert(antherFact(4)); //结果为24.
1
2
3
4
5
6
7
8
9
10
15、对前端路由的理解?前后端路由的区别?
前端的路由和后端的路由在实现技术上不一样,但是原理都是一样的。在 HTML5 的 history API 出现之前,前端的路由都是通过 hash 来实现的,hash 能兼容低版本的浏览器。
http://10.0.0.1/
http://10.0.0.1/#/about
http://10.0.0.1/#/concat
1
2
3
服务端路由:每跳转到不同的URL,都是重新访问服务端,然后服务端返回页面,页面也可以是服务端获取数据,然后和模板组合,返回HTML,也可以是直接返回模板HTML,然后由前端JS再去请求数据,使用前端模板和数据进行组合,生成想要的HTML。
前端路由:每跳转到不同的URL都是使用前端的锚点路由,实际上只是JS根据URL来操作DOM元素,根据每个页面需要的去服务端请求数据,返回数据后和模板进行组合,当然模板有可能是请求服务端返回的,这就是 SPA 单页程序。
在js可以通过window.location.hash读取到路径加以解析之后就可以响应不同路径的逻辑处理。
history 是 HTML5 才有的新 API,可以用来操作浏览器的 session history (会话历史)。基于 history 来实现的路由可以和最初的例子中提到的路径规则一样。
H5还新增了一个hashchange事件,也是很有用途的一个新事件:
当页面hash(#)变化时,即会触发hashchange。锚点Hash起到引导浏览器将这次记录推入历史记录栈顶的作用,window.location对象处理“#”的改变并不会重新加载页面,而是将之当成新页面,放入历史栈里。并且,当前进或者后退或者触发hashchange事件时,我们可以在对应的事件处理函数中注册ajax等操作!
但是hashchange这个事件不是每个浏览器都有,低级浏览器需要用轮询检测URL是否在变化,来检测锚点的变化。当锚点内容(location.hash)被操作时,如果锚点内容发生改变浏览器才会将其放入历史栈中,如果锚点内容没发生变化,历史栈并不会增加,并且也不会触发hashchange事件。
16、介绍一下webpack和gulp,以及项目中具体的使用
17、你对es6的了解
参见阮大大的博客
http://es6.ruanyifeng.com/
18、解释一下vue和react,以及异同点
异同点:vue官网给过答案
https://cn.vuejs.org/v2/guide/comparison.html
只简单的用过vue,用vue写了一个日程表,请赐教哦~
https://yyywwwqqq.coding.me/schedule/dist/
源码地址:
https://coding.net/u/yyywwwqqq/p/schedule/git
19、关于平衡二叉树
平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树,同时,平衡二叉树必定是二叉搜索树,反之则不一定。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。 最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci(斐波那契)数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。
20、前后端分离的意义以及对前端工程化的理解
21、使用css实现一个三角形
利用border去画~
先看一下border的布局,如图:
所以三角形:
1.设置宽度、高度为0
2.不设置border-top
3.设置左右border颜色为transparent–透明
22、用promise手写ajax
function getJson(url){
return new Promise((resolve, reject) =>{
var xhr = new XMLHttpRequest();
xhr.open(‘open’, url, true);
xhr.onreadystatechange = function(){
if(this.readyState == 4){
if(this.status = 200){
resolve(this.responseText, this)
}else{
var resJson = { code: this.status, response: this.response }
reject(resJson, this)
}
}
}
xhr.send()
})
}
function postJSON(url, data) {
return new Promise( (resolve, reject) => {
var xhr = new XMLHttpRequest()
xhr.open(“POST”, url, true)
xhr.setRequestHeader(“Content-type”, “application/x-www-form-urlencoded”);
xhr.onreadystatechange = function () {<br /> if (this.readyState === 4) {<br /> if (this.status === 200) {<br /> resolve(JSON.parse(this.responseText), this)<br /> } else {<br /> var resJson = { code: this.status, response: this.response }<br /> reject(resJson, this)<br /> }<br /> }<br /> }
xhr.send(JSON.stringify(data))<br /> })<br />}
getJSON(‘/api/v1/xxx’) // => 这里面是就try
.catch( error => {
// dosomething // => 这里就是catch到了error,如果处理error以及返还合适的值
})
.then( value => {
// dosomething // 这里就是final
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
23、手写一个类的继承,并解释一下
继承的形式有很多中,js高程里面归纳了其中,我简单说一下前三种。
1.原型继承
function Parent(){
this.name = “parent”;
}
Parent.prototype.getName = function(){
return this.name;
}
function Child(){
this.name = “child”;
}
//继承parent
Child.prototype = new Parent();
1
2
3
4
5
6
7
8
9
10
11
12
13
2.构造函数继承
function Animal(name){
this.name = name;
this.eat = function(){
consoel.log(this.name + “吃饭”);
}
}
var cat = new Animal(“maomi”);
cat.name;
cat.eat();
1
2
3
4
5
6
7
8
9
缺点是:
3.组合继承
24、解释一下call函数和apply函数的作用,以及用法
改变this的指向。
this的指向问题,在你不知道的js这本书中(神书)做了四点归纳:
1.默认绑定 (指 直接调用 foo(), this指向window)
2.隐式绑定(obj.foo(), this指向obj 这里会出现很多坑,下面的问题应该会有解答)
3.显示绑定(利用call、apply、bind改变this)
4.new(var cat = new Animal() , this指向cat对象)
25、你说自己抗压能力强,具体表现在哪里?
略
26、对前端前景的展望,以后前端会怎么发展
27、手写第一次面试没有写出来的链表问题,要求用es6写
28、平时是怎么学技术的?
29、平时大学里面时间是怎么规划的?
30、接下来有什么计划?这个学期和下个学期的计划是?
31、项目中遇到的难点,或者你学习路上的难点
32、你是通过什么方法和途径来学习前端的
33、手写一个简单遍历算法
34、解释一下react和vue,以及区别
35、你在团队中更倾向于什么角色?
36、对java的理解
37、介绍node.js,并且介绍你用它做的项目
38、手写一个js的深克隆
function deepCopy(obj){
//判断是否是简单数据类型,
if(typeof obj == “object”){
//复杂数据类型
var result = obj.constructor == Array ? [] : {};
for(let i in obj){
result[i] = typeof obj[i] == “object” ? deepCopy(obj[i]) : obj[i];
}
}else {
//简单数据类型 直接 == 赋值
var result = obj;
}
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
39、for函数里面setTimeout异步问题
40、手写归并排序
<1>.长度为n(n>1),把该输入序列分成两个长度为n/2的子序列;
<2>.对这两个子序列分别采用归并排序,直到长度n小于2;
<3>.将两个排序好的子序列合并成一个最终的排序序列。
function mergeSort(arr) {
var len = arr.length;
if(len < 2) {
return arr;
} else {
middle = Math.floor(len / 2);
var left = arr.slice(0, middle);
var right = arr.splice(middle);
return merge(mergeSort(left), mergeSort(right));
}
}
function merge(left, right) {
var result = [];
while(left.length && right.length) {
left[0] > right[0] ? result.push(right.shift()): result.push(left.shift());
}
if(left.length) {
result = result.concat(left);
}
if(right.length) {
result = result.concat(right);
}
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
41、介绍自己的项目
略
42、实现两个排序数组的合并
参考42题中的merge函数。
43、手写一个原生ajax
ajax:一种请求数据的方式,不需要刷新整个页面;
ajax的技术核心是 XMLHttpRequest 对象;
ajax 请求过程:创建 XMLHttpRequest 对象、连接服务器、发送请求、接收响应数据;
一个在stackoverflow的高分回答结合上面的代码,给出get和post的两种不同请求方法:
var ajax = {};
ajax.x = function () {
if (typeof XMLHttpRequest !== ‘undefined’) {
return new XMLHttpRequest();
}
var versions = [
“MSXML2.XmlHttp.6.0”,
“MSXML2.XmlHttp.5.0”,
“MSXML2.XmlHttp.4.0”,
“MSXML2.XmlHttp.3.0”,
“MSXML2.XmlHttp.2.0”,
“Microsoft.XmlHttp”
];
var xhr;<br /> for (var i = 0; i < versions.length; i++) {<br /> try {<br /> xhr = new ActiveXObject(versions[i]);<br /> break;<br /> } catch (e) {<br /> }<br /> }<br /> return xhr;<br />};
ajax.send = function (url, method, data, success,fail,async) {
if (async === undefined) {
async = true;
}
var x = ajax.x();
x.open(method, url, async);
x.onreadystatechange = function () {
if (x.readyState == 4) {
var status = x.status;
if (status >= 200 && status < 300) {
success && success(x.responseText,x.responseXML)
} else {
fail && fail(status);
}
}<br /> };<br /> if (method == 'POST') {<br /> x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');<br /> }<br /> x.send(data)<br />};
ajax.get = function (url, data, callback, fail, async) {
var query = [];
for (var key in data) {
query.push(encodeURIComponent(key) + ‘=’ + encodeURIComponent(data[key]));
}
ajax.send(url + (query.length ? ‘?’ + query.join(‘&’) : ‘’), ‘GET’, null, success, fail, async)
};
ajax.post = function (url, data, callback, fail, async) {
var query = [];
for (var key in data) {
query.push(encodeURIComponent(key) + ‘=’ + encodeURIComponent(data[key]));
}
ajax.send(url,’POST’, query.join(‘&’), success, fail, async)
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
使用方法:GET
ajax.get(‘/test.php’, {foo: ‘bar’}, function(response,xml) {
//success
},
function(status){
//fail
});
1
2
3
4
5
6
POST
ajax.post(‘/test.php’, {foo: ‘bar’}, function(response,xml) {
//succcess
},function(status){
//fail
});
1
2
3
4
5
6
7
44、手写一个promise版的ajax
45、手写实现一个promise
46、手写实现requireJS模块实现
47、手写实现jquery里面的insertAfter
48、react和vue的介绍以及异同
49、AMD和CMD,commonJS的区别
50、介绍一下backbone
51、了解过SEO吗?
52、低版本浏览器不支持HTML5标签怎么解决?
53、用js使低版本浏览器支持HTML5标签 底层是怎么实现的?
54、实现一个布局:左边固定宽度为200,右边自适应,而且滚动条要自动选择只出现最高的那个
55、画出盒子模型,要使谷歌浏览器的盒子模型显示得跟IE浏览器一致(让谷歌跟ie一致,不是ie跟谷歌一致),该怎么做?
56、手写JS实现类继承,讲原型链原理,并解释new一个对象的过程都发生了什么
57、Array对象自带的方法,一一列举
58、若干个数字,怎么选出最大的五个
59、Array对象自带的排序函数底层是怎么实现的?
60、常用的排序算法有哪些,介绍一下选择排序
61、了解navigator对象吗?
62、手写一个正则表达式,验证邮箱
63、link和@import引入CSS的区别?
64、刚才说有些浏览器不兼容@import,具体指哪些浏览器?
65、介绍一下cookie,localstorage,sessionstorage,session
66、jquery绑定click的方法有几种
67、你的优点/竞争力
68、移动端适配问题
69、react的难点在哪里
70、做过css动画吗
71、如何优化网站
72、以后的规划
73、你做过最困难的事情是啥?
74、css3 html5新特性
75、闭包,ES6,跨域
76、问做过啥项目,用到什么技术,遇到什么困难
77、兼容性
78、盒子模型
79、Array的unshift() method的作用是什么?如何连接两个Array?如何在Array里移除一个元素?
80、用纸笔写一个Closure,任意形式和内容
81、知不知道Array-like Object?
82、如何用Native JavaScript来读写Cookie?
83、知不知道CSS Box-model?
84、如何做一个AJAX Request?
85、Cross-domain access有没有了解?
86、前端安全方面有没有了解?XSS和CSRF如何攻防?
87、HTTP Response的Header里面都有些啥?
88、知不知道HTTP2?
89、输入URL后发生了什么?
90、new operator实际上做了什么?
91、面向对象的属性有哪些?
92、做一个两栏布局,左边fixed width,右边responsive,用纸笔手写
93、讲一下AJAX Request
94、讲一下Cross-domain access
95、介绍一下做过的项目
96、问到了多个服务器怎么弄,架构之类的
97、angular的渲染流程
98、脏检查
99、nodejs的架构、优缺点、回调
100、css 盒模型
101、css 布局,左边定宽右边自适应
102、冒泡和捕获,事件流哪三个阶段?
103、实现事件代理
104、原型链
105、继承的两种方法
106、ajax,原生ajax的四个过程
107、闭包,简单说一个闭包的应用,然后闭包的主要作用是什么
108、css:两个块状元素上下的margin-top和margin-bottom会重叠。啥原因?怎么解决?
109、js:写一个递归。就是每隔5秒调用一个自身,一共100次
110、cookie和session有什么区别
111、网络分层结构
112、你的不足是什么?
113、做了那么多项目,有没有自己的归纳总结
114、工程怎么进行文件管理
115、less和sass掌握程度
116、Cookie 是否会被覆盖,localStorage是否会被覆盖
117、事件代理js实现
118、Css实现动画效果
119、Animation还有哪些其他属性
120、Css实现三列布局
121、Css实现保持长宽比1:1
122、Css实现两个自适应等宽元素中间空10个像素
123、requireJS的原理是什么
124、如何保持登录状态
125、浮动的原理以及如何清除浮动
126、Html的语义化
127、原生js添加class怎么添加,如果本身已经有class了,会不会覆盖,怎么保留?
128、Jsonp的原理。怎么去读取一个script里面的数据?
129、如果页面初始载入的时候把ajax请求返回的数据存在localStorage里面,然后每次调用的时候去localStorage里面取数,是否可行。
130、304是什么意思?有没有方法不请求不经过服务器直接使用缓存
131、http请求头有哪些字段
132、数组去除一个函数。用arr.splice。又问splice返回了什么?应该返回的是去除的元素。
133、js异步的方法(promise,generator,async)
134、Cookie跨域请求能不能带上
135、最近看什么开源项目?
136、commonJS和AMD
137、平时是怎么学习的?
138、为什么要用translate3d?
139、对象中key-value的value怎么再放一个对象?
140、Get和post的区别?
145、Post一个file的时候file放在哪的?
146、说说你对组件的理解
147、组件的html怎么进行管理
148、js的异步加载,promise的三种状态,ES7中的async用过么
149、静态属性怎么继承
150、js原型链的继承
151、jquery和zepto有什么区别
152、angular的双向绑定原理
153、angular和react的认识
154、MVVM是什么
155、移动端是指手机浏览器,还是native,还是hybrid
156、你用了移动端的什么库类和框架?
157、移动端要注意哪些?
158、适配有去考虑么,retina屏幕啊?
159、rem是什么?em是什么?如果上一层就是根root了,em和rem等价么?
160、怎么测试的?会自动化测试么?
161、你觉得你什么技术最擅长?
162、你平时有没有什么技术的沉淀?
163、单向链表怎么查找有没有环?
164、怎么得到一个页面的a标签?
165、怎么在页面里放置一个很简单的图标,不能用img和background-img?
166、正则表达式判断url
167、怎么去除字符串前后的空格
168、实现页面的局部刷新
169、绝对定位与相对定位的区别
170、js轮播实现思路
171、使用js画一个抛物线,抛物线上有个小球随着抛物线运动,有两个按钮能使小球继续运动停止运动
172、java五子棋,说下实现思路
173、如何让各种情况下的div居中(绝对定位的div,垂直居中,水平居中)?
174、display有哪些值?说明他们的作用
175、css定义的权重
176、requirejs实现原理
177、requirejs怎么防止重复加载
178、ES6里头的箭头函数的this对象与其他的有啥区别
179、tcp/udp区别
180、tcp三次握手过程
181、xss与csrf的原理与怎么防范
182、mysql与 MongoDB的区别
183、w3c事件与IE事件的区别
184、有没有上传过些什么npm模块
185、IE与W3C怎么阻止事件的冒泡
186、gulp底层实现原理
187、webpack底层实现原理
188、gulp与webpack区别
189、vuejs与angularjs的区别
190、vuex是用来做什么的
191、说下你知道的响应状态码
192、ajax的过程以及 readyState几个状态的含义
193、你除了前端之外还会些什么?
194、cookie与session的区别
195、一些关于php与java的问题
196、你觉得你哪个项目是你做的最好的
197、说说你在项目中遇到了哪些困难,是怎么解决的
198、前端优化你知道哪些
199、webpack是用来干嘛的
200、webpack与gulp的区别
201、es6与es7了解多少
202、说下你知道的响应状态码
203、看过哪些框架的源码
204、遇到过哪些浏览器兼容性问题
205、清除浮动有哪几种方式,分别说说
206、你知道有哪些跨域方式,分别说说
207、JavaScript有哪几种类型的值
208、使用 new操作符时具体是干了些什么
209、学习前端的方法以及途径
210、怎么实现两个大整数的相乘,说下思路
211、你学过数据结构没,说说你都了解些什么
212、你学过计算机操作系统没,说说你都了解些什么
213、你学过计算机组成原理没,说说你都了解些什么
214、你学过算法没,说说你都了解些什么
215、说下选择排序,冒泡排序的实现思路
216、用过哪些框架
217、让你设计一个前端css框架你怎么做
218、了解哪些设计模式说说看
219、说下你所了解的设计模式的优点
220、vue源码结构
221、状态码
222、浏览器缓存的区别
223、304与200读取缓存的区别
224、http请求头有哪些,说说看你了解哪些
225、js中this的作用
226、js中上下文是什么
227、js有哪些函数能改变上下文
228、你所了解的跨域的方法都说说看你了解的?
229、要是让你自己写一个js框架你会用到哪些设计模式
230、平常在项目中用到过哪些设计模式,说说看
231、一来给了张纸要求写js自定义事件
232、前端跨域的方法
233、call与apply的区别
234、h5有个api能定位你知道是哪个吗?
235、vue与angularjs中双向数据绑定是怎样实现的?
236、webpack怎样配置?
237、nodejs中的文件怎么读写?
238、link和@import有什么区别?
239、cookies,sessionStorage 和 localStorage 的区别
240、看过哪些前端的书?平时是怎么学习的
241、说下你所理解的mvc与mvvc
242、position有哪些值,说下各自的作用
243、写个从几个li中取下标的闭包代码
244、你的职业规划是怎么样的?
245、移动端性能优化
246、lazyload如何实现
247、点透问题
248、前端安全
249、原生js模板引擎
250、repaint和reflow区别
251、requirejs如何避免循环依赖?
252、实现布局:左边一张图片,右边一段文字(不是环绕)
253、window.onload和$(document).ready()的区别,浏览器加载转圈结束时哪个时间点?
254、form表单当前页面无刷新提交 target iframe
255、setTimeout和setInterval区别,如何互相实现?
256、如何避免多重回调—promise,promise简单描述一下,如何在外部进行resolve()
257、margin坍塌?水平方向会不会坍塌?
258、伪类和伪元素区别
259、vue如何实现父子组件通信,以及非父子组件通信
260、数组去重
261、使用flex布局实现三等分,左右两个元素分别贴到左边和右边,垂直居中
262、平时如何学前端的,看了哪些书,关注了哪些公众号
263、实现bind函数
264、数组和链表区别,分别适合什么数据结构
265、对mvc的理解
HTML,CSS面试题:
每个HTML文件里面都有一个很重要的东西,Doctype,知道这是干什么的么?
答案:<!DOCTYPE>声明位于文档中最前面的位置,处于标签之前。此标签可告知浏览器文档使用哪种HTML或XHTML规范。(重点:告诉浏览器按照何种规范解析页面)
请讲一下HTML5的特点。
答案:https://www.h5course.com/a/2015050292.html
你知道的语义化的标签有哪些?
答案:这个链接里不仅讲了几个常见的H5新的语义化元素,还在最下方介绍了如何使不兼容这些标签的浏览器还能够按照我们预期的样子进行展示【如果要看更多的语义化标签请自行百度】:https://www.runoob.com/html/html5-semantic-elements.html
CSS3新增了哪些特性?
答案:CSS新特性详细讲解
请讲一下CSS3动画的优点。
答案:代码比较简单,再就是性能好,浏览器会对其进行优化。
请讲一下圣杯布局和双飞翼布局。
圣杯布局与双飞翼布局都是双边固定宽度,中间自适应的布局。
如何写宽高自适应的APP?
答案:请访问:前端项目自适应屏幕的技巧
如何更改input的样式?
答案:请访问:第一个:更改input复选框以及上传文件的样式、第二个:更改input输入框的样式
div+css的布局较table布局有什么优点?
答案: 改版的时候更方便,只要改css文件。页面加载速度更快、结构化清晰、页面显示简介。表现与结构相分离。易于优化(seo)搜索引擎更友好,排名更容易靠前。
grid布局有过了解么?
答案:CSS新布局之display: grid;详细介绍
img的alt与title有何异同?strong与em的异同?
答案:
alt:用来指定替换文字【图片加载失败展示】。
title:用来提供建议性文字【移入显示】。
strong:粗体强调标签。
em:斜体强调标签。
请描述一下渐进增强与优雅降级。
答案:渐进增强是向前【高版本浏览器】兼容。优雅降级是向后【低版本浏览器】兼容。
知道什么是微格式吗?谈谈理解。
答案:微格式是一种让机器可读的语义化XHTML词汇的集合,是结构化数据的开放标准。是为特殊应用而制定的特殊格式。
优点:将智能数据添加到网页上,让网页内容在搜索引擎结果页面可以显示额外的提示。(应用范例:豆瓣)
为什么利用多个域名来存储网站资源会更有效?
答案:CDN缓存更方便;突破浏览器并发限制;节约cookie带宽;节约主域名的连接数,优化页面相应速度;防止不必要的安全问题;
一个页面上有大量的图片(大型电商网站),加载很慢,你有哪些方法优化这些图片的加载,给用户更高的体验。
答案:使用精灵图,将小规格的图片整合为一张精灵图,减少浏览器请求次数。【http2.0可以不考虑此问题】
使用图片懒加载。
图片懒加载原理?
答案:
CSS有哪些选择器?
答案:最全CSS知识整理
CSS中可以通过哪些属性,使得一个DOM元素不显示在浏览器的可视范围内?
答案:
display: none;
visibility: hidden;
opacity: 0;
为什么要使用HTML5的语义化标签?
答案:去掉或样式丢失的时候能让页面保留基本样式呈现清晰的结构。利于SEO。减少团队差异化。
行内元素和块级元素的区别是什么?行内元素的padding和margin可设置么?
答案:
块级元素总是独占一行。width,height,padding,margin都可以控制。
行内元素和相邻的行内元素在同一行,width,height与padding-top,padding-bottom,还有margin-top,margin-bottom不可控制,其余可控制。
超链接被访问过后hover样式就不出现的问题是什么?如何解决?
答案:被点击访问过的超链接样式不在具有hover和active了,解决办法是改变css属性的排列顺序:L-V-H-A(link,visited,hover,active)。
rgba()和opacity的透明效果有什么不同?
答案:opacity透明子元素会跟着透明(继承),rgba()的透明子元素则不会继承。
请描述display:none;visibility:hidden;opacity:0;三者的区别;
答案:最全CSS知识整理
你知道的css让元素垂直水平居中的方法有哪些?
答案:请访问:元素垂直水平居中的方法
如何垂直居中一个浮动元素?
答案:用定位,计算top与left,可以用CSS的函数calc()计算。
请讲一下px,em的区别。
答案:px和em都是长度单位。但是px是固定的,指定多少就是多少。em是根据父级元素的大小变化的。
拓展:浏览器默认字体大小是16px。所以未经调整的浏览器都符合:1em=16px这个计算规则。
SASS和LESS是什么?为什么要使用它们?
答案:CSS预处理器,通过编程的方式来开发CSS,可实现代码简写与复用等。
使用它们是因为:结构清晰,便与拓展、
减少无意义的机械劳动、
可以轻松实现多重继承。
CSS的link和import的区别是什么?
答案:百度很多,自己搜吧。
请讲一下盒模型。
答案:css盒模型分俩种:IE盒子模型和标准盒子模型。
在 标准盒子模型中,width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。
IE盒子模型中,width 和 height 指的是内容区域+border+padding的宽度和高度。
BFC是什么?
答案:BFC是指浏览器中创建了一个独立的渲染区域,并且拥有一套渲染规则,他决定了其子元素如何定位,以及与其他元素的相互关系和作用。
对WEB标准以及W3C的理解与认识。
答案:标签闭合、标签小写、不乱嵌套、提高搜索机器人搜索几率、使用外链css和js脚本、结构行为表现的分离、文件下载与页面速度更快、内容能被更多的用户所访问、能被更多的设备所访问、更少的代码和组件,容易维护、改版方便,不需要变动页面内容、提供打印版本而不需要复制内容、提高网站易用性。
前端页面有哪三层构成?分别是什么?作用是什么?
答案:结构层(HTML - - 设置页面的基本结构)、样式层(CSS - - 修改页面展示给用户的样式加一些小交互)、行为层(JS - - 使用户与页面完美交互)
CSS选择符有哪些?块级元素有哪些?空元素有哪些?
答案:最全CSS知识整理
CSS选择符有哪些?哪些属性可以继承?优先级算法如何计算?CSS新增伪类有哪些?
答案链接同上。
请说出position的属性值有哪些。每个值的特点作用。
答案链接同上。
display的属性值有哪些?可以做什么?
答案链接同上。(https://blog.csdn.net/weixin_43606158/article/details/95873063)
哪些CSS属性可以继承?
答案链接同上。
css样式优先级算法如何计算?
答案:!important > id > class > 标签
!important比内联样式优先级高;
优先级就近原则,样式定义最近者为准;
以最后载入的样式为准;
css中的z-index的权重问题请讲讲你所了解的一些规则。
答案:css的z-index权重问题【最简洁,没有废话】
你开发过程中遇到过最棘手的html与css问题是什么?
参考答案:笔者遇到最棘手的是做左侧sidebar导航,具体可看:左侧sidebar和整体分开滚动,并在X轴正常显示二级菜单
JS基础题:
JS的输出输入有哪些?
答案:JS的输出与输入介绍
JS的数据类型有哪些?
答案:请访问:JS数据类型详解
如何判断JS变量的数据类型?
typeof()
instanceof
constructor
toString
Object.prototype.toString
关于最重要的Object.prototype.toString请观看:https://blog.csdn.net/weixin_43606158/article/details/93380867
typeof求解的可能值有哪些?
“number”
“string”
“boolean”
“undefined”
“object”
“symbol”
“function”
数据类型的自动转换和隐式转换你知道哪些?
隐式类型转换:
1 == ‘1’
‘1’ + 1
‘1’ - 1
显示类型转换:
parseInt(str,radix)/parseFloat(str,radix)/Number()转变成数字。
Boolean(param)转变成布尔值
subString()转变成字符串
详细关于JS数据类型转换的内容请观看:一篇文章搞懂JS转换规则
6. “ == ” 和 “ === ” 还有 “ != ” 和 “ !== ”的区别?
- “ == ” 和 “ != ”会做数据隐式类型转换,转换完数据类型在做比较。而“ === ” 和 “ !== ”会先判断数据类型,如果俩者的数据类型不一致直接返回false就不会再去做值的比较了。
7. 讲一讲“ || ” 和 “ && ”。
答案:请访问:彻底了解”||“和”&&”
8. “ i++ ” 和 “ ++i ”的区别。
答案:i++是先引用i的值而后将i递增1。
++i是先将i的值加1而后引用它的值。
9. break,renturn,continue三者的区别
答案:return、break与continue的区别
10. 请讲一讲递归。
函数自身调用自身。 详细请看:递归
用递归实现遍历迭代
11. 你知道哪些算法?
答案:请访问:JS算法小总结
12. 你一般如何调试bug?
答案:请访问:前端调试bug的方法
13. 数组的常用API你知道哪些?
答案:请访问:数组的常用API详解
14. 请讲将数组与伪数组的区别。
答案:请访问:伪数组是什么?伪数组与数组的区别
15. 请讲讲你对面向对象编程的理解。
答案:请访问:面向对象编程(OOP)的概念
16. 请讲讲原型链。
答案:JS原型知识整理
17. 请讲讲继承的方法。
答案:JS继承的六种方法
18. 请讲讲JavaScript作用域。
答案:JS作用域与声名提升
19. 请讲讲变量的声明提升
答案:JS作用域与声名提升
20. 创建对象的方法有哪些?
答案:https://blog.csdn.net/weixin_43606158/article/details/94912023
21. 请讲讲ECMAScript的内置对象。
答案:https://blog.csdn.net/weixin_43606158/article/details/94912023
22. Array在ES5新增遍历的API它们每个的用法,返回值,参数。
答案:数组ES5新增遍历迭代的方法及其区别
23. ES5/ES6新增的哪些东西是你平时开发中常用到的?
答案:ES5/6新特性
24. 列举浏览器对象模型BOM里常用的至少四个对象,并列举window对象的常用方法至少五个。
答案:BOM内容的小整理
25. 请讲一下你知道的性能优化的方法。
答案:提高JS性能的12个技巧
26. 事件绑定和普通事件有什么区别?
答案:事件绑定和普通事件的区别
27. IE和其他浏览器事件流的区别。
答案:IE浏览器是事件冒泡,其他浏览器是事件捕获(标准DOM事件流)。
28. IE的标准下有哪些兼容性的写法?
答案:javascript之IE兼容篇
29. 请讲一下this的指向问题。
答案:this的指向
30. 更改this指向的方法有哪些?
答案:更改this指向的方法及其区别
31. 请讲一下bind(),call(),apply()三者的区别。
答案链接同上
32. 请讲一下JavaScript的闭包。有什么特点?对页面有什么影响?
答案:JS闭包的理解
33. 事件委派/事件委托是什么?
答案:事件委派的使用及作用
34. 如何阻止事件冒泡和浏览器默认事件?
答案:浏览器事件默认行为介绍与阻止的方法
JS事件流介绍与阻止事件冒泡
35. 添加,删除,替换,插入到某个节点的方法。
DOM知识详细整理
36. document.load和jquery.ready的区别。
答案:加载页面之前的方法介绍
37. 请讲一下JavaScript的同源策略。
答案:JavaScript的同源策略
38. 请说出你知道的跨域的方法有哪些?最常用的是哪个?怎么使用的?
答案:前端跨域的六种解决方法
39. JavaScript是一门什么样的语言?它有哪些特点?
答案:弱类型语言,类型会做隐式转换,作用域,声名提升。。。
40. 正则表达式构造函数var reg = new RegExp(‘xxx’)与正则表达式字面量var reg = /xxx/有什么不同?
答案:当使用RegExp()构造函数的时候,不仅需要转义引号(即 \’ 表示 ’ ),并且还需要双反斜杠才能表示一个反斜杠。所以我们使用正则表达式字面量的效率更高。
41. JavaScript中callee和caller的作用?
答案:JavaScript中callee和caller的区别
42. 简述JavaScript的DOM里document获取节点的方法,并说出对应作用。
答案:DOM知识详细整理
43. 简述创建函数的几种方式。
答案:JS函数介绍
44. 把script标签放在body结束标签之前和结束标签之后有什么区别?浏览器会怎么解析它们?
答案:如果说放在body的封闭之前,将会阻塞其他资源的加载。如果放在body封闭标签之后,不会影响到body内元素的加载。
45. 请描述iframe的优缺点。
答案:Iframe介绍
46. 请谈谈cookie、localStorage和SessionStorage的区别和特点。
答案:客户端缓存的方法详细介绍
47. JS延迟加载的方式有哪些?
答案:1.script标签的defer和async属性。2.动态创建DOM方式(创建script,插入到DOM中,加载完毕之后callback)。3.按需异步载入js
48. 哪些操作会造成内存泄漏?
答案:内存泄漏指任何对象在您不再拥有或需要它的时候它仍然存在。
会引发内存泄露的情况:1.setTimeout的第一个参数使用字符串而非函数的话,会导致内存泄露。2.闭包。3.控制台日志。4.循环(在俩个对象彼此引用且彼此保留时,就会产生一个循环)。
49. 请说一下JavaScript中的垃圾回收机制。
答案:垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为0(没有其他对象引用过该对象),或对该对象的唯一引用是循环的,那么该对象的内存即可回收。
50. 在js中0.1+0.2等于多少?如何让它得到正确答案?
答案:等于0.30000000000000004。原因是因为浮点数运算中产生的误差。
最完善的解决方法:
不管是加减乘除都有这个问题,所以我们可以在传递一个额外的参数然后里面加一个switch判断使用什么计算,这样就是一个通用的计算器了。
function add(param1, param2) {
return parseFloat((param1 + param2).toFixed(10));
}
add(0.1, 0.2); // 0.3
1
2
3
4
关于浮点数加减乘除的问题解决方法请看:https://wudi98.blog.csdn.net/article/details/105530637
51. 你用过axios么?
答案:axios的使用
52. async,promise,settimeout的执行顺序
答案:一篇文章彻底搞懂异步,同步,setTimeout,Promise,async
53. 前端开发这么久了你知道哪些常用的网站?
答案:前端开发应知网站
54. 你写过哪些前端工具(功能)函数?
答案:前端开发常用功能函数总结
55. async/await 和 promise 的区别。
答案:
async/await 是建立在 Promise上的,不能被使用在普通回调以及节点回调
async/await 和 Promises 很像,不阻塞
async/await 代码看起来像同步代码。
Promise代码完全都是Promise的API(then、catch等等),操作本身的语义反而不容易看出来
56. 节流和防抖
答案:JS的节流和防抖实际应用
57. Event Loop,事件循环是什么?
答案:一篇文章彻底搞懂异步,同步,setTimeout,Promise,async【文章末尾做了event loop总结】
nodejs与普通js的Event Loop:https://juejin.im/post/5b8f76675188255c7c653811
58.
React面试题:
由于内容过多,于是笔者单独整理了一篇文章,请点击链接: React一到三年面试题总结以及进阶题
dvajs:
reducers与effects的区别:
答案:reducers是处理同步的操作。effects是处理异步的。effects是generator函数。
Vue面试题整理:
由于内容过多,于是笔者单独整理了一篇文章,请点击链接: Vue一到三年面试题总结
NodeJS:
请讲讲NodeJS的优点和缺点,并说出你认为他适合什么开发场景?
答案:因为Node是基于事件驱动和无阻塞的,所以非常适合处理并发请求。此外,与Node代理服务器交互的客户端代码是由js编写的,客户端和服务端都用一种语言编写,这是非常美妙的事情。缺点:单进程,单线程,只支持单核CPU,不能充分的利用多核CPU服务器。一旦这个进程崩掉,那么整个web服务就崩掉了。
适用场景:实时应用,如在线聊天,实时通知推送等等。分布式应用,通过高效的并且I/O使用已有的数据。工具类应用,海量的工具,小到前端压缩部署(如grunt),大到桌面图形界面应用程序。游戏类应用,游戏领域对实时和并发有很高的要求。利用稳定接口提升web渲染能力。前后端编程语言统一,前端人员可以非常快速的切入到服务端开发。(如著名的纯js全栈式MEAN架构。)
需求:实现一个页面操作不会整夜刷新的网站,并且能在浏览器前进、后退时正确响应。给出你的技术实现方案。
答案:至少给出思路(url-hash,可以使用已有的history.js之类的)
讲一讲route、middleware、cluster、nodemon、pm2、server-side rendering之类的。
什么是前端路由?什么时候适合使用前端路由?前端路由有哪些优点和缺点。
答案:前端路由就是在不进行后端请求的情况下进行页面跳转。前端路由一般使用在单页应用。优点:用户体验好,不需要每次都从服务器全部获取,快速展现给用户。缺点:使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存
Webpack:
webpack原理,以及常用插件。
版本仓库的使用:
你了解Git么?
答案:Git版本仓库介绍
你了解SVN么?
答案:SVN简介及使用方法
Git的常用命令你知道哪些?
答案:Git常用命令介绍
Git你是怎么解决代码冲突的?
答案:git解决代码冲突
Git你是怎么回退版本的?
答案:git回退版本
命令行的命令你知道哪些?
答案:命令行常用命令
电脑相关知识【HTTP的也在这里】:
TCP/IP三次握手与四次挥手你了解过么?它的存在意义是什么?
答案:一篇文章搞懂TCP/IP三次握手与四次挥手,用过手机的都能看懂
意义:为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
常见请求头与响应头你了解哪些?
答案: 常见的请求头与响应头介绍
常见状态码及其代表的意义你知道哪些?
答案:开发过程中常见状态码
实际开发移动端项目的过程中,你如何使用真机调试呢?
答案:开发移动端项目在真机上面的调试方法
请讲讲长连接与短连接。
答案:https://www.cnblogs.com/gotodsp/p/6366163.html
如何给网站做seo优化。
答案:https://baike.baidu.com/item/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E7%AE%97%E6%B3%95
除了上述描述的那些,其实最重要的是砸钱。。。
请讲讲浏览器渲染原理。
答案:https://blog.fundebug.com/2019/01/03/understand-browser-rendering/
HTTP协议中,GET和POST有什么区别?分别适用什么场景?
答案:get传送的数据长度有限制,因为是放在url中传递参数,如果传递中文参数,需要自己进行编码操作,安全性较低。post是放在报文中,没有限制。【如果服务器做了限制另说,可更改】。
适用场景:post一般用于数据提交。get一般用于简单的数据查询,严格要求不是那么高的场景。
一个页面从输入URL到页面加载显示完成,这个过程中都发生了什么?
答案:
1.用户输入
当用户输入关键字并按下回车之后,这意味着当前页面即将要被替换成新的页面,不过在这个流程继续之前,浏览器还给了当前页面一次执行beforeunload事件的机会,beforeunload事件允许页面在退出之前执行一些数据清理操作,还可以询问用户是否要离开当前页面。
2.url请求过程
首先会查找本地hosts文件看是否有缓存,如果没有那么浏览器都会开启一个线程来处理这个请求,同时在远程DNS服务器上启动一个DNS查询。这能使浏览器获得请求对应的IP地址。
浏览器与Web服务器通过TCP三次握手协商来建立一个TCP/IP连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,而后服务器应答并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。
一旦TCP/IP连接建立,浏览器会通过该连接向远程服务器发送HTTP的GET请求。远程服务器找到资源并使用HTTP响应返回该资源,值为200的HTTP响应状态表示一个正确的响应。
此时,Web服务器提供资源服务,客户端开始下载资源。
3.准备渲染阶段
默认情况下,chrome会为每个页面分配一个渲染进程,也就是说,每打开一个新页面就会配套创建一个新的渲染进程。
4.渲染阶段
文件解码成功后会开始渲染流程,先会根据HTML创建DOM树,有CSS的话会去构建CSSOM树。如果遇到script标签的话,会判断是否存在async或者defer,前者会并行进行下载并执行js,后者会先下载文件,然后等待HTML解析完成后顺序执行。
如果以上都没有,就会阻塞住流程直到js执行完毕。
CSSOM树和DOM树构建完成后会开始生产Render树,这一步就是确定页面元素的布局、样式等等诸多方面的东西。
在生成Render树的过程中,浏览器就开始调用GPU绘制,合成图层,将内容显示在屏幕上了。
为什么利用多个域名来存储网站资源会更有效?
答案:确保用户在不同地区能用最快的速度打开网站,其中某个域名崩溃用户也能通过其他域名访问网站,并且不同的资源放到不同的服务器上有利于减轻单台服务器的压力。
线程与进程的区别。
答案:一个程序最少有一个进程,一个进程最少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大的提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
讲一讲强缓存和协议缓存?
HTTP/2.0 都有哪些特性?头部压缩的原理?
HTTP和HTTPS握手差异?
nginx了解么?你都用来做什么?
有了【Last-Modified,If-Modified-Since】为何还要有【ETag、If-None-Match】?
安全方面相关:
解释一下什么是sql注入,xss攻击。
答案:
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
CSRF跨站请求伪造是什么?
拓展题:
前端开发规范了解过么?
答案:前端开发规范
web前端整体的性能考虑,你的优化思路是什么?
答案举例:
【参考雅虎优化规则】
减少http请求【精灵图,合理缓存,资源合并、压缩】,图片懒加载
将外部js文件置底
将css放在页面最上面
避免在CSS中使用Expressions
减少关键资源的个数和大小(webpack拆/合包,懒加载等)
减少关键资源RTT【往返时延】的时间(Gzip压缩,边缘节点CDN)
JS代码不可占用主线程太久,与首屏无关的脚本加上延后处理(async/defer)属性,与无关的交给Web Worker。
CSS用对选择器(尽可能绑定Class或Id),否则会遍历多次。
移动端的点击事件有延迟,时间是多久?为什么会有这个延迟?
答案:有300ms的延迟,为了实现safari的双击事件的设计,浏览器要知道你是不是要双击操作。
平时如何管理你的项目,如何设计大规模并发架构?
答案:先期团队必须确定好全局样式(global.css),编码模式(utf-8)等等,编写习惯必须一致【确定好团队开发代码规范文档】。每个人负责的模块写好注释【模块功能,参数说明,编写时间,编写人】。文件做好分类处理。
谈谈你认为怎样做才能使项目做的更好。
答案:考虑问题的深入,在开发时不能仅仅停留在完成任务上,要认真思考及时发现问题。要精益求精,对自己写的代码负责。
项目中遇到的难点,以及解决思路。
埋点数据上报的方案做过么?【统计用户的页面浏览时间,退出率,使用人数等等】
前端架构思考,你是如何考量部门的技术栈的?
前端重构思考,老项目在新业务紧急与重构技术债务间如何衡量轻重?
————————————————
版权声明:本文为CSDN博主「超级吴小迪」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43606158/article/details/89811189
1. 达达京东到家
笔试:
都是些基础选择题,考察计算机网络,事件循环机制,闭包,this 这些。
一面:
三次握手和四次挥手详细介绍
TCP 有哪些手段保证可靠交付
URL 从输入到页面渲染全流程
如何预防中间人攻击
DNS 解析会出错吗,为什么
ES6 的 Set 内部实现
如何应对流量劫持
算法:top-K 问题,分成 top-1,top-2,top-K 三小问
二面:
跨域
webpack 的 plugins 和 loaders 的实现原理
vue 和 react 谈谈区别和选型考虑
webpack 如何优化编译速度
事件循环机制,node 和浏览器的事件循环机制区别
三面:
单元测试编写有哪些原则
一个大型项目如何分配前端开发的工作
怼项目
2. 达观数据
笔试:
同样都是基础题,注意有两道算法:柯里化通用实现和 two-sum 问题。
一面:
typescript 有什么好处
vue 项目中如何约束 rxjs 数据的类型
rxjs 高阶数据流定义,常用高阶数据流操作符
二三面:
围绕着我的简历问项目细节,侧重于 rxjs 和 typescript 这块内容。
3. 英语流利说
一面:
JWT 优缺点
选择器优先级
基本数据类型
RxJS 冷热流区别
RxJS 调试方法
nginx 负载均衡配置
前端性能优化手段
针对 React 的性能优化手段
301 302 307 308 401 403
vue 的 nextTick 实现原理以及应用场景
vue 组件间通信
谈谈 XSS 防御,以及 Content-Security-Policy 细节
二面:
场景题:一个气球从右上角移动到中间,然后抖动,如何实现
场景题:一个关于外边距合并的高度计算
mobx-react 如何驱动 react 组件重渲染
forceUpdate 经历了哪些生命周期,子组件呢?
React key 场景题:列表使用 index 做 key,删除其中一个后,如何表现?
算法:实现 setter(obj, ‘a.b.c’ ,val)
RxJS 相对于其他状态管理方案的优势?
三面:
手写冒泡排序
JWT 细节,适用场景
跨域
方案题:不同前端技术栈的项目,如何实现一套通用组件方案?
4. 拍拍贷
一面:
ES6 特性
闭包和 this 一起谈谈
postcss 配置
Promise 内部实现原理
vuex, mobx, redux 各自的特点和区别
react 生命周期
各方面谈谈性能优化
serviceworker 如何保证离线缓存资源更新
virtual dom 有哪些好处
然后换了个有黑板的面试间,狂怼项目,各方面都问到了。
二面:
总监面,把刚才一黑板的项目架构图全部擦掉,再来谈一遍。
三面:
Vue3 proxy 解决了哪些问题?
Vue 响应式原理
发布订阅模式和观察者模式的异同
图片懒加载实现
css 垂直居中
CI/CD 流程
谈谈性能优化
5. 天壤智能
一面:
react 生命周期
key 的作用
hooks
vue 和 react 区别,选型考虑
canvas 优化绘制性能
webpack 性能优化手段
事件循环
如何解决同步调用代码耗时太高的问题
手写 Promise 实现
二面:
场景题:如何实现登录功能
聊项目
三面:
聊项目
5. 拼多多
一面:
Promise 实现原理
vue 组件间通信
性能优化
vuex 数据流动过程
谈谈 css 预处理器机制
算法:Promise 串行
二面:
CI/CD 整体流程
性能优化
SSR 对性能优化的提升在哪里
怼项目
6.猫眼电影
一面:
vue 组件间通信
react 和 vue 更新机制的区别
Vue3 proxy 的优劣
性能优化
symbol 应用
深拷贝
怼项目
二面:
dns 解析流程
怼项目
6.米哈游
一面:
跨域
vue 和 react 选型和比较
ssr 优缺点
性能优化
贝塞尔曲线
怼项目
7.bilibili
一面:
Vue3 proxy 优缺点
ES6 特性
Vue 组件间通信
性能优化
ssr 性能优化,node 中间层细节处理
怼项目
二面:
这一面比较特别,和之前的面试都不太一样,是知乎早已关注很久的之昊老师面的。
之前的面试大概是属于主导权在我这边,面试官倾听的比较多,搭配上少量提问。而这一面基本全程处于被之昊老师教育加吊打的状态,感觉之昊老师说的话比我还多了,针对问出的每个点会在我回答的基础上做更多的延伸说明,没有局限到具体的技术方案或者细节代码,更多的是谈到了一些方法论或者说作为一个优秀的开发者面对一些问题时比编码更高的思维层面上的处理方式。收获很大,聊到了很多之前工作中都没有考虑过的东西。这就是大佬的世界吗.jpg。
8.阅文
一面:
如何编写 loaders 和 plugins
webpack 热更新原理
vue 和 react 组件通信
性能优化
谈谈 eleme 框架源码
谈谈项目
个人兴趣爱好
8.阿里
笔试题
第一题:将数组扁平化并去除其中重复数据,最终得到一个升序且不重复的数组
第二题:
说明:实现一个方法,用于比较两个版本号(version1、version2)
如果version1 > version2,返回1;如果version1 < version2,返回-1,其他情况返回0
版本号规则x.y.z,xyz均为大于等于0的整数,至少有x位
示例:
compareVersion(‘0.1’, ‘1.1.1’); // 返回-1
compareVersion(‘13.37’, ‘1.2 ‘); // 返回1
compareVersion(‘1.1’, ‘1.1.0’); // 返回0
第三题:找到字符串中最大回文子串,例如 ‘3434356’ 的最长回文子串是 ‘34343’。回文是指对称的字符串,如:‘abccba’。找到字符串中最大回文子串
9.新希望
面试题
我做一个搜索,实时的去进行筛选数据,做一个简单的防抖,然后如何保证我的请求回来的结果是我最后一次的查询条件的结果
一百个异步请求,如何捕捉请求失败的有哪些,如何获取最后一个请求结果?
————————————————
版权声明:本文为CSDN博主「超级吴小迪」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43606158/article/details/89640672
266、描述一个印象最深的项目,在其中担任的角色,解决什么问题
267、http状态码。。。401和403区别?
268、描述下二分查找
269、为什么选择前端,如何学习的,看了哪些书,《js高级程序设计》和《你不知道的js》有什么区别,看书,看博客,看公众号三者的时间是如何分配的?
270、如何评价BAT?
271、描述下在实习中做过的一个项目,解决了什么问题,在其中担任了什么角色?这个过程存在什么问题,有什么值得改进的地方?
272、如何看待加班,如果有个项目需要连续一个月加班,你怎么看?
273、遇到的压力最大的一件事是什么?如何解决的?
274、平时有什么爱好
275、自身有待改进的地方
276、n长的数组放入n+1个数,不能重复,找出那个缺失的数
277、手里有什么offer
278、你对于第一份工作最看重的三个方面是什么?
279、如何评价现在的前端?
280、用原生js实现复选框选择以及全选非全选功能
281、用4个颜色给一个六面体上色有多少种情况
282、amd和cmd区别
283、为什么选择前端,移动端性能优化
284、vue的特点?双向数据绑定是如何实现的
285、Object.defineProperty
286、算法题:数组去重,去除重复两次以上的元素,代码题:嵌套的ul-li结构,根据input中输入的内容,去除相应的li节点,且如果某个嵌套的ul下面的li都被移除,则该ul的父li节点也要被移除
287、页面加载过程
288、浏览器如何实现图片缓存
————————————————
版权声明:本文为CSDN博主「傻傻的鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_22944825/article/details/78169321
HTML&CSS: 对Web标准的理解、浏览器内核差异、兼容性、hack、CSS基本功:布局、盒子模型、选择器优先级及使用、HTML5、CSS3、移动端适应。
- JavaScript: 数据类型、面向对象、继承、闭包、插件、作用域、跨域、原型链、模块化、自定义事件、内存泄漏、事件机制、异步装载回调、模板引擎、Nodejs、JSON、ajax等。
- 其他: HTTP、安全、正则、优化、重构、响应式、移动端、团队协作、可维护、SEO、UED、架构、职业生涯
1.请你谈谈Cookie的弊端
cookie虽然在持久保存客户端数据提供了方便,分担了服务器存储的负担,但还是有很多局限性的。
第一:每个特定的域名下最多生成20个cookie
1.IE6或更低版本最多20个cookie2.IE7和之后的版本最后可以有50个cookie。3.Firefox最多50个cookie4.chrome和Safari没有做硬性限制
IE和Opera 会清理近期最少使用的cookie,Firefox会随机清理cookie。
cookie的最大大约为4096字节,为了兼容性,一般不能超过4095字节。
IE 提供了一种存储可以持久化用户数据,叫做uerData,从IE5.0就开始支持。每个数据最多128K,每个域名下最多1M。这个持久化数据放在缓存中,如果缓存没有清理,那么会一直存在。
优点:极高的扩展性和可用性1.通过良好的编程,控制保存在cookie中的session对象的大小。
2.通过加密和安全传输技术(SSL),减少cookie被破解的可能性。
3.只在cookie中存放不敏感数据,即使被盗也不会有重大损失。
4.控制cookie的生命期,使之不会永远有效。偷盗者很可能拿到一个过期的cookie。
缺点:1.<span class="javascript">Cookie</span>数量和长度的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉。
2.安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。即使加密也与事无补,因为拦截者并不需要知道cookie的意义,他只要原样转发cookie就可以达到目的了。
3.有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。
2.浏览器本地存储
在较高版本的浏览器中,js提供了sessionStorage和globalStorage。在HTML5中提供了localStorage来取代globalStorage。
html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage。
sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。
而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。
3.web storage和cookie的区别
Web Storage的概念和cookie相似,区别是它是为了更大容量存储设计的。Cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可以跨域调用。
除此之外,Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie。
但是Cookie也是不可以或缺的:Cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生
浏览器的支持除了IE7及以下不支持外,其他标准浏览器都完全支持(ie及FF需在web服务器里运行),值得一提的是IE总是办好事,例如IE7、IE6中的UserData其实就是javascript本地存储的解决方案。通过简单的代码封装可以统一到所有的浏览器都支持web storage。
localStorage和sessionStorage都具有相同的操作方法,例如setItem、getItem和removeItem等
CSS 相关问题
display:none和visibility:hidden的区别?
display:none 隐藏对应的元素,在文档布局中不再给它分配空间,它各边的元素会合拢,就当他从来不存在。visibility:hidden 隐藏对应的元素,但是在文档布局中仍保留原来的空间。
CSS中 link 和@import 的区别是?A:(1) link属于HTML标签,而@import是CSS提供的; (2) 页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;(3) import只在IE5以上才能识别,而link是HTML标签,无兼容问题; (4) link方式的样式的权重 高于@import的权重.
position的absolute与fixed共同点与不同点A:共同点:
1.改变行内元素的呈现方式,display被置为block;2.让元素脱离普通流,不占据空间;3.默认会覆盖到非定位元素上
B不同点:
absolute的”根元素“是可以设置的,而fixed的”根元素“固定为浏览器窗口。当你滚动网页,fixed元素与浏览器窗口之间的距离是不变的。
介绍一下CSS的盒子模型?1)有两种, IE 盒子模型、标准 W3C 盒子模型;IE的content部分包含了 border 和 pading;
2)盒模型: 内容(content)、填充(padding)、边界(margin)、 边框(border).
CSS 选择符有哪些?哪些属性可以继承?优先级算法如何计算? CSS3新增伪类有那些?
* 1.id选择器( # myid)2.类选择器(.myclassname)3.标签选择器(div, h1, p)4.相邻选择器(h1 + p)5.子选择器(ul > li)6.后代选择器(li a)7.通配符选择器( * )8.属性选择器(a[rel = “external”])9.伪类选择器(a: hover, li:nth-child)- 可继承的样式: font-size font-family color, text-indent;
- 不可继承的样式:border padding margin width height ;
- 优先级就近原则,同权重情况下样式定义最近者为准;
- 载入样式以最后载入的定位为准;
优先级为:!important > id > class > tagimportant 比 内联优先级高,但内联比 id 要高CSS3新增伪类举例:p:first-of-type 选择属于其父元素的首个 <p> 元素的每个 <p> 元素。p:last-of-type 选择属于其父元素的最后 <p> 元素的每个 <p> 元素。p:only-of-type 选择属于其父元素唯一的 <p> 元素的每个 <p> 元素。p:only-child 选择属于其父元素的唯一子元素的每个 <p> 元素。p:nth-child(2) 选择属于其父元素的第二个子元素的每个 <p> 元素。:enabled :disabled 控制表单控件的禁用状态。:checked 单选框或复选框被选中。
列出display的值,说明他们的作用。position的值, relative和absolute分别是相对于谁进行定位的?
1.block 象块类型元素一样显示。inline 缺省值。象行内元素类型一样显示。inline-block 象行内元素一样显示,但其内容象块类型元素一样显示。list-item 象块类型元素一样显示,并添加样式列表标记。2.*absolute生成绝对定位的元素,相对于 static 定位以外的第一个祖先元素进行定位。*fixed (老IE不支持)生成绝对定位的元素,相对于浏览器窗口进行定位。*relative生成相对定位的元素,相对于其在普通流中的位置进行定位。- static 默认值。没有定位,元素出现在正常的流中
*(忽略 top, bottom, left, right z-index 声明)。- inherit 规定从父元素继承 position 属性的值。
CSS3有哪些新特性?
CSS3实现圆角(border-radius),阴影(box-shadow),对文字加特效(text-shadow、),线性渐变(gradient),旋转(transform)transform:rotate(9deg) scale(0.85,0.90) translate(0px,-30px) skew(-9deg,0deg);//旋转,缩放,定位,倾斜增加了更多的CSS选择器 多背景 rgba在CSS3中唯一引入的伪元素是::selection.媒体查询,多栏布局border-image
为什么要初始化CSS样式。
因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面显示差异。当然,初始化样式会对SEO有一定的影响,但鱼和熊掌不可兼得,但力求影响最小的情况下初始化。最简单的初始化方法就是: {padding: 0; margin: 0;} (不建议)淘宝的样式初始化:body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { margin:0; padding:0; }body, button, input, select, textarea { font:12px/1.5tahoma, arial, \5b8b\4f53; }h1, h2, h3, h4, h5, h6{ font-size:100%; }address, cite, dfn, em, var { font-style:normal; }code, kbd, pre, samp { font-family:couriernew, courier, monospace; }small{ font-size:12px; }ul, ol { list-style:none; }a { text-decoration:none; }a:hover { text-decoration:underline; }sup { vertical-align:text-top; }sub{ vertical-align:text-bottom; }legend { color:#000; }fieldset, img { border:0; }button, input, select, textarea { font-size:100%; }table { border-collapse:collapse; border-spacing:0; }
对BFC规范的理解? BFC,块级格式化上下文,一个创建了新的BFC的盒子是独立布局的,盒子里面的子元素的样式不会影响到外面的元素。在同一个BFC中的两个毗邻的块级盒在垂直方向(和布局方向有关系)的margin会发生折叠。
(W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行布局,以及与其他元素的关系和相互作用。)
解释下 CSS sprites,以及你要如何在页面或网站中使用它。CSS Sprites其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位,background-position可以用数字能精确的定位出背景图片的位置。这样可以减少很多图片请求的开销,因为请求耗时比较长;请求虽然可以并发,但是也有限制,一般浏览器都是6个。对于未来而言,就不需要这样做了,因为有了<span class="javascript">http2</span>。
html部分
说说你对语义化的理解?1,去掉或者丢失样式的时候能够让页面呈现出清晰的结构
2,有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;
3,方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;
4,便于团队开发和维护,语义化更具可读性,是下一步吧网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化。
Doctype作用? 严格模式与混杂模式如何区分?它们有何意义?(1)、<!DOCTYPE> 声明位于文档中的最前面,处于 <html> 标签之前。告知浏览器以何种模式来渲染文档。
(2)、严格模式的排版和 JS 运作模式是 以该浏览器支持的最高标准运行。
(3)、在混杂模式中,页面以宽松的向后兼容的方式显示。模拟老式浏览器的行为以防止站点无法工作。
(4)、DOCTYPE不存在或格式不正确会导致文档以混杂模式呈现。
你知道多少种Doctype文档类型? 该标签可声明三种 DTD 类型,分别表示严格版本、过渡版本以及基于框架的 HTML 文档。
HTML 4.01 规定了三种文档类型:Strict、Transitional 以及 Frameset。
XHTML 1.0 规定了三种 XML 文档类型:Strict、Transitional 以及 Frameset。
Standards (标准)模式(也就是严格呈现模式)用于呈现遵循最新标准的网页,而 Quirks
(包容)模式(也就是松散呈现模式或者兼容模式)用于呈现为传统浏览器而设计的网页。
HTML与XHTML——二者有什么区别区别:
1.所有的标记都必须要有一个相应的结束标记
2.所有标签的元素和属性的名字都必须使用小写
3.所有的XML标记都必须合理嵌套
4.所有的属性必须用引号“”括起来
5.把所有<和&特殊符号用编码表示
6.给所有属性赋一个值
7.不要在注释内容中使“—”
8.图片必须有说明文字
常见兼容性问题? png24位的图片在iE6浏览器上出现背景,解决方案是做成PNG8.也可以引用一段脚本处理.
浏览器默认的margin和padding不同。解决方案是加一个全局的{margin:0;padding:0;}来统一。
IE6双边距bug:块属性标签float后,又有横行的margin情况下,在ie6显示margin比设置的大。
浮动ie产生的双倍距离(IE6双边距问题:在IE6下,如果对元素设置了浮动,同时又设置了margin-left或margin-right,margin值会加倍。)
#box{ float:left; width:10px; margin:0 0 0 100px;}
这种情况之下IE会产生20px的距离,解决方案是在float的标签样式控制中加入 ——display:inline;将其转化为行内属性。(这个符号只有ie6会识别)
渐进识别的方式,从总体中逐渐排除局部。
首先,巧妙的使用“\9”这一标记,将IE游览器从所有情况中分离出来。
接着,再次使用“+”将IE8和IE7、IE6分离开来,这样IE8已经独立识别。
css
.bb{
background-color:#f1ee18;/所有识别/
.background-color:#00deff\9; /IE6、7、8识别/
+background-color:#a200ff;/IE6、7识别/
_background-color:#1e0bd1;/IE6识别/
}
IE下,可以使用获取常规属性的方法来获取自定义属性,
也可以使用getAttribute()获取自定义属性;
Firefox下,只能使用getAttribute()获取自定义属性.
解决方法:统一通过getAttribute()获取自定义属性.
IE下,event对象有x,y属性,但是没有pageX,pageY属性;
Firefox下,event对象有pageX,pageY属性,但是没有x,y属性.
解决方法:(条件注释)缺点是在IE浏览器下可能会增加额外的HTTP请求数。
Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示,
可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决.
超链接访问过后hover样式就不出现了 被点击访问过的超链接样式不在具有hover和active了解决方法是改变CSS属性的排列顺序:
L-V-H-A : a:link {} a:visited {} a:hover {} a:active {}
怪异模式问题:漏写DTD声明,Firefox仍然会按照标准模式来解析网页,但在IE中会触发怪异模式。为避免怪异模式给我们带来不必要的麻烦,最好养成书写DTD声明的好习惯。现在可以使用html5;”>http://www.w3.org/TR/html5/single-page.html)推荐的写法:<doctype html>
上下margin重合问题
ie和ff都存在,相邻的两个div的margin-left和margin-right不会重合,但是margin-top和margin-bottom却会发生重合。
解决方法,养成良好的代码编写习惯,同时采用margin-top或者同时采用margin-bottom。
ie6对png图片格式支持不好(引用一段脚本处理)
解释下浮动和它的工作原理?清除浮动的技巧
浮动元素脱离文档流,不占据空间。浮动元素碰到包含它的边框或者浮动元素的边框停留。1.使用空标签清除浮动。这种方法是在所有浮动标签后面添加一个空标签 定义css clear:both. 弊端就是增加了无意义标签。2.使用overflow。给包含浮动元素的父标签添加css属性 overflow:auto; zoom:1; zoom:1用于兼容IE6。3.使用after伪对象清除浮动。该方法只适用于非IE浏览器。具体写法可参照以下示例。使用中需注意以下几点。一、该方法中必须为需要清除浮动元素的伪对象中设置 height:0,否则该元素会比实际高出若干像素;
浮动元素引起的问题和解决办法?浮动元素引起的问题:
(1)父元素的高度无法被撑开,影响与父元素同级的元素
(2)与浮动元素同级的非浮动元素会跟随其后
(3)若非第一个元素浮动,则该元素之前的元素也需要浮动,否则会影响页面显示的结构
解决方法:
使用CSS中的clear:both;属性来清除元素的浮动可解决2、3问题,对于问题1,添加如下样式,给父元素添加clearfix样式:
.clearfix:after{content: “.”;display: block;height: 0;clear: both;visibility: hidden;}.clearfix{display: inline-block;} / for IE/Mac /
清除浮动的几种方法:1,额外标签法,
“clear:both;”>(缺点:不过这个办法会增加额外的标签使HTML结构看起来不够简洁。)
2,使用after伪类
#parent:after{
content:“.”;
height:0;
visibility:hidden;
display:block;
clear:both;
}
3,浮动外部元素
4,设置<span class="javascript">overflow</span>为<span class="javascript">hidden</span>或者auto
IE 8以下版本的浏览器中的盒模型有什么不同
IE8以下浏览器的盒模型中定义的元素的宽高不包括内边距和边框
DOM操作——怎样添加、移除、移动、复制、创建和查找节点。
(1)创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
(2)添加、移除、替换、插入
appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子节点前插入一个新的子节点
(3)查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
getElementById() //通过元素Id,唯一性
html5有哪些新特性、移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5?
HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加。
拖拽释放(Drag and drop) API
语义化更好的内容标签(header,nav,footer,aside,article,section)
音频、视频API(audio,video)
画布(Canvas) API
地理(Geolocation) API
本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
sessionStorage 的数据在浏览器关闭后自动删除
表单控件,calendar、date、time、email、url、search
新的技术webworker, websocket, Geolocation
移除的元素
纯表现的元素:basefont,big,center,font, s,strike,tt,u;
对可用性产生负面影响的元素:frame,frameset,noframes;
支持HTML5新标签:
IE8/IE7/IE6支持通过document.createElement方法产生的标签,
可以利用这一特性让这些浏览器支持HTML5新标签,
浏览器支持新标签后,还需要添加标签默认的样式:
当然最好的方式是直接使用成熟的框架、使用最多的是html5shim框架
如何区分: DOCTYPE声明\新增的结构元素\功能元素
iframe的优缺点?
1.<iframe>优点:
解决加载缓慢的第三方内容如图标和广告等的加载问题
Security sandbox
并行加载脚本
2.<iframe>的缺点:
iframe会阻塞主页面的Onload事件;
即时内容为空,加载也需要时间
没有语意
如何实现浏览器内多个标签页之间的通信?
调用localstorge、cookies等本地存储方式
webSocket如何兼容低浏览器?
Adobe Flash Socket 、 ActiveX HTMLFile (IE) 、 基于 multipart 编码发送 XHR 、 基于长轮询的 XHR
线程与进程的区别
一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
你如何对网站的文件和资源进行优化?
期待的解决方案包括:
文件合并
文件最小化/文件压缩
使用 CDN 托管
缓存的使用(多个域名来提供缓存)
其他
请说出三种减少页面加载时间的方法。
1.优化图片
2.图像格式的选择(GIF:提供的颜色较少,可用在一些对颜色要求不高的地方)
3.优化CSS(压缩合并css,如margin-top,margin-left…)
4.网址后加斜杠(如www.campr.com/目录,会判断这个“目录是什么文件类型,或者是目录。)
5.标明高度和宽度(如果浏览器没有找到这两个参数,它需要一边下载图片一边计算大小,如果图片很多,浏览器需要不断地调整页面。这不但影响速度,也影响浏览体验。
当浏览器知道了高度和宽度参数后,即使图片暂时无法显示,页面上也会腾出图片的空位,然后继续加载后面的内容。从而加载时间快了,浏览体验也更好了。)
6.减少http请求(合并文件,合并图片)。
你都使用哪些工具来测试代码的性能?
Profiler, JSPerf(http://jsperf.com/nexttick-vs-setzerotimeout-vs-settimeout), Dromaeo
什么是 FOUC(无样式内容闪烁)?你如何来避免 FOUC?
FOUC - Flash Of Unstyled Content 文档样式闪烁
<style type=“text/css” media=“all”>@import “../fouc.css”;</style>
而引用CSS文件的@import就是造成这个问题的罪魁祸首。IE会先加载整个HTML文档的DOM,然后再去导入外部的CSS文件,因此,在页面DOM加载完成到CSS导入完成中间会有一段时间页面上的内容是没有样式的,这段时间的长短跟网速,电脑速度都有关系。
解决方法简单的出奇,只要在<head>之间加入一个<link>或者<script>元素就可以了。
null和undefined的区别?
null是一个表示”无”的对象,转为数值时为0;undefined是一个表示”无”的原始值,转为数值时为NaN。
当声明的变量还未被初始化时,变量的默认值为undefined。null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。
undefined表示”缺少值”,就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
null表示”没有对象”,即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
new操作符具体干了什么呢?
1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2、属性和方法被加入到 this 引用的对象中。
3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。
var obj = {};
obj.proto = Base.prototype;
Base.call(obj);
JSON 的了解?
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小{‘age’:‘12’, ‘name’:‘back’}
js延迟加载的方式有哪些?defer和async、动态创建DOM方式(创建script,插入到DOM中,加载完毕后callBack)、按需异步载入js
如何解决跨域问题? jsonp、 document.domain+iframe、window.name、window.postMessage、服务器上设置代理页面
jsonp的原理是动态插入script标签
具体参见:详解js跨域问题
documen.write和 innerHTML的区别document.write只能重绘整个页面
innerHTML可以重绘页面的一部分
.call() 和 .apply() 的区别和作用?
作用:动态改变某个类的某个方法的运行环境。
区别参见:JavaScript学习总结(四)function函数部分
哪些操作会造成内存泄漏?内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。
垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。
setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
详见:详解js变量、作用域及内存
JavaScript中的作用域与变量声明提升?
详见:详解JavaScript函数模式
如何判断当前脚本运行在浏览器还是node环境中?通过判断Global对象是否为window,如果不为window,当前脚本没有运行在浏览器中
其他问题?
你遇到过比较难的技术问题是?你是如何解决的?
常使用的库有哪些?常用的前端开发工具?开发过什么应用或组件?
列举IE 与其他浏览器不一样的特性?
99%的网站都需要被重构是那本书上写的? 网站重构:应用web标准进行设计(第2版)
什么叫优雅降级和渐进增强?优雅降级:Web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会检查以确认它们是否能正常工作。由于IE独特的盒模型布局问题,针对不同版本的IE的hack实践过优雅降级了,为那些无法支持功能的浏览器增加候选方案,使之在旧式浏览器上以某种形式降级体验却不至于完全失效.
渐进增强:从被所有浏览器支持的基本功能开始,逐步地添加那些只有新式浏览器才支持的功能,向页面增加无害于基础浏览器的额外样式和功能的。当浏览器支持时,它们会自动地呈现出来并发挥作用。
详见:css学习归纳总结(一)
WEB应用从服务器主动推送Data到客户端有那些方式?
对Node的优点和缺点提出了自己的看法?(优点)因为Node是基于事件驱动和无阻塞的,所以非常适合处理并发请求,
因此构建在Node上的代理服务器相比其他技术实现(如Ruby)的服务器表现要好得多。
此外,与Node代理服务器交互的客户端代码是由javascript语言编写的,
因此客户端和服务器端都用同一种语言编写,这是非常美妙的事情。
(缺点)Node是一个相对新的开源项目,所以不太稳定,它总是一直在变,
而且缺少足够多的第三方库支持。看起来,就像是Ruby/Rails当年的样子。
除了前端以外还了解什么其它技术么?你最最厉害的技能是什么?
你常用的开发工具是什么,为什么?
对前端界面工程师这个职位是怎么样理解的?它的前景会怎么样?前端是最贴近用户的程序员,比后端、数据库、产品经理、运营、安全都近。
1、实现界面交互
2、提升用户体验
3、有了Node.js,前端可以实现服务端的一些事情
前端是最贴近用户的程序员,前端的能力就是能让产品从 90分进化到 100 分,甚至更好,
参与项目,快速高质量完成实现效果图,精确到1px;
与团队成员,UI设计,产品经理的沟通;
做好的页面结构,页面重构和用户体验;
处理hack,兼容、写出优美的代码格式;
针对服务器的优化、拥抱最新前端技术。
你在现在的团队处于什么样的角色,起到了什么明显的作用?
你认为怎样才是全端工程师(Full Stack developer)?
介绍一个你最得意的作品吧?
项目中遇到什么问题?如何解决?
你的优点是什么?缺点是什么?
如何管理前端团队?
最近在学什么?能谈谈你未来3,5年给自己的规划吗?
你有哪些性能优化的方法?
(详情请看雅虎14条性能优化原则)。 (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) 图片预加载,将样式表放在顶部,将脚本放在底部 加上时间戳。
http状态码有那些?分别代表是什么意思?100-199 用于指定客户端应相应的某些动作。
200-299 用于表示请求成功。
300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息。
400-499 用于指出客户端的错误。400 1、语义有误,当前请求无法被服务器理解。401 当前请求需要用户验证 403 服务器已经理解请求,但是拒绝执行它。
500-599 用于支持服务器错误。 503 – 服务不可用
详情:http://segmentfault.com/blog/trigkit4/1190000000691919
一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么? 分为4个步骤:
(1),当发送一个URL请求时,不管这个URL是Web页面的URL还是Web页面上每个资源的URL,浏览器都会开启一个线程来处理这个请求,同时在远程DNS服务器上启动一个DNS查询。这能使浏览器获得请求对应的IP地址。
(2), 浏览器与远程Web服务器通过TCP三次握手协商来建立一个TCP/IP连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在 浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,而后服务器应答并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。
(3),一旦TCP/IP连接建立,浏览器会通过该连接向远程服务器发送HTTP的GET请求。远程服务器找到资源并使用HTTP响应返回该资源,值为200的HTTP响应状态表示一个正确的响应。
(4),此时,Web服务器提供资源服务,客户端开始下载资源。
请求返回后,便进入了我们关注的前端模块
简单来说,浏览器会解析HTML生成DOM Tree,其次会根据CSS生成CSS Rule Tree,而javascript又可以根据DOM API操作DOM
详情:从输入 URL 到浏览器接收的过程中发生了什么事情?
平时如何管理你的项目?先期团队必须确定好全局样式(globe.css),编码模式(utf-8) 等;
编写习惯必须一致(例如都是采用继承式的写法,单样式都写成一行);
标注样式编写人,各模块都及时标注(标注关键样式调用的地方);
页面进行标注(例如 页面 模块 开始和结束);
CSS跟HTML 分文件夹并行存放,命名都得统一(例如style.css);
JS 分文件夹存放 命名以该JS功能为准的英文翻译。
图片采用整合的 images.png png8 格式文件使用 尽量整合在一起使用方便将来的管理
说说最近最流行的一些东西吧?常去哪些网站?Node.js、Mongodb、npm、MVVM、MEAN、three.js,React 。
网站:w3cfuns,sf,hacknews,CSDN,慕课,博客园,InfoQ,w3cplus等
javascript对象的几种创建方式1,工厂模式
2,构造函数模式
3,原型模式
4,混合构造函数和原型模式
5,动态原型模式
6,寄生构造函数模式
7,稳妥构造函数模式
javascript继承的6种方法1,原型链继承
2,借用构造函数继承
3,组合继承(原型+借用构造)
4,原型式继承
5,寄生式继承
6,寄生组合式继承
详情:JavaScript继承方式详解
ajax过程(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
(3)设置响应HTTP请求状态变化的函数.
(4)发送HTTP请求.
(5)获取异步调用返回的数据.
(6)使用JavaScript和DOM实现局部刷新.
详情:JavaScript学习总结(七)Ajax和Http状态字
异步加载和延迟加载1.异步加载的方案: 动态插入script标签
2.通过ajax去获取js代码,然后通过eval执行
3.script标签上添加defer或者async属性
4.创建并插入iframe,让它异步执行js
5.延迟加载:有些 js 代码并不是页面初始化的时候就立刻需要的,而稍后的某些情况才需要的。
前端安全问题? (XSS,sql注入,CSRF)
CSRF:是跨站请求伪造,很明显根据刚刚的解释,他的核心也就是请求伪造,通过伪造身份提交POST和GET请求来进行跨域的攻击。
完成CSRF需要两个步骤:
1.登陆受信任的网站A,在本地生成COOKIE
2.在不登出A的情况下,或者本地COOKIE没有过期的情况下,访问危险网站B。
ie各版本和chrome可以并行下载多少个资源IE6 两个并发,iE7升级之后的6个并发,之后版本也是6个
Firefox,chrome也是6个
javascript里面的继承怎么实现,如何避免原型链上面的对象共享用构造函数和原型链的混合模式去实现继承,避免对象共享可以参考经典的extend()函数,很多前端框架都有封装的,就是用一个空函数当做中间变量
grunt, YUI compressor 和 google clojure用来进行代码压缩的用法。YUI Compressor 是一个用来压缩 JS 和 CSS 文件的工具,采用Java开发。
使用方法:
//压缩JS
java -jar yuicompressor-2.4.2.jar —type js —charset utf-8 -v src.js > packed.js
//压缩CSS
java -jar yuicompressor-2.4.2.jar —type css —charset utf-8 -v src.css > packed.css
详情请见:你需要掌握的前端代码性能优化工具
Flash、Ajax各自的优缺点,在使用中如何取舍?1、Flash ajax对比
Flash适合处理多媒体、矢量图形、访问机器;对CSS、处理文本上不足,不容易被搜索。
Ajax对CSS、文本支持很好,支持搜索;多媒体、矢量图形、机器访问不足。
共同点:与服务器的无刷新传递消息、用户离线和在线状态、操作DOM
请解释一下 JavaScript 的同源策略。
概念:同源策略是客户端脚本(尤其是Javascript)的重要的安全度量标准。它最早出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载。
这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议。
指一段脚本只能读取来自同一来源的窗口和文档的属性。
为什么要有同源限制?
我们举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。
什么是 “use strict”; ? 使用它的好处和坏处分别是什么?
ECMAscript 5添加了第二种运行模式:”严格模式”(strict mode)。顾名思义,这种模式使得Javascript在更严格的条件下运行。
设立”严格模式”的目的,主要有以下几个:- 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的一些不安全之处,保证代码运行的安全;
- 提高编译器效率,增加运行速度;
- 为未来新版本的Javascript做好铺垫。
注:经过测试IE6,7,8,9均不支持严格模式。
缺点:
现在网站的JS 都会进行压缩,一些文件用了严格模式,而另一些没有。这时这些本来是严格模式的文件,被 merge 后,这个串就到了文件的中间,不仅没有指示严格模式,反而在压缩后浪费了字节。
GET和POST的区别,何时使用POST? GET:一般用于信息获取,使用URL传递参数,对所发送信息的数量也有限制,一般在2000个字符
POST:一般用于修改服务器上的资源,对所发送的信息没有限制。
GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值,
也就是说Get是通过地址栏来传值,而Post是通过提交表单来传值。
然而,在以下情况中,请使用 POST 请求:
无法使用缓存文件(更新服务器上的文件或数据库)
向服务器发送大量数据(POST 没有数据量限制)
发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
哪些地方会出现css阻塞,哪些地方会出现js阻塞?
js的阻塞特性:所有浏览器在下载JS的时候,会阻止一切其他活动,比如其他资源的下载,内容的呈现等等。直到JS下载、解析、执行完毕后才开始继续并行下载其他资源并呈现内容。为了提高用户体验,新一代浏览器都支持并行下载JS,但是JS下载仍然会阻塞其它资源的下载(例如.图片,css文件等)。
由于浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以就会阻塞其他的下载和呈现。
嵌入JS会阻塞所有内容的呈现,而外部JS只会阻塞其后内容的显示,2种方式都会阻塞其后资源的下载。也就是说外部样式不会阻塞外部脚本的加载,但会阻塞外部脚本的执行。
CSS怎么会阻塞加载了?CSS本来是可以并行下载的,在什么情况下会出现阻塞加载了(在测试观察中,IE6下CSS都是阻塞加载)
当CSS后面跟着嵌入的JS的时候,该CSS就会出现阻塞后面资源下载的情况。而当把嵌入JS放到CSS前面,就不会出现阻塞的情况了。
根本原因:因为浏览器会维持html中css和js的顺序,样式表必须在嵌入的JS执行前先加载、解析完。而嵌入的JS会阻塞后面的资源加载,所以就会出现上面CSS阻塞下载的情况。
嵌入JS应该放在什么位置? 1、放在底部,虽然放在底部照样会阻塞所有呈现,但不会阻塞资源下载。
2、如果嵌入JS放在head中,请把嵌入JS放在CSS头部。
3、使用defer(只支持IE)
4、不要在嵌入的JS中调用运行时间较长的函数,如果一定要用,可以用<span class="javascript">setTimeout</span>来调用
*Javascript无阻塞加载具体方式
- 将脚本放在底部。还是放在head中,用以保证在js加载前,能加载出正常显示的页面。
2.让js最后加载
例如引入外部js脚本文件时,如果放入html的head中,则页面加载前该js脚本就会被加载入页面,而放入body中,则会按照页面从上倒下的加载顺序来运行JavaScript的代码~~~ 所以我们可以把js外部引入的文件放到页面底部,来让js最后引入,从而加快页面加载速度
3.上述方法2也会偶尔让你收到Google页面速度测试工具的”延迟加载javascript”警告。所以这里的解决方案将是来自Google帮助页面的推荐方案。
//这些代码应被放置在标签前(接近HTML文件底部)
这段代码意思是等到整个文档加载完后,再加载外部文件”defer.js”。
使用此段代码的步骤:
1).复制上面代码
2).粘贴代码到HTML的标签前 (靠近HTML文件底部)
3).修改”defer.js”为你的外部JS文件名
4).确保你文件路径是正确的。例如:如果你仅输入”defer.js”,那么”defer.js”文件一定与HTML文件在同一文件夹下。
注意:这段代码直到文档加载完才会加载指定的外部js文件。因此,不应该把那些页面正常加载需要依赖的javascript代码放在这里。而应该将JavaScript代码分成两组。一组是因页面需要而立即加载的javascript代码,另外一组是在页面加载后进行操作的javascript代码(例如添加click事件或其他东西)。这些需等到页面加载后再执行的JavaScript代码,应放在一个外部文件,然后再引进来。
30、同步和异步的区别?
同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
举个浏览器例子:普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事
异步: 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
再举个生活的例子:大家联系的时候如果使用手机通话,那么只能跟一个人联系,过程中做不了其他任何操作,如果使用短信或者聊天的方式,就可以同时跟很多人聊天,别人收到信息后会回复,在回复之前还可以跟另外的人进行聊天。
31、document.write和innerHTML的区别?
1.document.write是直接写入到页面的内容流,如果在写之前没有调用document.open, 浏览器会自动调用open。每次写完关闭之后重新调用该函数,会导致页面被重写。
2.innerHTML则是DOM页面元素的一个属性,代表该元素的html内容。你可以精确到某一个具体的元素来进行更改。如果想修改document的内容,则需要修改document.documentElement.innerElement。
3.两者都可动态包含外部资源如JavaScript文件
通过document.write插入元素会自动执行其中的脚本;
大多数浏览器中,通过innerHTML插入元素并不会执行其中的脚本
innerHTML很多情况下都优于document.write,其原因在于其允许更精确的控制要刷新页面的那一个部分。
32、.call()和.apply()的含义和区别?
1、call,apply都属于Function.prototype的一个方法,它是JavaScript引擎内在实现的,因为属于Function.prototype,所以每个Function对象实例(就是每个方法)都有call,apply属性。既然作为方法的属性,那它们的使用就当然是针对方法的了,这两个方法是容易混淆的,因为它们的作用一样,只是使用方式不同。
2、语法:foo.call(this, arg1,arg2,arg3) == foo.apply(this, arguments) == this.foo(arg1, arg2, arg3);
3、相同点:两个方法产生的作用是完全一样的。
4、不同点:方法传递的参数不同,单个单数传入,另一个可以以数组方式传入
33、JQ和JQUI有啥区别?
jQuery是一个快速、简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架)。jQuery设计的宗旨是”write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互。
jQuery UI 是建立在 jQuery JavaScript 库上的一组用户界面交互、特效、小部件及主题。
34、需求:实现一个页面操作不会整页刷新的网站,并且能在浏览器的前进,后退时正确响应。给出你的技术实现方案?
用cookie或者localStorage来记录应用的状态即可,刷新页面时读取一下这个状态,然后发送相应ajax请求来改变页面即可
HTML5里引用了新的API,就是history.pushState和history.replaceState,就是通过这个接口做到无刷新改变页面URL的
虽然ajax可以无刷新改变页面内容,但无法改变页面URL
其次为了更好的可访问性,内容发生改变后,改变URL的hash。但是hash的方式不能很好的处理浏览器的前进、后退等问题
有的浏览器引入了onhashchange的接口,不支持的浏览器只能定时去判断hash是否改变
再有,ajax的使用对搜索引擎很不友好,往往蜘蛛爬到的区域是空的
为了解决传统ajax带来的问题,HTML5里引入了新的API,即:history.pushState, history.replaceState
可以通过pushState和replaceState接口操作浏览器历史,并且改变当前页面的URL。
pushState是将指定的URL添加到浏览器历史里,replaceState是将指定的URL替换当前的URL。
如何调用
var state = { title: title, url: options.url, otherkey: othervalue};window.history.pushState(state, document.title, url);
state对象除了要title和url之外,也可以添加其他的数据,比如:还想将一些发送ajax的配置给保存起来。
replaceState和pushState是相似的,不需要多做解释。
如何响应浏览器的前进、后退操作
window对象上提供了onpopstate事件,上面传递的state对象会成为event的子对象,这样就可以拿到存储的title和URL了。
window.addEventListener(‘popstate’, function(e){ if (history.state){ var state = e.state; //do something(state.url, state.title); }}, false);
这样就可以结合ajax和pushState完美的进行无刷新浏览了。
35、js的数据类型都有哪些?
字符串、数字、布尔、数组、对象、Null、Undefined
36、已知ID的input输入框,希望获取这个输入框的输入值,怎么做?(不使用第三方框架)
document.getElementById(id).value;
37、希望获取到页面中所有的checkbox怎么做?(不使用第三方框架)
document.getElementsByTagName(‘input’);
遍历循环
38、设置一个已知ID的div和html内容为xxx,字体颜色设置为黑色?(不使用第三方框架)
var div = document.getElementById(id);
div.innerHTML = ”;
div.style.color = ”;
39、当一个dom节点被点击时,我们需要能够执行一个函数,应该怎么做?
直接在DOM里绑定事件:”xx” …
在JS里通过onclick绑定:xxx.onclick = test
通过事件添加进行绑定:addEventListener(xxx, ‘click’, test)
那么问题来了,Javascript的事件流模型都有什么?
“事件冒泡”:事件开始由最具体的元素接受,然后逐级向上传播
“事件捕捉”:事件由最不具体的节点先接收,然后逐级向下,一直到最具体的
“DOM事件流”:三个阶段:事件捕捉,目标阶段,事件冒泡
40、什么是Ajax和JSON,他们的优缺点?
Ajax是异步JavaScript和XML,用于在Web页面中实现异步数据交互。
优点:
可以使得页面不重载全部内容的情况下加载局部内容,降低数据传输量
避免用户不断刷新或者跳转页面,提高用户体验
缺点:
对搜索引擎不友好(
要实现ajax下的前后退功能成本较大
可能造成请求数的增加
跨域问题限制
JSON是一种轻量级的数据交换格式,ECMA的一个子集
优点:轻量级、易于人的阅读和编写,便于机器(JavaScript)解析,支持复合数据类型(数组、对象、字符串、数字)
41、请看下列代码输出什么?解释原因?
var a;
alert(typeof a); //undefined
alert(b); //报错
解释:Undefined是一个只有一个值的数据类型,这个值就是”undefined”,
在使用var声明变量但并未对其赋值进行初始化时,这个变量的值就是undefined。而b由于未声明将报错。
注意未申明的变量和声明了未赋值的是不一样的。
ar a = null;
alert(typeof a); //object
解释:null是一个只有一个值的数据类型,这个值就是null。表示一个空指针对象,所以用typeof检测会返回”object”
42、js的typeof返回哪些数据类型?
有如下6种返回值:
1)number;
2)string;
3)boolean;
4)object
5)function
6)undefined;
43、split() join()的区别?
join() 方法用于把数组中的所有元素放入一个字符串。
元素是通过指定的分隔符进行分隔的。
指定分隔符方法join(“#”);其中#可以是任意
与之相反的是split()方法:用于把一个字符串分割成字符串数组.
44、数组方法pop() push() unshift() shift()?
push和pop方法,这两个方法只会对数组从尾部进行压入或弹出,而且是在原数组进行操作,任何的改动都是会影响到操作的数组。push(args)可以每次压入多个元素,并返回更新后的数组长度。pop()函数每次只会弹出最后一个结尾的元素,并返回弹出的元素,如果是对空组数调用pop()则返回undefined。 如果参数是数组则是将整个数组当做一个元素压入到原来的数组当中。并不会产生类似concat合并数组时产生的”拆分现象”
unshift和shift这两个方法都是通过对数组的头部进行的操作,其他基本跟push和pop类似
shift:从集合中把第一个元素删除,并返回这个元素的值。
unshift: 在集合开头添加一个或更多元素,并返回新的长度
push:在集合中添加元素,并返回新的长度
pop:从集合中把最后一个元素删除,并返回这个元素的值
45、ajax请求时,如何解释json数据?
1.$.JSON(url,params,fun);
2.$.ajax({}); dataType:’json’
都可以使用$each();进行遍历
$.each(object,function(index,item){
});
46、js的本地对象,内置对象和宿主对象?
本地对象:
Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError官方定义好了的对象
内置对象: Global 和 Math,内置对象是本地对象的一种
宿主对象:所有的BOM和DOM对象都是宿主对象,是那些官方未定义,你自己构建的对象加上DOM和BOM对象组成的
47、列举所了解的前端框架并简述?
以下是常用的前端基础框架:
以下是常见的前端构建框架:
以下是场检的JS/CSS模块化开发的框架:
48、对web标准以及w3c的理解与认识?
(1)web标准规范要求,书写标签必须闭合、标签小写、不乱嵌套,可提高搜索机器人对网页内容的搜索几率。— SEO
(2)建议使用外链css和js脚本,从而达到结构与行为、结构与表现的分离,提高页面的渲染速度,能更快地显示页面的内容。
(3)样式与标签的分离,更合理的语义化标签,使内容能被更多的用户所访问、内容能被更广泛的设备所访问、更少的代码和组件, 从而降低维护成本、改版更方便
(4)不需要变动页面内容,便可提供打印版本而不需要复制内容,提高网站易用性
遵循w3c制定的web标准,能够使用户浏览者更方便的阅读,使网页开发者之间更好的交流。
49、xhtml和html有什么区别?
XHTML是HTML 4.01和XML1.0的杂交,XHTML1.0是基于HTML4.01的
HTML是一种基于标准通用标记语言(SGML)的应用,而XHTML则基于可扩展标记语言(XML),HTML和XHTML其实是平行发展的两个标准。本质上说,XHTML是一个过渡技术,结合了部分XML的强大功能及大多数HTML的简单特性。建立XHTML的目的就是实现HTML向XML的过渡
1、XHTML要求正确嵌套
2、XHTML所有元素必须关闭
3、XHTML区分大小写
4、XHTML属性值要加引号
5、XHTML用id属性代替name属性
6、属性值不能简写
50、行内元素有哪些?块级元素有哪些?css和盒子模型?
盒子模型:内容、填充(padding)、边框(border)、外边界(margin)
box-sizing:border-box; box-sizing:content-box;
51、css选择器有哪些?哪些属性可以继承?优先级算法如何计算?内联和import哪个级别更高?
可继承的:font-size font-family color
不可继承的:border padding margin background-color width height
优先级:!important > [ id > class > tag ] important 比 内联优先级高
52、前端页面有哪三层构成,分别是什么?作用是什么?
结构层、表示层、行为层
结构层(structural layer)
由 HTML 或 XHTML之类的标记语言负责创建。标签,也就是那些出现在尖括号里的单词,对网页内容的语义含义做出了描述,但这些标签不包含任何关于如何显示有关内容的信息。例如,P标签表达了这样一种语义:”这是一个文本段。”
表示层(presentation layer)
由 CSS 负责创建。 CSS对”如何显示有关内容”的问题做出了回答。
行为层(behaviorlayer)
负责回答”内容应该如何对事件做出反应”这一问题。这是 Javascript 语言和 DOM主宰的领域
53、你如何对网站的文件和资源进行优化?期待的解决方法包括?
A、文件合并,减少http请求,合并JavaScript和CSS文件、CSS Sprites、图像映射 (Image Map)和使用Data URI来编码图片
B、文件最小化/文件压缩,减少文件下载的体积;常用的工具是YUI Compressor
C、使用 CDN 托管,尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定
D、缓存的使用(多个域名来提供缓存)
E、GZIP 压缩你的 JS 和 CSS 文件
54、看下列代码?输出什么?解释原因?
var a = null;
alert(typeof a);
答案:输出为object, JS类型值是存在32 BIT 单元里,32位有1-3位表示TYPE TAG,其它位表示真实值
而表示object的标记位正好是低三位都是0
000: object. The data is a reference to an object.
而js 里的Null 是机器码NULL空指针, (0x00 is most platforms).所以空指针引用 加上 对象标记还是0,最终体现的类型还是object..
这也就是为什么Number(null)===0吧…
The history of “typeof null”
2. 曾经有提案 typeof null === ‘null’.但提案被拒绝
harmony:typeofnull
55、看代码给答案?并进行解释?
var a = new Object();
a.value=1;
b = a;
b.value=2;
alert(a.value);
56、var numberArray = [3,6,2,4,1,5];
1) 实现对该数组的倒排,输出[5,1,4,2,6,3]
2) 实现对该数组的降序排列,输出[6,5,4,3,2,1]
var numberArray = [3,6,2,4,1,5];
numberArray.reverse(); // 5,1,4,2,6,3
numberArray.sort(function(a,b){ //6,5,4,3,2,1
return b-a;
})
57、你能描述一下渐进增强和优雅降级之间的不同吗?
如果提到了特性检测,可以加分。
检测浏览器,渐进增强就是让牛b的浏览器的效果更好,优雅降级就是让2b的浏览器在功能ok的情况下效果一般。
58、线程与进程的区别?
一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
59、请解释一下什么是”语义化的 HTML”?
语义化的好处:
1:去掉或样式丢失的时候能让页面呈现清晰的结构:
html本身是没有表现的,我们看到例如是粗体,字体大小2em,加粗;是加粗的,不要认为这是html的表现,这些其实html默认的css样式在起作用,所以去掉或样式丢失的时候能让页面呈现清晰的结构不是
的HTML结构的优点,但是浏览器都有有默认样式,默认样式的目的也是为了更好的表达html的语义,可以说浏览器的默认样式和语义化的HTML结构是不可分割的。
2.屏幕阅读器(如果访客有视障)会完全根据你的标记来”读”你的网页.
3.PDA、手机等设备可能无法像普通电脑的浏览器一样来渲染网页(通常是因为这些设备对CSS的支持较弱).
4.搜索引擎的爬虫也依赖于标记来确定上下文和各个关键字的权重.
5.你的页面是否对爬虫容易理解非常重要,因为爬虫很大程度上会忽略用于表现的标记, 而只注重语义标记.
6.便于团队开发和维护
语义化的HTML就是:标题用h1-h6,文字段落用p,列表用ul li,大致如此
60、为什么利用多个域名来提供网站资源会更有效?
浏览器同一时间可以从一个域名下载多少资源?你的浏览器能同时保持对一个域名的多少连接?
三个最主流的原因:
1. CDN缓存更方便
2. 突破浏览器并发限制 (你随便挑一个 G家的 url: https://lh4.googleusercontent.com/- si4dh2myPWk/T81YkSi__AI/AAAAAAAAQ5o/LlwbBRpp58Q/w497-h373/IMG_20120603_163233.jpg, 把前面的 lh4换成 lh3,lh6 啥的,都照样能够访问,像地图之类的需要大量并发下载图片的站点,这个非常重要。)
3. Cookieless, 节省带宽,尤其是上行带宽 一般比下行要慢。。。
还有另外两个非常规原因:
4. 对于UGC的内容和主站隔离,防止不必要的安全问题( 上传js窃取主站cookie之类的) 。
正是这个原因要求用户内容的域名必须不是自己主站的子域名,而是一个完全独立的第三方域名。
5. 数据做了划分,甚至切到了不同的物理集群,通过子域名来分流比较省事. ^^ 这个可能被用的不多。
PS: 关于Cookie的问题,带宽是次要的,安全隔离才是主要的。
关于多域名,也不是越多越好,虽然服务器端可以做泛解释,浏览器做dns解释也是耗时间的,而且太多域名,如果要走 https的话,还有要多买证书和部署的问题,^^。
61、请说出三种减少页面加载时间的方法。(加载时间指感知的时间或者实际加载时间)
1.优化图片
2.图像格式的选择(GIF:提供的颜色较少,可用在一些对颜色要求不高的地方)
3.优化CSS(压缩合并css,如margin-top,margin-left…)
4.网址后加斜杠(如www.campr.com/目录,会判断这个”目录是什么文件类型,或者是目录。)
5.标明高度和宽度(如果浏览器没有找到这两个参数,它需要一边下载图片一边计算大小,如果图片很多,浏览器需要不断地调整页面。这不但影响速度,也影响浏览体验。
当浏览器知道了高度和宽度参数后,即使图片暂时无法显示,页面上也会腾出图片的空位,然后继续加载后面的内容。从而加载时间快了,浏览体验也更好了。)
6.减少http请求(合并文件,合并图片)。
62、如果你参与到一个项目中,发现他们使用 Tab 来缩进代码,但是你喜欢空格,你会怎么做?
1.建议这个项目使用像 EditorConfig (http://editorconfig.org/) 之类的规范
2.为了保持一致性,接受项目原有的风格
3.直接使用 VIM 的 retab 命令
63、请写一个简单的幻灯效果页面
如果不使用JS来完成,可以加分。(如:纯CSS实现的幻灯片效果)
可以采用CSS3的单选按钮radio来实现图片的切换
64、你都使用哪些工具来测试代码的性能?
Profiler, JSPerf(http://jsperf.com/nexttick-vs-setzerotimeout-vs-settimeout), Dromaeo
65、如果今年你打算熟练掌握一项新技术,那会是什么?
nodejs,html5,css3,less
66、请谈一下你对网页标准和标准制定机构重要性的理解?
(google)w3c存在的意义就是让浏览器兼容性问题尽量小,首先是他们对浏览器开发者的约束,然后是对开发者的约束。
67、什么是 FOUC(无样式内容闪烁)?你如何来避免 FOUC?
FOUC – Flash Of Unstyled Content 文档样式闪烁
而引用CSS文件的@import就是造成这个问题的罪魁祸首。IE会先加载整个HTML文档的DOM,然后再去导入外部的CSS文件,因此,在页面DOM加载完成到CSS导入完成中间会有一段时间页面上的内容是没有样式的,这段时间的长短跟网速,电脑速度都有关系。
解决方法简单的出奇,只要在之间加入一个或者元素就可以了。
68、doctype(文档类型)的作用是什么?你知道多少种文档类型?
此标签可告知浏览器文档使用哪种 HTML 或 XHTML 规范。
该标签可声明三种 DTD 类型,分别表示严格版本、过渡版本以及基于框架的 HTML 文档。
HTML 4.01 规定了三种文档类型:Strict、Transitional 以及 Frameset。
XHTML 1.0 规定了三种 XML 文档类型:Strict、Transitional 以及 Frameset。
Standards (标准)模式(也就是严格呈现模式)用于呈现遵循最新标准的网页,而 Quirks
(包容)模式(也就是松散呈现模式或者兼容模式)用于呈现为传统浏览器而设计的网页。
69、浏览器标准模式和怪异模式之间的区别是什么?
W3C标准推出以后,浏览器都开始采纳新标准,但存在一个问题就是如何保证旧的网页还能继续浏览,在标准出来以前,很多页面都是根据旧的渲染方法编写的,如果用的标准来渲染,将导致页面显示异常。为保持浏览器渲染的兼容性,使以前的页面能够正常浏览,浏览器都保留了旧的渲染方法(如:微软的IE)。这样浏览器渲染上就产生了Quircks mode和Standars mode,两种渲染方法共存在一个浏览器上。
IE盒子模型和标准W3C盒子模型:ie的width包括:padding\border。 标准的width不包括:padding\border
在js中如何判断当前浏览器正在以何种方式解析?
document对象有个属性compatMode ,它有两个值:
BackCompat 对应quirks mode
CSS1Compat 对应strict mode
70、使用 XHTML 的局限有哪些?
xhtml要求严格,必须有head、body每个dom必须要闭合。
如果页面使用’application/xhtml+xml’会有什么问题吗?
一些老的浏览器并不兼容。
十六、如果网页内容需要支持多语言,你会怎么做?
编码UTF-8,空间域名需要支持多浏览地址。
在设计和开发多语言网站时,有哪些问题你必须要考虑?
1、应用字符集的选择 2、语言书写习惯&导航结构 3、数据库驱动型网站
71、data-属性的作用是什么?
data-为前端开发者提供自定义的属性,这些属性集可以通过对象的dataset属性获取,不支持该属性的浏览器可以通过 getAttribute方法获取
…
div.dataset.commentNum; // 10
需要注意的是,data-之后的以连字符分割的多个单词组成的属性,获取的时候使用驼峰风格。
并不是所有的浏览器都支持.dataset属性,测试的浏览器中只有Chrome和Opera支持。
72、如果把 HTML5 看作做一个开放平台,那它的构建模块有哪些?
- 执行say667()后,say667()闭包内部变量会存在,而闭包内部函数的内部变量不会存在
- 使得Javascript的垃圾回收机制GC不会收回say667()所占用的资源
- 因为say667()的内部函数的执行需要依赖say667()中的变量
- 这是对闭包作用的非常直白的描述
- function say667() {
- // Local variable that ends up within closure
- var num = 666;
- var sayAlert = function() {
- alert(num);
- }
- num++;
- return sayAlert;
- }
- var sayAlert = say667();
- sayAlert()//执行结果应该弹出的667
- javascript 代码中的”use strict”;是什么意思 ? 使用它区别是什么?
- use strict是一种ECMAscript 5 添加的(严格)运行模式,这种模式使得 Javascript 在更严格的条件下运行,
- 使JS编码更加规范化的模式,消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为。
- 默认支持的糟糕特性都会被禁用,比如不能用with,也不能在意外的情况下给全局变量赋值;
- 全局变量的显示声明,函数必须声明在顶层,不允许在非函数代码块内声明函数,arguments.callee也不允许使用;
- 消除代码运行的一些不安全之处,保证代码运行的安全,限制函数中的arguments修改,严格模式下的eval函数的行为和非严格模式的也不相同;
- 提高编译器效率,增加运行速度;
- 为未来新版本的Javascript标准化做铺垫。
- 如何判断一个对象是否属于某个类?
- 使用instanceof (待完善)
- if(a instanceof Person){
- alert(‘yes’);
- }
- new操作符具体干了什么呢?
- 1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
- 2、属性和方法被加入到 this 引用的对象中。
- 3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。
- var obj = {};
- obj.proto = Base.prototype;
- Base.call(obj);
- 用原生JavaScript的实现过什么功能吗?
- Javascript中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是?
- hasOwnProperty
- javaScript中hasOwnProperty函数方法是返回一个布尔值,指出一个对象是否具有指定名称的属性。此方法无法检查该对象的原型链中是否具有该属性;该属性必须是对象本身的一个成员。
- 使用方法:
- object.hasOwnProperty(proName)
- 其中参数object是必选项。一个对象的实例。
- proName是必选项。一个属性名称的字符串值。
- 如果 object 具有指定名称的属性,那么JavaScript中hasOwnProperty函数方法返回 true,反之则返回 false。
- JSON 的了解?
- JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
- 它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小
- 如:{“age”:”12”, “name”:”back”}
- JSON字符串转换为JSON对象:
- var obj =eval(‘(‘+ str +’)’);
- var obj = str.parseJSON();
- var obj = JSON.parse(str);
- JSON对象转换为JSON字符串:
- var last=obj.toJSONString();
- var last=JSON.stringify(obj);
- [].forEach.call($$(““),function(a){a.style.outline=”1px solid #”+(~~(Math.random()(1<<24))).toString(16)}) 能解释一下这段代码的意思吗?
- js延迟加载的方式有哪些?
- defer和async、动态创建DOM方式(用得最多)、按需异步载入js
- Ajax 是什么? 如何创建一个Ajax?
- ajax的全称:Asynchronous Javascript And XML。
- 异步传输+js+xml。
- 所谓异步,在这里简单地解释就是:向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是不会发生整页刷新的,提高了用户体验。
- (1)创建XMLHttpRequest对象,也就是创建一个异步调用对象
- (2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息
- (3)设置响应HTTP请求状态变化的函数
- (4)发送HTTP请求
- (5)获取异步调用返回的数据
- (6)使用JavaScript和DOM实现局部刷新
- 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都会执行这条语句就是不需要保存缓存记录。同步和异步的区别?
同步的概念应该是来自于OS中关于同步的概念:不同进程为协同完成某项工作而在先后次序上调整(通过阻塞,唤醒等方式).同步强调的是顺序性.谁先谁后.异步则不存在这种顺序性.
同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作。
异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。
(待完善)
- 如何解决跨域问题?
- jsonp、 iframe、window.name、window.postMessage、服务器上设置代理页面
- 页面编码和被请求的资源编码如果不一致如何处理?
- 服务器代理转发时,该如何处理cookie?
- nginx
- 模块化开发怎么做?
立即执行函数,不暴露私有成员
var module1 = (function(){
var _count = 0;
var m1 = function(){
//…
};
var m2 = function(){
//…
};
return {
m1 : m1,
m2 : m2
};
})();
(待完善)
- AMD(Modules/Asynchronous-Definition)、CMD(Common Module Definition)规范区别?
AMD 规范在这里:https://github.com/amdjs/amdjs-api/wiki/AMD
CMD 规范在这里:https://github.com/seajs/seajs/issues/242
Asynchronous Module Definition,异步模块定义,所有的模块将被异步加载,模块加载不影响后面语句运行。所有依赖某些模块的语句均放置在回调函数中。
区别:
1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.<br /> 2. 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()
// …
})
- requireJS的核心原理是什么?(如何动态加载的?如何避免多次加载的?如何 缓存的?)
- 参考:http://annn.me/how-to-realize-cmd-loader/
- JS模块加载器的轮子怎么造,也就是如何实现一个模块加载器?
- 谈一谈你对ECMAScript6的了解?
- ECMAScript6 怎么写class么,为什么会出现class这种东西?
- 异步加载JS的方式有哪些?
- (1) defer,只支持IE
- (2) async:
- (3) 创建script,插入到DOM中,加载完毕后callBack
- documen.write和 innerHTML的区别
- document.write只能重绘整个页面
- innerHTML可以重绘页面的一部分
- DOM操作——怎样添加、移除、移动、复制、创建和查找节点?
- (1)创建新节点
- createDocumentFragment() //创建一个DOM片段
- createElement() //创建一个具体的元素
- createTextNode() //创建一个文本节点
- (2)添加、移除、替换、插入
- appendChild()
- removeChild()
- replaceChild()
- insertBefore() //在已有的子节点前插入一个新的子节点
- (3)查找
- getElementsByTagName() //通过标签名称
- getElementsByName() //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
- getElementById() //通过元素Id,唯一性
- .call() 和 .apply() 的区别?
- 例子中用 add 来替换 sub,add.call(sub,3,1) == add(3,1) ,所以运行结果为:alert(4);
- 注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。
- function add(a,b)
- {
- alert(a+b);
- }
- function sub(a,b)
- {
- alert(a-b);
- }
- add.call(sub,3,1);
- 数组和对象有哪些原生方法,列举一下?
- JS 怎么实现一个类。怎么实例化这个类
- JavaScript中的作用域与变量声明提升?
- 如何编写高性能的Javascript?
- 那些操作会造成内存泄漏?
- JQuery的源码看过吗?能不能简单概况一下它的实现原理?
- jQuery.fn的init方法返回的this指的是什么对象?为什么要返回this?
- jquery中如何将数组转化为json字符串,然后再转化回来?
- jQuery 的属性拷贝(extend)的实现原理是什么,如何实现深拷贝?
- jquery.extend 与 jquery.fn.extend的区别?
- jquery.extend 为jquery类添加类方法,可以理解为添加静态方法
- jquery.fn.extend:
- 源码中jquery.fn = jquery.prototype,所以对jquery.fn的扩展,就是为jquery类添加成员函数
- 使用:
- jquery.extend扩展,需要通过jquery类来调用,而jquery.fn.extend扩展,所有jquery实例都可以直接调用。
- jQuery 的队列是如何实现的?队列可以用在哪些地方?
- 谈一下Jquery中的bind(),live(),delegate(),on()的区别?
- JQuery一个对象可以同时绑定多个事件,这是如何实现的?
- 是否知道自定义事件。jQuery里的fire函数是什么意思,什么时候用?
- jQuery 是通过哪个方法和 Sizzle 选择器结合的?(jQuery.fn.find()进入Sizzle)
- 针对 jQuery性能的优化方法?
- Jquery与jQuery UI 有啥区别?
- *jQuery是一个js库,主要提供的功能是选择器,属性修改和事件绑定等等。
- *jQuery UI则是在jQuery的基础上,利用jQuery的扩展性,设计的插件。
- 提供了一些常用的界面元素,诸如对话框、拖动行为、改变大小行为等等
- JQuery的源码看过吗?能不能简单说一下它的实现原理?
- jquery 中如何将数组转化为json字符串,然后再转化回来?
jQuery中没有提供这个功能,所以你需要先编写两个jQuery的扩展:
$.fn.stringifyArray = function(array) {
return JSON.stringify(array)
}
$.fn.parseArray = function(array) {<br /> return JSON.parse(array)<br /> }
然后调用:<br /> $("").stringifyArray(array)
- jQuery和Zepto的区别?各自的使用场景?
- 针对 jQuery 的优化方法?
- *基于Class的选择性的性能相对于Id选择器开销很大,因为需遍历所有DOM元素。
- *频繁操作的DOM,先缓存起来再操作。用Jquery的链式调用更好。
- 比如:var str=$(“a”).attr(“href”);
- *for (var i = size; i < arr.length; i++) {}
- for 循环每一次循环都查找了数组 (arr) 的.length 属性,在开始循环的时候设置一个变量来存储这个数字,可以让循环跑得更快:
- for (var i = size, length = arr.length; i < length; i++) {}
- Zepto的点透问题如何解决?
- jQueryUI如何自定义组件?
- 需求:实现一个页面操作不会整页刷新的网站,并且能在浏览器前进、后退时正确响应。给出你的技术实现方案?
- 如何判断当前脚本运行在浏览器还是node环境中?(阿里)
- this === window ? ‘browser’ : ‘node’;
- 通过判断Global对象是否为window,如果不为window,当前脚本没有运行在浏览器中
- 移动端最小触控区域是多大?
- jQuery 的 slideUp动画 ,如果目标元素是被外部事件驱动, 当鼠标快速地连续触发外部元素事件, 动画会滞后的反复执行,该如何处理呢?
- jquery stop(): 如:$(“#div”).stop().animate({width:”100px”},100);
- 把 Script 标签 放在页面的最底部的body封闭之前 和封闭之后有什么区别?浏览器会如何解析它们?
- 移动端的点击事件的有延迟,时间是多久,为什么会有? 怎么解决这个延时?(click 有 300ms 延迟,为了实现safari的双击事件的设计,浏览器要知道你是不是要双击操作。)
- 知道各种JS框架(Angular, Backbone, Ember, React, Meteor, Knockout…)么? 能讲出他们各自的优点和缺点么?
- Underscore 对哪些 JS 原生对象进行了扩展以及提供了哪些好用的函数方法?
- 解释JavaScript中的作用域与变量声明提升?
- 那些操作会造成内存泄漏?
- 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。
- 垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。
- setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
- 闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
- JQuery一个对象可以同时绑定多个事件,这是如何实现的?
- 多个事件同一个函数:
- $(“div”).on(“click mouseover”, function(){});
- 多个事件不同函数
- $(“div”).on({
- click: function(){},
- mouseover: function(){}
- });
- Node.js的适用场景?
- (如果会用node)知道route, middleware, cluster, nodemon, pm2, server-side rendering么?
- 解释一下 Backbone 的 MVC 实现方式?
- 什么是“前端路由”?什么时候适合使用“前端路由”? “前端路由”有哪些优点和缺点?
- 知道什么是webkit么? 知道怎么用浏览器的各种工具来调试和debug代码么?
- Chrome,Safari浏览器内核。
- 如何测试前端代码么? 知道BDD, TDD, Unit Test么? 知道怎么测试你的前端工程么(mocha, sinon, jasmin, qUnit..)?
- 前端templating(Mustache, underscore, handlebars)是干嘛的, 怎么用?
- 简述一下 Handlebars 的基本用法?
- 简述一下 Handlerbars 的对模板的基本处理流程, 如何编译的?如何缓存的?
- 用js实现千位分隔符?(来源:前端农民工,提示:正则+replace)
- 参考:http://www.tuicool.com/articles/ArQZfui
- function commafy(num) {
- return num && num
- .toString()
- .replace(/(\d)(?=(\d{3})+.)/g, function($0, $1) {
- return $1 + “,”;
- });
- }
- console.log(commafy(1234567.90)); //1,234,567.90
- 检测浏览器版本版本有哪些方式?
- 功能检测、userAgent特征检测
- 比如:navigator.userAgent
- //“Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36
- (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36”
- What is a Polyfill?
- polyfill 是“在旧版浏览器上复制标准 API 的 JavaScript 补充”,可以动态地加载 JavaScript 代码或库,在不支持这些标准 API 的浏览器中模拟它们。
- 例如,geolocation(地理位置)polyfill 可以在 navigator 对象上添加全局的 geolocation 对象,还能添加 getCurrentPosition 函数以及“坐标”回调对象,
- 所有这些都是 W3C 地理位置 API 定义的对象和函数。因为 polyfill 模拟标准 API,所以能够以一种面向所有浏览器未来的方式针对这些 API 进行开发,
- 一旦对这些 API 的支持变成绝对大多数,则可以方便地去掉 polyfill,无需做任何额外工作。
- 做的项目中,有没有用过或自己实现一些 polyfill 方案(兼容性处理方案)?
- 比如: html5shiv、Geolocation、Placeholder
- 我们给一个dom同时绑定两个点击事件,一个用捕获,一个用冒泡。会执行几次事件,会先执行冒泡还是捕获?
- 使用JS实现获取文件扩展名?
- function getFileExtension(filename) {
- return filename.slice((filename.lastIndexOf(“.”) - 1 >>> 0) + 2);
- }
- String.lastIndexOf() 方法返回指定值(本例中的’.’)在调用该方法的字符串中最后出现的位置,如果没找到则返回 -1。
- 对于’filename’和’.hiddenfile’,lastIndexOf的返回值分别为0和-1无符号右移操作符(»>) 将-1转换为4294967295,将-2转换为4294967294,这个方法可以保证边缘情况时文件名不变。
- String.prototype.slice() 从上面计算的索引处提取文件的扩展名。如果索引比文件名的长度大,结果为””。
- Webpack热更新实现原理?
- Webpack编译期,为需要热更新的 entry 注入热更新代码(EventSource通信)
- 页面首次打开后,服务端与客户端通过 EventSource 建立通信渠道,把下一次的 hash 返回前端
- 客户端获取到hash,这个hash将作为下一次请求服务端 hot-update.js 和 hot-update.json的hash
- 修改页面代码后,Webpack 监听到文件修改后,开始编译,编译完成后,发送 build 消息给客户端
- 客户端获取到hash,成功后客户端构造hot-update.js script链接,然后插入主文档
- hot-update.js 插入成功后,执行hotAPI 的 createRecord 和 reload方法,获取到 Vue 组件的 render方法,重新 render 组件, 继而实现 UI 无刷新更新。
- 请介绍一下JS之事件节流?
-
ECMAScript6 相关
Object.is() 与原来的比较操作符“ ===”、“ ==”的区别?
- 两等号判等,会在比较时进行类型转换;
- 三等号判等(判断严格),比较时不进行隐式类型转换,(类型不同则会返回false);
- Object.is 在三等号判等的基础上特别处理了 NaN 、-0 和 +0 ,保证 -0 和 +0 不再相同,
- 但 Object.is(NaN, NaN) 会返回 true.
- Object.is 应被认为有其特殊的用途,而不能用它认为它比其它的相等对比更宽松或严格。
- ES6是如何实现编译成ES5的?
-
前端框架
React 使用场景?
- 逻辑复杂单页应用,偏中后台管理系统,纯展示性的UI页面不合适、
- 描述一下React 生命周期
- 渲染过程调用到的生命周期函数,主要几个要知道;
- constructor
- getInitialState
- getDefaultProps
- componentWillMount
- render
- componentDidMount
- 更新过程
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
- 卸载过程
- componentWillUnmount
- 实现组件有哪些方式?
- React.createClass 使用API来定义组件
- React ES6 class component 用 ES6 的class 来定义组件
- Functional stateless component 通过函数定义无状态组件
- 应该在React生命周期的什么阶段发出ajax请求,为什么?
- AJAX请求应在 componentDidMount函数 进行请求。
- shouldComponentUpdate函数有什么作用?
- shouldComponentUpdate是一个允许我们自行决定某些组件(以及他们的子组件)是否进行更新的生命周期函数,reconciliation的最终目的是尽可能以最有效的方式去根据新的state更新UI,
- 如果你已经知道UI的哪些状态无需进行改变,就没必要去让React去判断它是否该改变。 让shouldComponentUpdate返回falss, React就会让当前的组件和其子组件保持不变。
- 当组件的setState函数被调用之后,发生了什么?
- React会做的第一件事就是把你传递给setState的参数对象合并到组件原先的state。这个事件会导致一个“reconciliation”(调和)的过程。reconciliation的最终目标就是,
- 尽可能以最高效的方法,去基于新的state来更新UI。为了达到这个目的,React会构建一个React元素树(你可以把这个想象成一个表示UI的一个对象)。一旦这个树构建完毕,
- React为了根据新的state去决定UI要怎么进行改变,它会找出这棵新树和旧树的不同之处。React能够相对精确地找出哪些位置发生了改变以及如何发生了什么变化,
- 并且知道如何只通过必要的更新来最小化重渲染。
- 为什么循环产生的组件中要利用上key这个特殊的prop?
- Keys负责帮助React跟踪列表中哪些元素被改变/添加/移除。React利用子元素的key在比较两棵树的时候,快速得知一个元素是新的还是刚刚被移除。没有keys,React也就不知道当前哪一个的item被移除了。
- React-router 路由的实现原理?
- 说说React Native,Weex框架的实现原理?
- 受控组件(Controlled Component)与非受控组件(Uncontrolled Component)的区别
- refs 是什么?
- Refs是能访问DOM元素或组件实例的一个函数;
- React为什么自己定义一套事件体系呢,与浏览器原生事件体系有什么关系?
- 什么时候应该选择用class实现一个组件,什么时候用一个函数实现一个组件?
- 组件用到了state或者用了生命周期函数,那么就该使用Class component。其他情况下,应使用Functional component。
- 什么是HoC(Higher-Order Component)?适用于什么场景?
- 高阶组件就是一个 React 组件包裹着另外一个 React 组件
- 并不是父子关系的组件,如何实现相互的数据通信?
- 使用父组件,通过props将变量传入子组件 (如通过refs,父组件获取一个子组件的方法,简单包装后,将包装后的方法通过props传入另一个子组件 )
- 用过 React 技术栈中哪些数据流管理库?
- Redux\Dva
- Redux是如何做到可预测呢?
- Redux将React组件划分为哪两种?
- Redux是如何将state注入到React组件上的?
- 请描述一次完整的 Redux 数据流
- React的批量更新机制 BatchUpdates?
React与Vue,各自的组件更新进行对比,它们有哪些区别?
其他问题
原来公司工作流程是怎么样的,如何与其他人协作的?如何跨部门合作的?
- 你遇到过比较难的技术问题是?你是如何解决的?
- 设计模式 知道什么是singleton, factory, strategy, decrator么?
- 常使用的库有哪些?常用的前端开发工具?开发过什么应用或组件?
- 页面重构怎么操作?
- 网站重构:在不改变外部行为的前提下,简化结构、添加可读性,而在网站前端保持一致的行为。
- 也就是说是在不改变UI的情况下,对网站进行优化,在扩展的同时保持一致的UI。
- 对于传统的网站来说重构通常是:
- 表格(table)布局改为DIV+CSS
- 使网站前端兼容于现代浏览器(针对于不合规范的CSS、如对IE6有效的)
- 对于移动平台的优化
- 针对于SEO进行优化
- 深层次的网站重构应该考虑的方面
- 减少代码间的耦合
- 让代码保持弹性
- 严格按规范编写代码
- 设计可扩展的API
- 代替旧有的框架、语言(如VB)
- 增强用户体验
- 通常来说对于速度的优化也包含在重构中
- 压缩JS、CSS、image等前端资源(通常是由服务器来解决)
- 程序的性能优化(如数据读写)
- 采用CDN来加速资源加载
- 对于JS DOM的优化
- HTTP服务器的文件缓存
- 列举IE与其他浏览器不一样的特性?
- 1、事件不同之处:
- 触发事件的元素被认为是目标(target)。而在 IE 中,目标包含在 event 对象的 srcElement 属性;
- 获取字符代码、如果按键代表一个字符(shift、ctrl、alt除外),IE 的 keyCode 会返回字符代码(Unicode),DOM 中按键的代码和字符是分离的,要获取字符代码,需要使用 charCode 属性;
- 阻止某个事件的默认行为,IE 中阻止某个事件的默认行为,必须将 returnValue 属性设置为 false,Mozilla 中,需要调用 preventDefault() 方法;
- 停止事件冒泡,IE 中阻止事件进一步冒泡,需要设置 cancelBubble 为 true,Mozzilla 中,需要调用 stopPropagation();
- 99%的网站都需要被重构是那本书上写的?
- 网站重构:应用web标准进行设计(第2版)
- 什么叫优雅降级和渐进增强?
- 优雅降级:Web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会针对旧版本的IE进行降级处理了,使之在旧式浏览器上以某种形式降级体验却不至于完全不能用。
- 如:border-shadow
- 渐进增强:从被所有浏览器支持的基本功能开始,逐步地添加那些只有新版本浏览器才支持的功能,向页面增加不影响基础浏览器的额外样式和功能的。当浏览器支持时,它们会自动地呈现出来并发挥作用。
- 如:默认使用flash上传,但如果浏览器支持 HTML5 的文件上传功能,则使用HTML5实现更好的体验;
- 是否了解公钥加密和私钥加密。
- 一般情况下是指私钥用于对数据进行签名,公钥用于对签名进行验证;
- HTTP网站在浏览器端用公钥加密敏感数据,然后在服务器端再用私钥解密。
- WEB应用从服务器主动推送Data到客户端有那些方式?
- html5提供的Websocket
- 不可见的iframe
- WebSocket通过Flash
- XHR长时间连接
- XHR Multipart Streaming
JSONP 使用简单且兼容性不错,但是只限于 get 请求。
2.CORS
CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现。
3.document.domain
该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。
只需要给页面添加 document.domain = ‘test.com’ 表示二级域名都相同就可以实现跨域
4.webpack配置proxyTable设置开发环境跨域
5.nginx代理跨域
6.iframe跨域
7.postMessage
这种方式通常用于获取嵌入页面中的第三方页面数据。一个页面发送消息,另一个页面判断来源并接收消息
复制代码- 说一说前端性能优化方案
三个方面来说明前端性能优化
一: webapck优化与开启gzip压缩
1.babel-loader用 include 或 exclude 来帮我们避免不必要的转译,不转译node_moudules中的js文件
其次在缓存当前转译的js文件,设置loader: ‘babel-loader?cacheDirectory=true’
2.文件采用按需加载等等
3.具体的做法非常简单,只需要你在你的 request headers 中加上这么一句:
accept-encoding:gzip
4.图片优化,采用svg图片或者字体图标
5.浏览器缓存机制,它又分为强缓存和协商缓存
二:本地存储——从 Cookie 到 Web Storage、IndexedDB
说明一下SessionStorage和localStorage还有cookie的区别和优缺点
三:代码优化
1.事件代理
2.事件的节流和防抖
3.页面的回流和重绘
4.EventLoop事件循环机制
5.代码优化等等
复制代码- 说一说SessionStorage和localStorage还有cookie
共同点:都是保存在浏览器端、且同源的
不同点:
1.cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。
cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下
sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。
2.存储大小限制也不同,cookie数据不能超过4K,sessionStorage和localStorage可以达到5M
3.sessionStorage:仅在当前浏览器窗口关闭之前有效;
localStorage:始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据;
cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
4.作用域不同
sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面;
localstorage:在所有同源窗口中都是共享的;也就是说只要浏览器不关闭,数据仍然存在
cookie: 也是在所有同源窗口中都是共享的.也就是说只要浏览器不关闭,数据仍然存在
复制代码- 说一说你用过的css布局
gird布局,layout布局,flex布局,双飞翼,圣杯布局等
复制代码Promise是什么,解决了什么,之前怎么实现的
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
解决来之前在请求中回调请求产生的回调地狱,使得现在的代码更加合理更加优雅,也更加容易定位查找问题。
复制代码说说浏览器缓存
缓存可以减少网络 IO 消耗,提高访问速度。浏览器缓存是一种操作简单、效果显著的前端性能优化手段
很多时候,大家倾向于将浏览器缓存简单地理解为“HTTP 缓存”。
但事实上,浏览器缓存机制有四个方面,它们按照获取资源时请求的优先级依次排列如下:
Memory Cache
Service Worker Cache
HTTP Cache
Push Cache
缓存它又分为强缓存和协商缓存。优先级较高的是强缓存,在命中强缓存失败的情况下,才会走协商缓存
实现强缓存,过去我们一直用 expires。
当服务器返回响应时,在 Response Headers 中将过期时间写入 expires 字段,现在一般使用Cache-Control 两者同时出现使用Cache-Control
协商缓存,Last-Modified 是一个时间戳,如果我们启用了协商缓存,它会在首次请求时随着 Response Headers 返回:每次请求去判断这个时间戳是否发生变化。
从而去决定你是304读取缓存还是给你返回最新的数据
作者:只会番茄炒蛋
链接:https://juejin.im/post/5e3d898cf265da5732551a56
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。- 请描述一下 React 和 Vue的区别
这道题你如果熟知的话,从各个方面的不同点,原理,为什么这样实现来描述,起吗聊个半个小时。后续就不会问你太多问题了。
1.设计思想
vue的官网中说它是一款渐进式框架,采用自底向上增量开发的设计。
react主张函数式编程,所以推崇纯组件,数据不可变,单向数据流,当然需要双向的地方也可以手动实现,
比如借助 onChange 和 setState 来实现一个双向的数据流。
2.编写语法
Vue推荐的做法是webpack+vue-loader的单文件组件格式,vue保留了html、css、js分离的写法
React的开发者可能知道,react是没有模板的,直接就是一个渲染函数,它中间返回的就是一个虚拟DOM树,
React推荐的做法是 JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即’all in js’。
3.构建工具
vue提供了CLI 脚手架,可以帮助你非常容易地构建项目。
React 在这方面也提供了 create-react-app,但是现在还存在一些局限性,不能配置等等
4.数据绑定
vue是实现了双向数据绑定的mvvm框架,当视图改变更新模型层,当模型层改变更新视图层。
在vue中,使用了双向绑定技术,就是View的变化能实时让Model发生变化,而Model的变化也能实时更新到View。
(这里我们可以继续深入讲解一下双向数据绑定的原理,我之前的文章手写Vue源码可参考)
react是单向数据流,react中属性是不允许更改的,状态是允许更改的。
react中组件不允许通过this.state这种方式直接更改组件的状态。自身设置的状态,可以通过setState来进行更改。
(注意:React中setState是异步的,导致获取dom可能拿的还是之前的内容,
所以我们需要在setState第二个参数(回调函数)中获取更新后的新的内容。)
【这里如果你了解深入的话可以尝试描述一下React中setState的异步操作是怎么实现的,Vue中的更新是通过微任务等】
5.diff算法
vue中diff算法实现流程:
1.在内存中构建虚拟dom树
2.将内存中虚拟dom树渲染成真实dom结构
3.数据改变的时候,将之前的虚拟dom树结合新的数据生成新的虚拟dom树
4.将此次生成好的虚拟dom树和上一次的虚拟dom树进行一次比对(diff算法进行比对),来更新只需要被替换的DOM,
而不是全部重绘。在Diff算法中,只平层的比较前后两棵DOM树的节点,没有进行深度的遍历。
5.会将对比出来的差异进行重新渲染
react中diff算法实现流程:
DOM结构发生改变——-直接卸载并重新create
DOM结构一样——-不会卸载,但是会update变化的内容
所有同一层级的子节点.他们都可以通过key来区分——-同时遵循1.2两点
(其实这个key的存在与否只会影响diff算法的复杂度,换言之,你不加key的情况下,
diff算法就会以暴力的方式去根据一二的策略更新,但是你加了key,diff算法会引入一些另外的操作)
复制代码
React会逐个对节点进行更新,转换到目标节点。而最后插入新的节点,涉及到的DOM操作非常多。diff总共就是移动、删除、增加三个操作,而如果给每个节点唯一的标识(key),那么React优先采用移动的方式,能够找到正确的位置去插入新的节点。
vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制。
以上内容来自于Vue 和 React 的优点分别是什么?,大家说的越多理解的越深越好。我只说了其中的三点。- 前端常用的数据请求格式有哪些?都有些什么特点?
这个问题在http中已经回答了一部分了,这里就在单独详细的描述一下使用场景
Get/Post/Delete/Patch/Put经常用的这五种,其他的就不说了通常:
我们使用Get请求来获取数据
我们使用Post请求来发送数据
我们使用Put请求来更新数据
我们使用Delete请求来删除数据
我们使用Patch请求用于对资源应用部分修改。
Get和Post的区别:
1.Get 请求能缓存,Post 不能
2.Post 相对 Get 安全一点点,因为Get 请求都包含在 URL 里,
(当然你想写到 body 里也是可以的),且会被浏览器保存历史纪录。Post 不会,但是在抓包的情况下都是一样的。
4.URL有长度限制,会影响 Get 请求,但是这个长度限制是浏览器规定的,不是 RFC 规定的
5.Post 支持更多的编码类型且不对数据类型限制
复制代码- 二次封装axios,描述一下你在项目中封装axios的思路和想法
关于axios等封装,我之前有一篇简易封装axios的文章,大家可以简单参考。
通常来说,我们在二次封装axios,一般会引入UI组件的一些Message和Loading组件用来做提示信息。
1.通过获取存储在浏览器端,或者是vuex中的token信息,判断是否跳转登录页面
2.在获取到token的情况下设置自定义请求头部信息
3.在响应事件中,根据返回的不同状态码,根据业务需求,使用switch判断跳转页面还是发出提示信息。
4.封装请求和响应事件的返回结果,使用Promise封装。
5.增加请求loading和提示信息。
简单版本大致如上,复杂版本需要根据业务进行对应的封装。
复制代码- 请介绍一下this
其实大部分情况下可以用一句话来概括,this总是指向调用该函数的对象。
对于常规的函数来说,谁调用该函数,this就指向该调用者,全局环境下调用函数执行,this指向window
对于箭头函数的this总结如下:
箭头函数不绑定this,箭头函数中的this相当于普通变量。
箭头函数的this寻值行为与普通变量相同,在作用域中逐级寻找。
箭头函数的this无法通过bind,call,apply来直接修改(可以间接修改)。
改变作用域中this的指向可以改变箭头函数的this。
描述this问题,这里我们可以扩展说明如何去改变this指向,通过bind,call,apply,然后说说他们的区别,懂得多的话,
可以说说他们的实现原理,或者手写bind,call,apply的实现。
复制代码- 请介绍一下节流函数和防抖函数,简单实现节流函数和防抖函数
“节流”与“防抖”的本质: 这两个东西都以闭包的形式存在。
它们通过对事件对应的回调函数进行包裹、以自由变量的形式缓存时间信息,最后用 setTimeout 来控制事件的触发频率。
防抖函数:有这样一个按钮,他提供查看你未来老婆的样子,当你在一定时间内多次点击查询时,他只会在你最后一次点击以后,
采取执行查询操作。节流函数:当你在玩LOL的时候,你在放出大招后的一段时间内,再次点击放大招是不启作用的,因为有一个冷却时间。
代码我就不写在这里了,简易版本的很简单,完整版封装一般我们都使用lodash封装好的。
复制代码- 请介绍一下Eventloop(事件循环)
搞懂 Event Loop,是理解 Vue 对 DOM 操作优化的第一步。
Micro-Task 与 Macro-Task
事件循环中的异步队列有两种:macro(宏任务)队列和 micro(微任务)队列。常见的 macro-task 比如:
setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作、UI 渲染等。
常见的 micro-task 比如:
process.nextTick、Promise、MutationObserver 等。
大家也知道了当我们执行 JS 代码的时候其实就是往执行栈中放入函数,当遇到异步的代码时,会被挂起并在需要执行的时候,
加入到 Task(有多种 Task) 队列中。
一旦执行栈为空,Event Loop 就会从 Task 队列中拿出需要执行的代码并放入执行栈中执行,
所以本质上来说 JS 中的异步还是同步行为。所以 Event Loop 执行顺序如下所示:
首先执行同步代码,这属于宏任务
当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
执行所有微任务
当执行完所有微任务后,如有必要会渲染页面
然后开始下一轮 Event Loop,执行宏任务中的异步代码,也就是 setTimeout 中的回调函数微任务包括 process.nextTick ,promise ,MutationObserver,其中 process.nextTick 为 Node 独有。
宏任务包括 script , setTimeout ,setInterval ,setImmediate ,I/O ,UI rendering。
这里很多人会有个误区,认为微任务快于宏任务,其实是错误的。
因为宏任务中包括了 script ,浏览器会先执行一个宏任务,接下来有异步代码的话才会先执行微任务。
复制代码- 请用一个例子来形象的描述原型链
哈,这个问题我在沸点有发过一个形象的比喻,给面试官逗笑了。
每个门派都有一个祖师爷。学徒在山上学艺,学成下山后谨记师门教导,施展一身武艺。
恰逢一日对敌,面对敌人的怪异武功,师门好像未曾教过破解之法,便高喊一声祖师爷救我,
刹那间一道白光降于头顶,祖师爷灵魂附体,一套精绝凌厉的拳法杀得敌人措手不及。
但敌人也极是难缠,恐怕非要那门传说中从天而降的掌法才能制敌。
你心中暗自着急,催促着祖师爷赶快发招,这时只听身内传来了祖师的声音:
“MD这破掌法当年偷懒没学,我去把我师祖也叫来问问…”
每个门派(FunctionX)都有一个祖师爷(prototype)。
学徒(object)在山上学艺(= new FunctionX),学成下山后谨记师门教导,
施展一身武艺(http://object.xxxobject.xxx)。
恰逢一日对敌,面对敌人的怪异武功,师门好像未曾教过破解之法(object对象没有yyy方法),
便高喊一声祖师爷救我,刹那间一道白光降于头顶,祖师爷(proto)灵魂附体,
一套精绝凌厉的拳法杀得敌人措手不及(继续寻找原型中是否有yyy方法)。
但敌人也极是难缠,恐怕非要那门传说中从天而降的掌法才能制敌。你心中暗自着急,
催促着祖师爷赶快发招,这时只听身内传来了祖师的声音:
“MD这破掌法当年偷懒没学,我去把我师祖也叫来问问…”(如果原型中没有yyy方法,则继续查找原型的原型,是谓原型链)
复制代码- 请介绍一下回流(Reflow)与重绘(Repaint)
回流:当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,
浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),
然后再将计算的结果绘制出来。这个过程就是回流(也叫重排)。重绘:当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时,
浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式(跳过了上图所示的回流环节)。这个过程叫做重绘。由此我们可以看出,重绘不一定导致回流,回流一定会导致重绘。
硬要比较的话,回流比重绘做的事情更多,带来的开销也更大。但这两个说到底都是吃性能的,
所以都不是什么善茬。我们在开发中,要从代码层面出发,尽可能把回流和重绘的次数最小化。
复制代码- 请描述一下什么是执行栈
可以把执行栈认为是一个存储函数调用的栈结构,它遵从先进后出的原则。
当开始执行 JS 代码时,首先会执行一个 main 函数,然后执行我们的代码。根据先进后出的原则,后执行的函数会先弹出栈。
复制代码JavaScript 进阶问题列表(译)
我在我的 Instagram 上每天都会发布 JavaScript 的多选问题,并且同时也会在这个仓库中发布。
从基础到进阶,测试你有多了解 JavaScript,刷新你的知识,或者帮助你的 coding 面试! :muscle: :rocket: 我每周都会在这个仓库下更新新的问题。
答案在问题下方的折叠部分,点击即可展开问题。祝你好运 ❤️1. 输出是什么?
function sayHi() {
console.log(name)
console.log(age)
var name = ‘Lydia’
let age = 21
}sayHi()
复制代码- A: Lydia 和 undefined
- B: Lydia 和 ReferenceError
- C: ReferenceError 和 21
- D: undefined 和 ReferenceError
答案: D
在函数内部,我们首先通过 var 关键字声明了 name 变量。这意味着变量被提升了(内存空间在创建阶段就被设置好了),直到程序运行到定义变量位置之前默认值都是 undefined。因为当我们打印 name 变量时还没有执行到定义变量的位置,因此变量的值保持为 undefined。
通过 let 和 const 关键字声明的变量也会提升,但是和 var 不同,它们不会被初始化。在我们声明(初始化)之前是不能访问它们的。这个行为被称之为暂时性死区。当我们试图在声明之前访问它们时,JavaScript 将会抛出一个 ReferenceError 错误。2. 输出是什么?
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1)
}for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1)
}
复制代码- A: 0 1 2 和 0 1 2
- B: 0 1 2 和 3 3 3
- C: 3 3 3 和 0 1 2
答案: C
由于 JavaScript 的事件循环,setTimeout 回调会在遍历结束后才执行。因为在第一个遍历中遍历 i 是通过 var 关键字声明的,所以这个值是全局作用域下的。在遍历过程中,我们通过一元操作符 ++ 来每次递增 i 的值。当 setTimeout 回调执行的时候,i 的值等于 3。
在第二个遍历中,遍历 i 是通过 let 关键字声明的:通过 let 和 const 关键字声明的变量是拥有块级作用域(指的是任何在 {} 中的内容)。在每次的遍历过程中,i 都有一个新值,并且每个值都在循环内的作用域中。3. 输出是什么?
const shape = {
radius: 10,
diameter() {
return this.radius 2
},
perimeter: () => 2 Math.PI * this.radius
}shape.diameter()
shape.perimeter()
复制代码- A: 20 and 62.83185307179586
- B: 20 and NaN
- C: 20 and 63
- D: NaN and 63
答案: B
注意 diameter 的值是一个常规函数,但是 perimeter 的值是一个箭头函数。
对于箭头函数,this 关键字指向的是它当前周围作用域(简单来说是包含箭头函数的常规函数,如果没有常规函数的话就是全局对象),这个行为和常规函数不同。这意味着当我们调用 perimeter 时,this 不是指向 shape 对象,而是它的周围作用域(在例子中是 window)。
在 window 中没有 radius 这个属性,因此返回 undefined。4. 输出是什么?
+true;
!”Lydia”;
复制代码- A: 1 and false
- B: false and NaN
- C: false and false
答案: A
一元操作符加号尝试将 bool 转为 number。true 转换为 number 的话为 1,false 为 0。
字符串 ‘Lydia’ 是一个真值,真值取反那么就返回 false。5. 哪一个是无效的?
const bird = {
size: ‘small’
}const mouse = {
name: ‘Mickey’,
small: true
}
复制代码- A: mouse.bird.size
- B: mouse[bird.size]
- C: mouse[bird[“size”]]
- D: All of them are valid
答案: A
在 JavaScript 中,所有对象的 keys 都是字符串(除非对象是 Symbol)。尽管我们可能不会定义它们为字符串,但它们在底层总会被转换为字符串。
当我们使用括号语法时([]),JavaScript 会解释(或者 unboxes)语句。它首先看到第一个开始括号 [ 并继续前进直到找到结束括号 ]。只有这样,它才会计算语句的值。
mouse[bird.size]:首先计算 bird.size,这会得到 small。mouse[“small”] 返回 true。
然后使用点语法的话,上面这一切都不会发生。mouse 没有 bird 这个 key,这也就意味着 mouse.bird 是 undefined。然后当我们使用点语法 mouse.bird.size 时,因为 mouse.bird 是 undefined,这也就变成了 undefined.size。这个行为是无效的,并且会抛出一个错误类似 Cannot read property “size” of undefined。6. 输出是什么?
let c = { greeting: ‘Hey!’ }
let dd = c
c.greeting = ‘Hello’
console.log(d.greeting)
复制代码- A: Hello
- B: undefined
- C: ReferenceError
- D: TypeError
答案: A
在 JavaScript 中,当设置两个对象彼此相等时,它们会通过引用进行交互。
首先,变量 c 的值是一个对象。接下来,我们给 d 分配了一个和 c 对象相同的引用。因此当我们改变其中一个对象时,其实是改变了所有的对象。
7. 输出是什么?
let a = 3
let b = new Number(3)
let c = 3console.log(a == b)
console.log(a === b)
console.log(b === c)
复制代码- A: true false true
- B: false false true
- C: true false false
- D: false true true
答案: C
new Number() 是一个内建的函数构造器。虽然它看着像是一个 number,但它实际上并不是一个真实的 number:它有一堆额外的功能并且它是一个对象。
当我们使用 == 操作符时,它只会检查两者是否拥有相同的值。因为它们的值都是 3,因此返回 true。
然后,当我们使用 === 操作符时,两者的值以及类型都应该是相同的。new Number() 是一个对象而不是 number,因此返回 false。8. 输出是什么?
class Chameleon {
static colorChange(newColor) {
this.newColor = newColor
return this.newColor
}constructor({ newColor = ‘green’ } = {}) {
this.newColor = newColor
}
}const freddie = new Chameleon({ newColor: ‘purple’ })
freddie.colorChange(‘orange’)
复制代码- A: orange
- B: purple
- C: green
- D: TypeError
答案: D
colorChange 是一个静态方法。静态方法被设计为只能被创建它们的构造器使用(也就是 Chameleon),并且不能传递给实例。因为 freddie 是一个实例,静态方法不能被实例使用,因此抛出了 TypeError 错误。
9. 输出是什么?
let greeting
greetign = {} // Typo!
console.log(greetign)
复制代码- A: {}
- B: ReferenceError: greetign is not defined
- C: undefined
答案: A
代码打印出了一个对象,这是因为我们在全局对象上创建了一个空对象!当我们将 greeting 写错成 greetign 时,JS 解释器实际在上浏览器中将它视为 global.greetign = {} (或者 window.greetign = {})。
为了避免这个为题,我们可以使用 `”use strict”。这能确保当你声明变量时必须赋值。10. 当我们这么做时,会发生什么?
function bark() {
console.log(‘Woof!’)
}bark.animal = ‘dog’
复制代码- A: 正常运行!
- B: SyntaxError. 你不能通过这种方式给函数增加属性。
- C: undefined
- D: ReferenceError
答案: A
这在 JavaScript 中是可以的,因为函数是对象!(除了基本类型之外其他都是对象)
函数是一个特殊的对象。你写的这个代码其实不是一个实际的函数。函数是一个拥有属性的对象,并且属性也可被调用。11. 输出是什么?
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}const member = new Person(“Lydia”, “Hallie”);
Person.getFullName = function () {
return${this.firstName} ${this.lastName};
}console.log(member.getFullName());
复制代码- A: TypeError
- B: SyntaxError
- C: Lydia Hallie
- D: undefined undefined
答案: A
你不能像常规对象那样,给构造函数添加属性。如果你想一次性给所有实例添加特性,你应该使用原型。因此本例中,使用如下方式:
Person.prototype.getFullName = function () {
return${this.firstName} ${this.lastName};
}
复制代码
这才会使 member.getFullName() 起作用。为什么这么做有益的?假设我们将这个方法添加到构造函数本身里。也许不是每个 Person 实例都需要这个方法。这将浪费大量内存空间,因为它们仍然具有该属性,这将占用每个实例的内存空间。相反,如果我们只将它添加到原型中,那么它只存在于内存中的一个位置,但是所有实例都可以访问它!12. 输出是什么?
function Person(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}const lydia = new Person(‘Lydia’, ‘Hallie’)
const sarah = Person(‘Sarah’, ‘Smith’)console.log(lydia)
console.log(sarah)
复制代码- A: Person {firstName: “Lydia”, lastName: “Hallie”} and undefined
- B: Person {firstName: “Lydia”, lastName: “Hallie”} and Person {firstName: “Sarah”, lastName: “Smith”}
- C: Person {firstName: “Lydia”, lastName: “Hallie”} and {}
- D:Person {firstName: “Lydia”, lastName: “Hallie”} and ReferenceError
答案: A
对于 sarah,我们没有使用 new 关键字。当使用 new 时,this 引用我们创建的空对象。当未使用 new 时,this 引用的是全局对象(global object)。
我们说 this.firstName 等于 “Sarah”,并且 this.lastName 等于 “Smith”。实际上我们做的是,定义了 global.firstName = ‘Sarah’ 和 global.lastName = ‘Smith’。而 sarah 本身是 undefined。13. 事件传播的三个阶段是什么?
- A: Target > Capturing > Bubbling
- B: Bubbling > Target > Capturing
- C: Target > Bubbling > Capturing
- D: Capturing > Target > Bubbling
答案: D
在捕获(capturing)阶段中,事件从祖先元素向下传播到目标元素。当事件达到目标(target)元素后,冒泡(bubbling)才开始。
14. 所有对象都有原型。
- A: true
- B: false
答案: B
除了基本对象(base object),所有对象都有原型。基本对象可以访问一些方法和属性,比如 .toString。这就是为什么你可以使用内置的 JavaScript 方法!所有这些方法在原型上都是可用的。虽然 JavaScript 不能直接在对象上找到这些方法,但 JavaScript 会沿着原型链找到它们,以便于你使用。
15. 输出是什么?
function sum(a, b) {
return a + b
}sum(1, ‘2’)
复制代码- A: NaN
- B: TypeError
- C: “12”
- D: 3
答案: C
JavaScript 是一种动态类型语言:我们不指定某些变量的类型。值可以在你不知道的情况下自动转换成另一种类型,这种类型称为隐式类型转换(implicit type coercion)。Coercion 是指将一种类型转换为另一种类型。
在本例中,JavaScript 将数字 1 转换为字符串,以便函数有意义并返回一个值。在数字类型(1)和字符串类型(’2’)相加时,该数字被视为字符串。我们可以连接字符串,比如 “Hello” + “World”,这里发生的是 “1” + “2”,它返回 “12”。16. 输出是什么?
let number = 0
console.log(number++)
console.log(++number)
console.log(number)
复制代码- A: 1 1 2
- B: 1 2 2
- C: 0 2 2
- D: 0 1 2
答案: C
一元后自增运算符 ++:
- 返回值(返回 0)
- 值自增(number 现在是 1)
一元前自增运算符 ++:
- 值自增(number 现在是 2)
- 返回值(返回 2)
结果是 0 2 2.
17. 输出是什么?
function getPersonInfo(one, two, three) {
console.log(one)
console.log(two)
console.log(three)
}const person = ‘Lydia’
const age = 21getPersonInfo
${person} is ${age} years old
复制代码- A: “Lydia” 21 [“”, “ is “, “ years old”]
- B: [“”, “ is “, “ years old”] “Lydia” 21
- C: “Lydia” [“”, “ is “, “ years old”] 21
答案: B
如果使用标记模板字面量,第一个参数的值总是包含字符串的数组。其余的参数获取的是传递的表达式的值!
18. 输出是什么?
function checkAge(data) {
if (data === { age: 18 }) {
console.log(‘You are an adult!’)
} else if (data == { age: 18 }) {
console.log(‘You are still an adult.’)
} else {
console.log(Hmm.. You don't have an age I guess)
}
}checkAge({ age: 18 })
复制代码- A: You are an adult!
- B: You are still an adult.
- C: Hmm.. You don’t have an age I guess
答案: C
在测试相等性时,基本类型通过它们的值(value)进行比较,而对象通过它们的引用(reference)进行比较。JavaScript 检查对象是否具有对内存中相同位置的引用。
题目中我们正在比较的两个对象不是同一个引用:作为参数传递的对象引用的内存位置,与用于判断相等的对象所引用的内存位置并不同。
这也是 { age: 18 } === { age: 18 } 和 { age: 18 } == { age: 18 } 都返回 false 的原因。19. 输出是什么?
function getAge(…args) {
console.log(typeof args)
}getAge(21)
复制代码- A: “number”
- B: “array”
- C: “object”
- D: “NaN”
答案: C
扩展运算符(…args)会返回实参组成的数组。而数组是对象,因此 typeof args 返回 “object”。
20. 输出是什么?
function getAge() {
‘use strict’
age = 21
console.log(age)
}getAge()
复制代码- A: 21
- B: undefined
- C: ReferenceError
- D: TypeError
答案: C
使用 “use strict”,你可以确保不会意外地声明全局变量。我们从来没有声明变量 age,因为我们使用 “use strict”,它将抛出一个引用错误。如果我们不使用 “use strict”,它就会工作,因为属性 age 会被添加到全局对象中了。
21. 输出是什么?
const sum = eval(‘10*10+5’)
复制代码- A: 105
- B: “105”
- C: TypeError
- D: “10*10+5”
答案: A
代码以字符串形式传递进来,eval 对其求值。如果它是一个表达式,就像本例中那样,它对表达式求值。表达式是 10 * 10 + 5。这将返回数字 105。
22. cool_secret 可访问多长时间?
sessionStorage.setItem(‘cool_secret’, 123)
复制代码- A: 永远,数据不会丢失。
- B: 当用户关掉标签页时。
- C: 当用户关掉整个浏览器,而不只是关掉标签页。
- D: 当用户关闭电脑时。
答案: B
关闭 tab 标签页 后,sessionStorage 存储的数据才会删除。
如果使用 localStorage,那么数据将永远在那里,除非调用了 localStorage.clear()。23. 输出是什么?
var num = 8
var num = 10console.log(num)
复制代码- A: 8
- B: 10
- C: SyntaxError
- D: ReferenceError
答案: B
使用 var 关键字,你可以用相同的名称声明多个变量。然后变量将保存最新的值。
你不能使用 let 或 const 来实现这一点,因为它们是块作用域的。24. 输出是什么?
const obj = { 1: ‘a’, 2: ‘b’, 3: ‘c’ }
const set = new Set([1, 2, 3, 4, 5])obj.hasOwnProperty(‘1’)
obj.hasOwnProperty(1)
set.has(‘1’)
set.has(1)
复制代码- A: false true false true
- B: false true true true
- C: true true false true
- D: true true true true
答案: C
所有对象的键(不包括 Symbol)在底层都是字符串,即使你自己没有将其作为字符串输入。这就是为什么 obj.hasOwnProperty(‘1’) 也返回 true。
对于集合,它不是这样工作的。在我们的集合中没有 ‘1’:set.has(‘1’) 返回 false。它有数字类型为 1,set.has(1) 返回 true。25. 输出是什么?
const obj = { a: ‘one’, b: ‘two’, a: ‘three’ }
console.log(obj)
复制代码- A: { a: “one”, b: “two” }
- B: { b: “two”, a: “three” }
- C: { a: “three”, b: “two” }
- D: SyntaxError
答案: C
如果你有两个名称相同的键,则键会被替换掉。它仍然位于第一个键出现的位置,但是值是最后出现那个键的值。
26. JavaScript 全局执行上下文为你做了两件事:全局对象和 this 关键字。
- A: true
- B: false
- C: it depends
答案: A
基本执行上下文是全局执行上下文:它是代码中随处可访问的内容。
27. 输出是什么?
for (let i = 1; i < 5; i++) {
if (i === 3) continue
console.log(i)
}
复制代码- A: 1 2
- B: 1 2 3
- C: 1 2 4
- D: 1 3 4
答案: C
如果某个条件返回 true,则 continue 语句跳过本次迭代。
28. 输出是什么?
String.prototype.giveLydiaPizza = () => {
return ‘Just give Lydia pizza already!’
}const name = ‘Lydia’
name.giveLydiaPizza()
复制代码- A: “Just give Lydia pizza already!”
- B: TypeError: not a function
- C: SyntaxError
- D: undefined
答案: A
String 是内置的构造函数,我们可以向它添加属性。我只是在它的原型中添加了一个方法。基本类型字符串被自动转换为字符串对象,由字符串原型函数生成。因此,所有 string(string 对象)都可以访问该方法!
29. 输出是什么?
const a = {}
const b = { key: ‘b’ }
const c = { key: ‘c’ }a[b] = 123
a[c] = 456console.log(a[b])
复制代码- A: 123
- B: 456
- C: undefined
- D: ReferenceError
答案: B
对象的键被自动转换为字符串。我们试图将一个对象 b 设置为对象 a 的键,且相应的值为 123。
然而,当字符串化一个对象时,它会变成 “[object Object]”。因此这里说的是,a[“[object Object]”] = 123。然后,我们再一次做了同样的事情,c 是另外一个对象,这里也有隐式字符串化,于是,a[“[object Object]”] = 456。
然后,我们打印 a[b],也就是 a[“[object Object]”]。之前刚设置为 456,因此返回的是 456。30. 输出是什么?
const foo = () => console.log(‘First’)
const bar = () => setTimeout(() => console.log(‘Second’))
const baz = () => console.log(‘Third’)bar()
foo()
baz()
复制代码- A: First Second Third
- B: First Third Second
- C: Second First Third
- D: Second Third First
答案: B
我们有一个 setTimeout 函数,并首先调用它。然而,它是最后打印日志的。
这是因为在浏览器中,我们不仅有运行时引擎,还有一个叫做 WebAPI 的东西。WebAPI 提供了 setTimeout 函数,也包含其他的,例如 DOM。
将 callback 推送到 WebAPI 后,setTimeout 函数本身(但不是回调!)将从栈中弹出。现在,foo 被调用,打印 “First”。
foo 从栈中弹出,baz 被调用. 打印 “Third”。
WebAPI 不能随时向栈内添加内容。相反,它将回调函数推到名为 queue 的地方。
这就是事件循环开始工作的地方。一个事件循环查看栈和任务队列。如果栈是空的,它接受队列上的第一个元素并将其推入栈。
bar 被调用,打印 “Second”,然后它被栈弹出。
31. 当点击按钮时,event.target是什么?
复制代码- A: Outer div
- B: Inner div
- C: button
- D: 一个包含所有嵌套元素的数组。
答案: C
导致事件的最深嵌套的元素是事件的 target。你可以通过 event.stopPropagation 来停止冒泡。
32. 当您单击该段落时,日志输出是什么?
Click here!
复制代码- A: p div
- B: div p
- C: p
- D: div
答案: A
如果我们点击 p,我们会看到两个日志:p 和 div。在事件传播期间,有三个阶段:捕获、目标和冒泡。默认情况下,事件处理程序在冒泡阶段执行(除非将 useCapture 设置为 true)。它从嵌套最深的元素向外传播。
33. 输出是什么?
const person = { name: ‘Lydia’ }
function sayHi(age) {
console.log(${this.name} is ${age})
}sayHi.call(person, 21)
sayHi.bind(person, 21)
复制代码- A: undefined is 21 Lydia is 21
- B: function function
- C: Lydia is 21 Lydia is 21
- D: Lydia is 21 function
答案: D
使用这两种方法,我们都可以传递我们希望 this 关键字引用的对象。但是,.call 是立即执行的。
.bind 返回函数的副本,但带有绑定上下文!它不是立即执行的。34. 输出是什么?
function sayHi() {
return (() => 0)()
}typeof sayHi()
复制代码- A: “object”
- B: “number”
- C: “function”
- D: “undefined”
答案: B
sayHi 方法返回的是立即执行函数(IIFE)的返回值.此立即执行函数的返回值是 0, 类型是 number
参考:只有7种内置类型:null,undefined,boolean,number,string,object 和 symbol。 function 不是一种类型,函数是对象,它的类型是object。35. 下面哪些值是 falsy?
0
new Number(0)
(‘’)
(‘ ‘)
new Boolean(false)
undefined
复制代码- A: 0, ‘’, undefined
- B: 0, new Number(0), ‘’, new Boolean(false), undefined
- C: 0, ‘’, new Boolean(false), undefined
- D: All of them are falsy
答案: A
只有 6 种 falsy 值:
- undefined
- null
- NaN
- 0
- ‘’ (empty string)
- false
Function 构造函数, 比如 new Number 和 new Boolean,是 truthy。
36. 输出是什么?
console.log(typeof typeof 1)
复制代码- A: “number”
- B: “string”
- C: “object”
- D: “undefined”
答案: B
typeof 1 返回 “number”。 typeof “number” 返回 “string”。
37. 输出是什么?
const numbers = [1, 2, 3]
numbers[10] = 11
console.log(numbers)
复制代码- A: [1, 2, 3, 7 x null, 11]
- B: [1, 2, 3, 11]
- C: [1, 2, 3, 7 x empty, 11]
- D: SyntaxError
答案: C
当你为数组设置超过数组长度的值的时候, JavaScript 会创建名为 “empty slots” 的东西。它们的值实际上是 undefined。你会看到以下场景:
[1, 2, 3, 7 x empty, 11]
这取决于你的运行环境(每个浏览器,以及 node 环境,都有可能不同)38. 输出是什么?
(() => {
let x, y
try {
throw new Error()
} catch (x) {
(x = 1), (y = 2)
console.log(x)
}
console.log(x)
console.log(y)
})()
复制代码- A: 1 undefined 2
- B: undefined undefined undefined
- C: 1 1 2
- D: 1 undefined undefined
答案: A
catch 代码块接收参数 x。当我们传递参数时,这与之前定义的变量 x 不同 。这个 x 是属于 catch 块级作用域的。
然后,我们将块级作用域中的变量赋值为 1,同时也设置了变量 y 的值。现在,我们打印块级作用域中的变量 x,值为 1。
catch 块之外的变量 x 的值仍为 undefined, y 的值为 2。当我们在 catch 块之外执行 console.log(x) 时,返回 undefined,y 返回 2。39. JavaScript 中的一切都是?
- A: 基本类型与对象
- B: 函数与对象
- C: 只有对象
- D: 数字与对象
答案: A
JavaScript 只有基本类型和对象。
基本类型包括 boolean, null, undefined, bigint, number, string, symbol。40. 输出是什么?
[[0, 1], [2, 3]].reduce(
(acc, cur) => {
return acc.concat(cur)
},
[1, 2]
)
复制代码- A: [0, 1, 2, 3, 1, 2]
- B: [6, 1, 2]
- C: [1, 2, 0, 1, 2, 3]
- D: [1, 2, 6]
答案: C
[1, 2]是初始值。初始值将会作为首次调用时第一个参数 acc 的值。在第一次执行时, acc 的值是 [1, 2], cur 的值是 [0, 1]。合并它们,结果为 [1, 2, 0, 1]。 第二次执行, acc 的值是 [1, 2, 0, 1], cur 的值是 [2, 3]。合并它们,最终结果为 [1, 2, 0, 1, 2, 3]
41. 输出是什么?
!!null
!!’’
!!1
复制代码- A: false true false
- B: false false true
- C: false true true
- D: true true false
答案: B
null 是 falsy。 !null 的值是 true。 !true 的值是 false。
“” 是 falsy。 !”” 的值是 true。 !true 的值是 false。
1 是 truthy。 !1 的值是 false。 !false 的值是 true。42. setInterval 方法的返回值是什么?
setInterval(() => console.log(‘Hi’), 1000)
复制代码- A: 一个唯一的id
- B: 该方法指定的毫秒数
- C: 传递的函数
- D: undefined
答案: A
setInterval 返回一个唯一的 id。此 id 可被用于 clearInterval 函数来取消定时。
43. 输出是什么?
[…’Lydia’]
复制代码- A: [“L”, “y”, “d”, “i”, “a”]
- B: [“Lydia”]
- C: [[], “Lydia”]
- D: [[“L”, “y”, “d”, “i”, “a”]]
答案: A
string 类型是可迭代的。扩展运算符将迭代的每个字符映射成一个元素。
44. 输出是什么?
function generator(i) {
yield i;
yield i 2;
}const gen = generator(10);
console.log(gen.next().value);
console.log(gen.next().value);
复制代码- A: [0, 10], [10, 20]
- B: 20, 20
- C: 10, 20
- D: 0, 10 and 10, 20
答案: C
一般的函数在执行之后是不能中途停下的。但是,生成器函数却可以中途“停下”,之后可以再从停下的地方继续。当生成器遇到yield关键字的时候,会生成yield后面的值。注意,生成器在这种情况下不 返回 (return )值,而是 生成 (yield)值。
首先,我们用10作为参数i来初始化生成器函数。然后使用next()方法一步步执行生成器。第一次执行生成器的时候,i的值为10,遇到第一个yield关键字,它要生成i的值。此时,生成器“暂停”,生成了10。
然后,我们再执行next()方法。生成器会从刚才暂停的地方继续,这个时候i还是10。于是我们走到了第二个yield关键字处,这时候需要生成的值是i*2,i为10,那么此时生成的值便是20。所以这道题的最终结果是10,20。45. 返回值是什么?
const firstPromise = new Promise((res, rej) => {
setTimeout(res, 500, “one”);
});const secondPromise = new Promise((res, rej) => {
setTimeout(res, 100, “two”);
});Promise.race([firstPromise, secondPromise]).then(res => console.log(res));
复制代码- A: “one”
- B: “two”
- C: “two” “one”
- D: “one” “two”
答案: B
当我们向Promise.race方法中传入多个Promise时,会进行 优先 解析。在这个例子中,我们用setTimeout给firstPromise和secondPromise分别设定了500ms和100ms的定时器。这意味着secondPromise会首先解析出字符串two。那么此时res参数即为two,是为输出结果。
46. 输出是什么?
let person = { name: “Lydia” };
const members = [person];
person = null;console.log(members);
复制代码- A: null
- B: [null]
- C: [{}]
- D: [{ name: “Lydia” }]
答案: D
首先我们声明了一个拥有name属性的对象 person。
然后我们又声明了一个变量members. 将首个元素赋值为变量person。 当设置两个对象彼此相等时,它们会通过 引用 进行交互。但是当你将引用从一个变量分配至另一个变量时,其实只是执行了一个 复制 操作。(注意一点,他们的引用 并不相同!)
接下来我们让person等于null。
我们没有修改数组第一个元素的值,而只是修改了变量person的值,因为元素(复制而来)的引用与person不同。members的第一个元素仍然保持着对原始对象的引用。当我们输出members数组时,第一个元素会将引用的对象打印出来。
47. 输出是什么?
const person = {
name: “Lydia”,
age: 21
};for (const item in person) {
console.log(item);
}
复制代码- A: { name: “Lydia” }, { age: 21 }
- B: “name”, “age”
- C: “Lydia”, 21
- D: [“name”, “Lydia”], [“age”, 21]
答案: B
在for-in循环中,我们可以通过对象的key来进行迭代,也就是这里的name和age。在底层,对象的key都是字符串(如果他们不是Symbol的话)。在每次循环中,我们将item设定为当前遍历到的key.所以一开始,item是name,之后 item输出的则是age。
48. 输出是什么?
console.log(3 + 4 + “5”);
复制代码- A: “345”
- B: “75”
- C: 12
- D: “12”
答案: B
当所有运算符的 优先级 相同时,计算表达式需要确定运算符的结合顺序,即从右到左还是从左往右。在这个例子中,我们只有一类运算符+,对于加法来说,结合顺序就是从左到右。
3 + 4首先计算,得到数字7.
由于类型的强制转换,7 + ‘5’的结果是”75”. JavaScript将7转换成了字符串,可以参考问题15.我们可以用+号把两个字符串连接起来。 “7” + “5” 就得到了”75”.49. num的值是什么?
const num = parseInt(“7*6”, 10);
复制代码- A: 42
- B: “42”
- C: 7
- D: NaN
答案: C
只返回了字符串中第一个字母. 设定了 进制 后 (也就是第二个参数,指定需要解析的数字是什么进制: 十进制、十六机制、八进制、二进制等等……),parseInt 检查字符串中的字符是否合法. 一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。
*就是不合法的数字字符。所以只解析到”7”,并将其解析为十进制的7. num的值即为7.50. 输出是什么?
[1, 2, 3].map(num => {
if (typeof num === “number”) return;
return num * 2;
});
复制代码- A: []
- B: [null, null, null]
- C: [undefined, undefined, undefined]
- D: [ 3 x empty ]
答案: C
对数组进行映射的时候,num就是当前循环到的元素. 在这个例子中,所有的映射都是number类型,所以if中的判断typeof num === “number”结果都是true.map函数创建了新数组并且将函数的返回值插入数组。
但是,没有任何值返回。当函数没有返回任何值时,即默认返回undefined.对数组中的每一个元素来说,函数块都得到了这个返回值,所以结果中每一个元素都是undefined.51. 输出的是什么?
function getInfo(member, year) {
member.name = “Lydia”;
year = “1998”;
}const person = { name: “Sarah” };
const birthYear = “1997”;getInfo(person, birthYear);
console.log(person, birthYear);
复制代码- A: { name: “Lydia” }, “1997”
- B: { name: “Sarah” }, “1998”
- C: { name: “Lydia” }, “1998”
- D: { name: “Sarah” }, “1997”
答案: A
普通参数都是 值 传递的,而对象则不同,是 引用 传递。所以说,birthYear是值传递,因为他是个字符串而不是对象。当我们对参数进行值传递时,会创建一份该值的 复制 。(可以参考问题46)
变量birthYear有一个对”1997”的引用,而传入的参数也有一个对”1997”的引用,但二者的引用并不相同。当我们通过给 year赋值”1998”来更新year的值的时候我们只是更新了year(的引用)。此时birthYear仍然是”1997”.
而person是个对象。参数member引用与之 相同的 对象。当我们修改member所引用对象的属性时,person的相应属性也被修改了,因为他们引用了相同的对象. person的 name属性也变成了 “Lydia”.52. 输出是什么?
function greeting() {
throw “Hello world!”;
}function sayHi() {
try {
const data = greeting();
console.log(“It worked!”, data);
} catch (e) {
console.log(“Oh no an error!”, e);
}
}sayHi();
复制代码- A: “It worked! Hello world!”
- B: “Oh no an error: undefined
- C: SyntaxError: can only throw Error objects
- D: “Oh no an error: Hello world!
答案: D
通过throw语句,我么可以创建自定义错误。 而通过它,我们可以抛出异常。异常可以是一个字符串, 一个 数字, 一个 布尔类型 或者是一个 对象。在本例中,我们的异常是字符串’Hello world’.
通过 catch语句,我们可以设定当try语句块中抛出异常后应该做什么处理。在本例中抛出的异常是字符串’Hello world’. e就是这个字符串,因此被输出。最终结果就是’Oh an error: Hello world’.53. 输出是什么?
function Car() {
this.make = “Lamborghini”;
return { make: “Maserati” };
}const myCar = new Car();
console.log(myCar.make);
复制代码- A: “Lamborghini”
- B: “Maserati”
- C: ReferenceError
- D: TypeError
答案: B
返回属性的时候,属性的值等于 返回的 值,而不是构造函数中设定的值。我们返回了字符串 “Maserati”,所以 myCar.make等于”Maserati”.
54. 输出是什么?
(() => {
let x = (y = 10);
})();console.log(typeof x);
console.log(typeof y);
复制代码- A: “undefined”, “number”
- B: “number”, “number”
- C: “object”, “number”
- D: “number”, “undefined”
答案: A
let x = y = 10; 是下面这个表达式的缩写:
y = 10;
let x = y;
复制代码
我们设定y等于10时,我们实际上增加了一个属性y给全局对象(浏览器里的window, Nodejs里的global)。在浏览器中, window.y等于10.
然后我们声明了变量x等于y,也是10.但变量是使用 let声明的,它只作用于 块级作用域, 仅在声明它的块中有效;就是案例中的立即调用表达式(IIFE)。使用typeof操作符时, 操作值 x没有被定义:因为我们在x声明块的外部,无法调用它。这就意味着x未定义。未分配或是未声明的变量类型为”undefined”. console.log(typeof x)返回”undefined”.
而我们创建了全局变量y,并且设定y等于10.这个值在我们的代码各处都访问的到。 y已经被定义了,而且有一个”number”类型的值。 console.log(typeof y)返回”number”.55. 输出是什么?
class Dog {
constructor(name) {
this.name = name;
}
}Dog.prototype.bark = function() {
console.log(Woof I am ${this.name});
};const pet = new Dog(“Mara”);
pet.bark();
delete Dog.prototype.bark;
pet.bark();
复制代码- A: “Woof I am Mara”, TypeError
- B: “Woof I am Mara”,”Woof I am Mara”
- C: “Woof I am Mara”, undefined
- D: TypeError, TypeError
答案: A
我们可以用delete关键字删除对象的属性,对原型也是适用的。删除了原型的属性后,该属性在原型链上就不可用了。在本例中,函数bark在执行了delete Dog.prototype.bark后不可用, 然而后面的代码还在调用它。
当我们尝试调用一个不存在的函数时TypeError异常会被抛出。在本例中就是 TypeError: pet.bark is not a function,因为pet.bark是undefined.56. 输出是什么?
const set = new Set([1, 1, 2, 3, 4]);
console.log(set);
复制代码- A: [1, 1, 2, 3, 4]
- B: [1, 2, 3, 4]
- C: {1, 1, 2, 3, 4}
- D: {1, 2, 3, 4}
答案: D
Set对象是独一无二的值的集合:也就是说同一个值在其中仅出现一次。
我们传入了数组[1, 1, 2, 3, 4],他有一个重复值1.以为一个集合里不能有两个重复的值,其中一个就被移除了。所以结果是 {1, 2, 3, 4}.57. 输出是什么?
// counter.js
let counter = 10;
export default counter;
复制代码
// index.js
import myCounter from “./counter”;myCounter += 1;
console.log(myCounter);
复制代码- A: 10
- B: 11
- C: Error
- D: NaN
答案: C
引入的模块是 只读 的: 你不能修改引入的模块。只有导出他们的模块才能修改其值。
当我们给myCounter增加一个值的时候会抛出一个异常: myCounter是只读的,不能被修改。58. 输出是什么?
const name = “Lydia”;
age = 21;console.log(delete name);
console.log(delete age);
复制代码- A: false, true
- B: “Lydia”, 21
- C: true, true
- D: undefined, undefined
答案: A
delete操作符返回一个布尔值: true指删除成功,否则返回false. 但是通过 var, const 或 let 关键字声明的变量无法用 delete 操作符来删除。
name变量由const关键字声明,所以删除不成功:返回 false. 而我们设定age等于21时,我们实际上添加了一个名为age的属性给全局对象。对象中的属性是可以删除的,全局对象也是如此,所以delete age返回true.59. 输出是什么?
const numbers = [1, 2, 3, 4, 5];
const [y] = numbers;console.log(y);
复制代码- A: [[1, 2, 3, 4, 5]]
- B: [1, 2, 3, 4, 5]
- C: 1
- D: [1]
答案: C
我们可以通过解构赋值来解析来自对象的数组或属性的值,比如说:
[a, b] = [1, 2];
复制代码a的值现在是1,b的值现在是2.而在题目中,我们是这么做的:
[y] = [1, 2, 3, 4, 5];
复制代码也就是说,y等于数组的第一个值就是数字1.我们输出y, 返回1.
60. 输出是什么?
const user = { name: “Lydia”, age: 21 };
const admin = { admin: true, …user };console.log(admin);
复制代码- A: { admin: true, user: { name: “Lydia”, age: 21 } }
- B: { admin: true, name: “Lydia”, age: 21 }
- C: { admin: true, user: [“Lydia”, 21] }
- D: { admin: true }
答案: B
扩展运算符…为对象的组合提供了可能。你可以复制对象中的键值对,然后把它们加到另一个对象里去。在本例中,我们复制了user对象键值对,然后把它们加入到admin对象中。admin对象就拥有了这些键值对,所以结果为{ admin: true, name: “Lydia”, age: 21 }.
61. 输出是什么?
const person = { name: “Lydia” };
Object.defineProperty(person, “age”, { value: 21 });
console.log(person);
console.log(Object.keys(person));
复制代码- A: { name: “Lydia”, age: 21 }, [“name”, “age”]
- B: { name: “Lydia”, age: 21 }, [“name”]
- C: { name: “Lydia”}, [“name”, “age”]
- D: { name: “Lydia”}, [“age”]
答案: B
通过defineProperty方法,我们可以给对象添加一个新属性,或者修改已经存在的属性。而我们使用defineProperty方法给对象添加了一个属性之后,属性默认为 不可枚举(not enumerable). Object.keys方法仅返回对象中 可枚举(enumerable) 的属性,因此只剩下了”name”.
用defineProperty方法添加的属性默认不可变。你可以通过writable, configurable 和 enumerable属性来改变这一行为。这样的话, 相比于自己添加的属性,defineProperty方法添加的属性有了更多的控制权。62. 输出是什么?
const settings = {
username: “lydiahallie”,
level: 19,
health: 90
};const data = JSON.stringify(settings, [“level”, “health”]);
console.log(data);
复制代码- A: “{“level”:19, “health”:90}”
- B: “{“username”: “lydiahallie”}”
- C: “[“level”, “health”]”
- D: “{“username”: “lydiahallie”, “level”:19, “health”:90}”
答案: A
JSON.stringify的第二个参数是 替代者(replacer). 替代者(replacer)可以是个函数或数组,用以控制哪些值如何被转换为字符串。
如果替代者(replacer)是个 数组 ,那么就只有包含在数组中的属性将会被转化为字符串。在本例中,只有名为”level” 和 “health” 的属性被包括进来, “username”则被排除在外。 data 就等于 “{“level”:19, “health”:90}”.
而如果替代者(replacer)是个 函数,这个函数将被对象的每个属性都调用一遍。 函数返回的值会成为这个属性的值,最终体现在转化后的JSON字符串中(译者注:Chrome下,经过实验,如果所有属性均返回同一个值的时候有异常,会直接将返回值作为结果输出而不会输出JSON字符串),而如果返回值为undefined,则该属性会被排除在外。63. 输出是什么?
let num = 10;
const increaseNumber = () => num++;
const increasePassedNumber = number => number++;const num1 = increaseNumber();
const num2 = increasePassedNumber(num1);console.log(num1);
console.log(num2);
复制代码- A: 10, 10
- B: 10, 11
- C: 11, 11
- D: 11, 12
答案: A
一元操作符 ++ 先返回 操作值, 再累加 操作值。num1的值是10, 因为increaseNumber函数首先返回num的值,也就是10,随后再进行 num的累加。
num2是10因为我们将 num1传入increasePassedNumber. number等于10(num1的值。同样道理,++ 先返回 操作值, 再累加 操作值。) number是10,所以num2也是10.64. 输出什么?
const value = { number: 10 };
const multiply = (x = { …value }) => {
console.log(x.number *= 2);
};multiply();
multiply();
multiply(value);
multiply(value);
复制代码- A: 20, 40, 80, 160
- B: 20, 40, 20, 40
- C: 20, 20, 20, 40
- D: NaN, NaN, 20, 40
答案: C
在ES6中,我们可以使用默认值初始化参数。如果没有给函数传参,或者传的参值为 “undefined” ,那么参数的值将是默认值。上述例子中,我们将 value 对象进行了解构并传到一个新对象中,因此 x 的默认值为 {number:10} 。
默认参数在调用时才会进行计算,每次调用函数时,都会创建一个新的对象。我们前两次调用 multiply 函数且不传递值,那么每一次 x 的默认值都为 {number:10} ,因此打印出该数字的乘积值为20。
第三次调用 multiply 时,我们传递了一个参数,即对象value。 =运算符实际上是x.number = x.number 2的简写,我们修改了x.number的值,并打印出值20。
第四次,我们再次传递value对象。 x.number之前被修改为20,所以x.number * = 2打印为40。65. 输出什么?
[1, 2, 3, 4].reduce((x, y) => console.log(x, y));
复制代码- A: 1 2 and 3 3 and 6 4
- B: 1 2 and 2 3 and 3 4
- C: 1 undefined and 2 undefined and 3 undefined and 4 undefined
- D: 1 2 and undefined 3 and undefined 4
答案: D
reducer 函数接收4个参数:
- Accumulator (acc) (累计器)
- Current Value (cur) (当前值)
- Current Index (idx) (当前索引)
- Source Array (src) (源数组)
reducer 函数的返回值将会分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。
reducer 函数还有一个可选参数initialValue, 该参数将作为第一次调用回调函数时的第一个参数的值。如果没有提供initialValue,则将使用数组中的第一个元素。
在上述例子,reduce方法接收的第一个参数(Accumulator)是x, 第二个参数(Current Value)是y。
在第一次调用时,累加器x为1,当前值“y”为2,打印出累加器和当前值:1和2。
例子中我们的回调函数没有返回任何值,只是打印累加器的值和当前值。如果函数没有返回值,则默认返回undefined。 在下一次调用时,累加器为undefined,当前值为“3”, 因此undefined和3被打印出。
在第四次调用时,回调函数依然没有返回值。 累加器再次为 undefined ,当前值为“4”。 undefined和4被打印出。66. 使用哪个构造函数可以成功继承Dog类?
class Dog {
constructor(name) {
this.name = name;
}
};class Labrador extends Dog {
// 1
constructor(name, size) {
this.size = size;
}
// 2
constructor(name, size) {
super(name);
this.size = size;
}
// 3
constructor(size) {
super(name);
this.size = size;
}
// 4
constructor(name, size) {
this.name = name;
this.size = size;
}};
复制代码- A: 1
- B: 2
- C: 3
- D: 4
答案: B
在子类中,在调用super之前不能访问到this关键字。 如果这样做,它将抛出一个ReferenceError:1和4将引发一个引用错误。
使用super关键字,需要用给定的参数来调用父类的构造函数。 父类的构造函数接收name参数,因此我们需要将name传递给super。
Labrador类接收两个参数,name参数是由于它继承了Dog,size作为Labrador类的额外属性,它们都需要传递给Labrador的构造函数,因此使用构造函数2正确完成。67. 输出什么?
// index.js
console.log(‘running index.js’);
import { sum } from ‘./sum.js’;
console.log(sum(1, 2));// sum.js
console.log(‘running sum.js’);
export const sum = (a, b) => a + b;
复制代码- A: running index.js, running sum.js, 3
- B: running sum.js, running index.js, 3
- C: running sum.js, 3, running index.js
- D: running index.js, undefined, running sum.js
答案: B
import命令是编译阶段执行的,在代码运行之前。因此这意味着被导入的模块会先运行,而导入模块的文件会后执行。
这是CommonJS中require()和import之间的区别。使用require(),您可以在运行代码时根据需要加载依赖项。 如果我们使用require而不是import,running index.js,running sum.js,3会被依次打印。68. 输出什么?
console.log(Number(2) === Number(2))
console.log(Boolean(false) === Boolean(false))
console.log(Symbol(‘foo’) === Symbol(‘foo’))
复制代码- A: true, true, false
- B: false, true, false
- C: true, false, true
- D: true, true, true
答案: A
每个Symbol都是完全唯一的。传递给Symbol的参数只是给Symbol的一个描述。 Symbol的值不依赖于传递的参数。 当我们测试相等时,我们创建了两个全新的符号:第一个Symbol(’foo’),第二个Symbol(’foo’), 这两个值是唯一的,彼此不相等,因此返回false。
69. 输出什么?
const name = “Lydia Hallie”
console.log(name.padStart(13))
console.log(name.padStart(2))
复制代码- A: “Lydia Hallie”, “Lydia Hallie”
- B: “ Lydia Hallie”, “ Lydia Hallie” (“[13x whitespace]Lydia Hallie”, “[2x whitespace]Lydia Hallie”)
- C: “ Lydia Hallie”, “Lydia Hallie” (“[1x whitespace]Lydia Hallie”, “Lydia Hallie”)
- D: “Lydia Hallie”, “Lyd”
答案: C
使用padStart方法,我们可以在字符串的开头添加填充。传递给此方法的参数是字符串的总长度(包含填充)。字符串Lydia Hallie的长度为12, 因此name.padStart(13)在字符串的开头只会插入1(13 - 12 = 1)个空格。
如果传递给padStart方法的参数小于字符串的长度,则不会添加填充。70. 输出什么?
console.log(“🥑” + “💻”);
复制代码- A: “🥑💻”
- B: 257548
- C: A string containing their code points
- D: Error
答案: A
使用+运算符,您可以连接字符串。 上述情况,我们将字符串“🥑”与字符串”💻“连接起来,产生”🥑💻“。
71. 如何能打印出console.log语句后注释掉的值?
function* startGame() {
const answer = yield “Do you love JavaScript?”;
if (answer !== “Yes”) {
return “Oh wow… Guess we’re gone here”;
}
return “JavaScript loves you back ❤️”;
}const game = startGame();
console.log(/ 1 /); // Do you love JavaScript?
console.log(/ 2 /); // JavaScript loves you back ❤️
复制代码- A: game.next(“Yes”).value and game.next().value
- B: game.next.value(“Yes”) and game.next.value()
- C: game.next().value and game.next(“Yes”).value
- D: game.next.value() and game.next.value(“Yes”)
答案: C
generator函数在遇到yield关键字时会“暂停”其执行。 首先,我们需要让函数产生字符串Do you love JavaScript?,这可以通过调用game.next().value来完成。上述函数的第一行就有一个yield关键字,那么运行立即停止了,yield表达式本身没有返回值,或者说总是返回undefined, 这意味着此时变量 answer 为undefined
next方法可以带一个参数,该参数会被当作上一个 yield 表达式的返回值。当我们调用game.next(“Yes”).value时,先前的 yield 的返回值将被替换为传递给next()函数的参数”Yes”。此时变量 answer 被赋值为 “Yes”,if语句返回false,所以JavaScript loves you back ❤️被打印。72. 输出什么?
console.log(String.raw
Hello\nworld);
复制代码- A: Hello world!
- B: Hello
world - C: Hello\nworld
- D: Hello\n
world
答案: C
String.raw函数是用来获取一个模板字符串的原始字符串的,它返回一个字符串,其中忽略了转义符(\n,\v,\t等)。但反斜杠可能造成问题,因为你可能会遇到下面这种类似情况:
const path =C:\Documents\Projects\table.html
String.raw${path}
复制代码
这将导致:
“C:DocumentsProjects able.html”
直接使用String.raw
String.rawC:\Documents\Projects\table.html
复制代码
它会忽略转义字符并打印:C:\Documents\Projects\table.html
上述情况,字符串是Hello\nworld被打印出。73. 输出什么?
async function getData() {
return await Promise.resolve(“I made it!”);
}const data = getData();
console.log(data);
复制代码- A: “I made it!”
- B: Promise {
: “I made it!”} - C: Promise {
} - D: undefined
答案: C
异步函数始终返回一个promise。await仍然需要等待promise的解决:当我们调用getData()并将其赋值给data,此时data为getData方法返回的一个挂起的promise,该promise并没有解决。
如果我们想要访问已解决的值”I made it!”,可以在data上使用.then()方法:
data.then(res => console.log(res))
这样将打印 “I made it!”74. 输出什么?
function addToList(item, list) {
return list.push(item);
}const result = addToList(“apple”, [“banana”]);
console.log(result);
复制代码- A: [‘apple’, ‘banana’]
- B: 2
- C: true
- D: undefined
答案: B
push()方法返回新数组的长度。一开始,数组包含一个元素(字符串”banana”),长度为1。 在数组中添加字符串”apple”后,长度变为2,并将从addToList函数返回。
push方法修改原始数组,如果你想从函数返回数组而不是数组长度,那么应该在push item之后返回list。75. 输出什么?
const box = { x: 10, y: 20 };
Object.freeze(box);
const shape = box;
shape.x = 100;
console.log(shape)
复制代码- A: { x: 100, y: 20 }
- B: { x: 10, y: 20 }
- C: { x: 100 }
- D: ReferenceError
答案: B
Object.freeze使得无法添加、删除或修改对象的属性(除非属性的值是另一个对象)。
当我们创建变量shape并将其设置为等于冻结对象box时,shape指向的也是冻结对象。你可以使用Object.isFrozen检查一个对象是否被冻结,上述情况,Object.isFrozen(shape)将返回true。
由于shape被冻结,并且x的值不是对象,所以我们不能修改属性x。 x仍然等于10,{x:10,y:20}被打印。
注意,上述例子我们对属性x进行修改,可能会导致抛出TypeError异常(最常见但不仅限于严格模式下时)。76. 输出什么?
const { name: myName } = { name: “Lydia” };
console.log(name);
复制代码- A: “Lydia”
- B: “myName”
- C: undefined
- D: ReferenceError
答案: D
当我们从右侧的对象解构属性name时,我们将其值Lydia分配给名为myName的变量。
使用{name:myName},我们是在告诉JavaScript我们要创建一个名为myName的新变量,并且其值是右侧对象的name属性的值。
当我们尝试打印name,一个未定义的变量时,就会引发ReferenceError。77. 以下是个纯函数么?
function sum(a, b) {
return a + b;
}
复制代码- A: Yes
- B: No
答案: A
纯函数一种若输入参数相同,则永远会得到相同输出的函数。
sum函数总是返回相同的结果。 如果我们传递1和2,它将总是返回3而没有副作用。 如果我们传递5和10,它将总是返回15,依此类推,这是纯函数的定义。78. 输出什么?
const add = () => {
const cache = {};
return num => {
if (num in cache) {
returnFrom cache! ${cache[num]};
} else {
const result = num + 10;
cache[num] = result;
returnCalculated! ${result};
}
};
};const addFunction = add();
console.log(addFunction(10));
console.log(addFunction(10));
console.log(addFunction(5 * 2));
复制代码- A: Calculated! 20 Calculated! 20 Calculated! 20
- B: Calculated! 20 From cache! 20 Calculated! 20
- C: Calculated! 20 From cache! 20 From cache! 20
- D: Calculated! 20 From cache! 20 Error
答案: C
add函数是一个记忆函数。 通过记忆化,我们可以缓存函数的结果,以加快其执行速度。上述情况,我们创建一个cache对象,用于存储先前返回过的值。
如果我们使用相同的参数多次调用addFunction函数,它首先检查缓存中是否已有该值,如果有,则返回缓存值,这将节省执行时间。如果没有,那么它将计算该值,并存储在缓存中。
我们用相同的值三次调用了addFunction函数:
在第一次调用,num等于10时函数的值尚未缓存,if语句num in cache返回false,else块的代码被执行:Calculated! 20,并且其结果被添加到缓存对象,cache现在看起来像{10:20}。
第二次,cache对象包含10的返回值。 if语句 num in cache 返回true,From cache! 20被打印。
第三次,我们将5 * 2(值为10)传递给函数。 cache对象包含10的返回值。 if语句 num in cache 返回true,From cache! 20被打印。79. 输出什么?
const myLifeSummedUp = [“☕”, “💻”, “🍷”, “🍫”]
for (let item in myLifeSummedUp) {
console.log(item)
}for (let item of myLifeSummedUp) {
console.log(item)
}
复制代码- A: 0 1 2 3 and “☕” “💻” “🍷” “🍫”
- B: “☕” “💻” “🍷” “🍫” and “☕” “💻” “🍷” “🍫”
- C: “☕” “💻” “🍷” “🍫” and 0 1 2 3
- D: 0 1 2 3 and {0: “☕”, 1: “💻”, 2: “🍷”, 3: “🍫”}
答案: A
通过for-in循环,我们可以遍历一个对象自有的、继承的、可枚举的、非Symbol的属性。 在数组中,可枚举属性是数组元素的“键”, 即它们的索引。 类似于下面这个对象:
{0: “☕”, 1: “💻”, 2: “🍷”, 3: “🍫”}
其中键则是可枚举属性,因此 0,1,2,3被记录。
通过for-of循环,我们可以迭代可迭代对象(包括 Array,Map,Set,String,arguments等)。当我们迭代数组时,在每次迭代中,不同属性的值将被分配给变量item, 因此“☕”,“💻”,“🍷”,“🍫”被打印。80. 输出什么?
const list = [1 + 2, 1 * 2, 1 / 2]
console.log(list)
复制代码- A: [“1 + 2”, “1 * 2”, “1 / 2”]
- B: [“12”, 2, 0.5]
- C: [3, 2, 0.5]
- D: [1, 1, 1]
答案: C
数组元素可以包含任何值。 数字,字符串,布尔值,对象,数组,null,undeifned, 以及其他表达式,如日期,函数和计算。
元素将等于返回的值。 1 + 2返回3,1 * 2返回’2,’1 / 2返回0.5。81. 输出什么?
function sayHi(name) {
returnHi there, ${name}
}console.log(sayHi())
复制代码- A: Hi there,
- B: Hi there, undefined
- C: Hi there, null
- D: ReferenceError
答案: B
默认情况下,如果不给函数传参,参数的值将为undefined。 上述情况,我们没有给参数name传值。 name等于undefined,并被打印。
在ES6中,我们可以使用默认参数覆盖此默认的undefined值。 例如:
function sayHi(name =“Lydia”){…}
在这种情况下,如果我们没有传递值或者如果我们传递undefined,name总是等于字符串Lydia82. 输出什么?
var status = “😎”
setTimeout(() => {
const status = “😍”const data = {
status: “🥑”,
getStatus() {
return this.status
}
}console.log(data.getStatus())
console.log(data.getStatus.call(this))
}, 0)
复制代码- A: “🥑” and “😍”
- B: “🥑” and “😎”
- C: “😍” and “😎”
- D: “😎” and “😎”
答案: B
this关键字的指向取决于使用它的位置。 在函数中,比如getStatus,this指向的是调用它的对象,上述例子中data对象调用了getStatus,因此this指向的就是data对象。 当我们打印this.status时,data对象的status属性被打印,即”🥑”。
使用call方法,可以更改this指向的对象。data.getStatus.call(this)是将this的指向由data对象更改为全局对象。在全局对象上,有一个名为status的变量,其值为”😎“。 因此打印this.status时,会打印“😎”。83. 输出什么?
const person = {
name: “Lydia”,
age: 21
}let city = person.city
city = “Amsterdam”console.log(person)
复制代码- A: { name: “Lydia”, age: 21 }
- B: { name: “Lydia”, age: 21, city: “Amsterdam” }
- C: { name: “Lydia”, age: 21, city: undefined }
- D: “Amsterdam”
答案: A
我们将变量city设置为等于person对象上名为city的属性的值。 这个对象上没有名为city的属性,因此变量city的值为undefined。
请注意,我们没有引用person对象本身,只是将变量city设置为等于person对象上city属性的当前值。
然后,我们将city设置为等于字符串“Amsterdam”。 这不会更改person对象:没有对该对象的引用。
因此打印person对象时,会返回未修改的对象。84. 输出什么?
function checkAge(age) {
if (age < 18) {
const message = “Sorry, you’re too young.”
} else {
const message = “Yay! You’re old enough!”
}return message
}console.log(checkAge(21))
复制代码- A: “Sorry, you’re too young.”
- B: “Yay! You’re old enough!”
- C: ReferenceError
- D: undefined
答案: C
const和let声明的变量是具有块级作用域的,块是大括号({})之间的任何东西, 即上述情况if / else语句的花括号。 由于块级作用域,我们无法在声明的块之外引用变量,因此抛出ReferenceError。
85. 什么样的信息将被打印?
fetch(‘https://www.website.com/api/user/1‘)
.then(res => res.json())
.then(res => console.log(res))
复制代码- A: fetch方法的结果
- B: 第二次调用fetch方法的结果
- C: 前一个.then()中回调方法返回的结果
- D: 总是undefined
答案: C
第二个.then中res的值等于前一个.then中的回调函数返回的值。 你可以像这样继续链接.then,将值传递给下一个处理程序。
86. 哪个选项是将hasName设置为true的方法,前提是不能将true作为参数传递?
function getName(name) {
const hasName = //
}
复制代码- A: !!name
- B: name
- C: new Boolean(name)
- D: name.length
答案: A
使用逻辑非运算符!,将返回一个布尔值,使用!! name,我们可以确定name的值是真的还是假的。 如果name是真实的,那么!name返回false。 !false返回true。
通过将hasName设置为name,可以将hasName设置为等于传递给getName函数的值,而不是布尔值true。
new Boolean(true)返回一个对象包装器,而不是布尔值本身。
name.length返回传递的参数的长度,而不是布尔值true。87. 输出什么?
console.log(“I want pizza”[0])
复制代码- A: “””
- B: “I”
- C: SyntaxError
- D: undefined
答案: B
可以使用方括号表示法获取字符串中特定索引的字符,字符串中的第一个字符具有索引0,依此类推。 在这种情况下,我们想要得到索引为0的元素,字符’I’被记录。
请注意,IE7及更低版本不支持此方法。 在这种情况下,应该使用.charAt()88. 输出什么?
function sum(num1, num2 = num1) {
console.log(num1 + num2)
}sum(10)
复制代码- A: NaN
- B: 20
- C: ReferenceError
- D: undefined
答案: B
您可以将默认参数的值设置为函数的另一个参数,只要另一个参数定义在其之前即可。 我们将值10传递给sum函数。 如果sum函数只接收1个参数,则意味着没有传递num2的值,这种情况下,num1的值等于传递的值10。 num2的默认值是num1的值,即10。 num1 + num2返回20。
如果您尝试将默认参数的值设置为后面定义的参数,则可能导致参数的值尚未初始化,从而引发错误。比如:
function test(m = n, n = 2) {
console.log(m, n)
}
test() // Uncaught ReferenceError: Cannot access ‘n’ before initialization
test(3) // 3 2
test(3, 4) // 3 4
复制代码89. 输出什么?
// module.js
export default () => “Hello world”
export const name = “Lydia”// index.js
import * as data from “./module”console.log(data)
复制代码- A: { default: function default(), name: “Lydia” }
- B: { default: function default() }
- C: { default: “Hello world”, name: “Lydia” }
- D: Global object of module.js
答案: A
使用import * as name语法,我们将module.js文件中所有export导入到index.js文件中,并且创建了一个名为data的新对象。 在module.js文件中,有两个导出:默认导出和命名导出。 默认导出是一个返回字符串“Hello World”的函数,命名导出是一个名为name的变量,其值为字符串“Lydia”。
data对象具有默认导出的default属性,其他属性具有指定exports的名称及其对应的值。90. 输出什么?
class Person {
constructor(name) {
this.name = name
}
}const member = new Person(“John”)
console.log(typeof member)
复制代码- A: “class”
- B: “function”
- C: “object”
- D: “string”
答案: C
类是构造函数的语法糖,如果用构造函数的方式来重写Person类则将是:
function Person() {
this.name = name
}
复制代码
通过new来调用构造函数,将会生成构造函数Person的实例,对实例执行typeof关键字将返回”object”,上述情况打印出”object”。91. 输出什么?
let newList = [1, 2, 3].push(4)
console.log(newList.push(5))
复制代码- A: [1, 2, 3, 4, 5]
- B: [1, 2, 3, 5]
- C: [1, 2, 3, 4]
- D: Error
答案: D
.push方法返回数组的长度,而不是数组本身! 通过将newList设置为[1,2,3].push(4),实际上newList等于数组的新长度:4。
然后,尝试在newList上使用.push方法。 由于newList是数值4,抛出TypeError。92. 输出什么?
function giveLydiaPizza() {
return “Here is pizza!”
}const giveLydiaChocolate = () => “Here’s chocolate… now go hit the gym already.”
console.log(giveLydiaPizza.prototype)
console.log(giveLydiaChocolate.prototype)
复制代码- A: { constructor: …} { constructor: …}
- B: {} { constructor: …}
- C: { constructor: …} {}
- D: { constructor: …} undefined
答案: D
常规函数,例如giveLydiaPizza函数,有一个prototype属性,它是一个带有constructor属性的对象(原型对象)。 然而,箭头函数,例如giveLydiaChocolate函数,没有这个prototype属性。 尝试使用giveLydiaChocolate.prototype访问prototype属性时会返回undefined。
93. 输出什么?
const person = {
name: “Lydia”,
age: 21
}for (const [x, y] of Object.entries(person)) {
console.log(x, y)
}
复制代码- A: name Lydia and age 21
- B: [“name”, “Lydia”] and [“age”, 21]
- C: [“name”, “age”] and undefined
- D: Error
答案: A
Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,上述情况返回一个二维数组,数组每个元素是一个包含键和值的数组:
[[‘name’,’Lydia’],[‘age’,21]]
使用for-of循环,我们可以迭代数组中的每个元素,上述情况是子数组。 我们可以使用const [x,y]在for-of循环中解构子数组。 x等于子数组中的第一个元素,y等于子数组中的第二个元素。
第一个子阵列是[“name”,“Lydia”],其中x等于name,而y等于Lydia。 第二个子阵列是[“age”,21],其中x等于age,而y等于21。94. 输出什么?
function getItems(fruitList, …args, favoriteFruit) {
return […fruitList, …args, favoriteFruit]
}getItems([“banana”, “apple”], “pear”, “orange”)
复制代码- A: [“banana”, “apple”, “pear”, “orange”]
- B: [[“banana”, “apple”], “pear”, “orange”]
- C: [“banana”, “apple”, [“pear”], “orange”]
- D: SyntaxError
答案: D
… args是剩余参数,剩余参数的值是一个包含所有剩余参数的数组,并且只能作为最后一个参数。上述示例中,剩余参数是第二个参数,这是不可能的,并会抛出语法错误。
function getItems(fruitList, favoriteFruit, …args) {
return […fruitList, …args, favoriteFruit]
}getItems([“banana”, “apple”], “pear”, “orange”)
复制代码
上述例子是有效的,将会返回数组:[ ‘banana’, ‘apple’, ‘orange’, ‘pear’ ]95. 输出什么?
function nums(a, b) {
if
(a > b)
console.log(‘a is bigger’)
else
console.log(‘b is bigger’)
return
a + b
}console.log(nums(4, 2))
console.log(nums(1, 2))
复制代码- A: a is bigger, 6 and b is bigger, 3
- B: a is bigger, undefined and b is bigger, undefined
- C: undefined and undefined
- D: SyntaxError
答案: B
在JavaScript中,我们不必显式地编写分号(;),但是JavaScript引擎仍然在语句之后自动添加分号。这称为自动分号插入。例如,一个语句可以是变量,或者像throw、return、break这样的关键字。
在这里,我们在新的一行上写了一个return语句和另一个值a + b。然而,由于它是一个新行,引擎并不知道它实际上是我们想要返回的值。相反,它会在return后面自动添加分号。你可以这样看:
return;
a + b
复制代码
这意味着永远不会到达a + b,因为函数在return关键字之后停止运行。如果没有返回值,就像这里,函数返回undefined。注意,在if/else语句之后没有自动插入!96. 输出什么?
class Person {
constructor() {
this.name = “Lydia”
}
}Person = class AnotherPerson {
constructor() {
this.name = “Sarah”
}
}const member = new Person()
console.log(member.name)
复制代码- A: “Lydia”
- B: “Sarah”
- C: Error: cannot redeclare Person
- D: SyntaxError
答案: B
我们可以将类设置为等于其他类/函数构造函数。 在这种情况下,我们将Person设置为AnotherPerson。 这个构造函数的名字是Sarah,所以新的Person实例member上的name属性是Sarah。
97. 输出什么?
const info = {
[Symbol(‘a’)]: ‘b’
}console.log(info)
console.log(Object.keys(info))
复制代码- A: {Symbol(‘a’): ‘b’} and [“{Symbol(‘a’)”]
- B: {} and []
- C: { a: “b” } and [“a”]
- D: {Symbol(‘a’): ‘b’} and []
答案: D
Symbol类型是不可枚举的。Object.keys方法返回对象上的所有可枚举的键属性。Symbol类型是不可见的,并返回一个空数组。 记录整个对象时,所有属性都是可见的,甚至是不可枚举的属性。
这是Symbol的众多特性之一:除了表示完全唯一的值(防止对象意外名称冲突,例如当使用2个想要向同一对象添加属性的库时),您还可以隐藏这种方式对象的属性(尽管不完全。你仍然可以使用Object.getOwnPropertySymbols()方法访问 Symbol。98. 输出什么?
const getList = ([x, …y]) => [x, y]
const getUser = user => { name: user.name, age: user.age }const list = [1, 2, 3, 4]
const user = { name: “Lydia”, age: 21 }console.log(getList(list))
console.log(getUser(user))
复制代码- A: [1, [2, 3, 4]] and undefined
- B: [1, [2, 3, 4]] and { name: “Lydia”, age: 21 }
- C: [1, 2, 3, 4] and { name: “Lydia”, age: 21 }
- D: Error and { name: “Lydia”, age: 21 }
答案: A
getList函数接收一个数组作为其参数。 在getList函数的括号之间,我们立即解构这个数组。 您可以将其视为:
[x, …y] = [1, 2, 3, 4]
使用剩余的参数… y,我们将所有剩余参数放在一个数组中。 在这种情况下,其余的参数是2,3和4。 y的值是一个数组,包含所有其余参数。 在这种情况下,x的值等于1,所以当我们打印[x,y]时,会打印[1,[2,3,4]]。
getUser函数接收一个对象。对于箭头函数,如果只返回一个值,我们不必编写花括号。但是,如果您想从一个箭头函数返回一个对象,您必须在圆括号之间编写它,否则不会返回任何值!下面的函数将返回一个对象:
const getUser = user => ({ name: user.name, age: user.age })
由于在这种情况下不返回任何值,因此该函数返回undefined。99. 输出什么?
const name = “Lydia”
console.log(name())
复制代码- A: SyntaxError
- B: ReferenceError
- C: TypeError
- D: undefined
答案: C
变量name保存字符串的值,该字符串不是函数,因此无法调用。
当值不是预期类型时,会抛出TypeErrors。 JavaScript期望name是一个函数,因为我们试图调用它。 但它是一个字符串,因此抛出TypeError:name is not a function
当你编写了一些非有效的JavaScript时,会抛出语法错误,例如当你把return这个词写成retrun时。 当JavaScript无法找到您尝试访问的值的引用时,抛出ReferenceErrors。100. 输出什么?
// 🎉✨ This is my 100th question! ✨🎉
const output =
${[] && 'Im'}possible!<br />You should${'' &&n’t} see a therapist after so much JavaScript lol
复制代码- A: possible! You should see a therapist after so much JavaScript lol
- B: Impossible! You should see a therapist after so much JavaScript lol
- C: possible! You shouldn’t see a therapist after so much JavaScript lol
- D: Impossible! You shouldn’t see a therapist after so much JavaScript lol
答案: B
[]是一个真值。 使用&&运算符,如果左侧值是真值,则返回右侧值。 在这种情况下,左侧值[]是一个真值,所以返回Im。
“”是一个假值。 如果左侧值是假的,则不返回任何内容。 n’t不会被退回。
作者:将源兵魂
链接:https://juejin.im/post/5e1830c05188254c461313dc
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。101.输出什么?
const one = (false || {} || null)
const two = (null || false || “”)
const three = ([] || 0 || true)console.log(one, two, three)
复制代码- A: false null []
- B: null “” true
- C: {} “” []
- D: null null true
答案: C
使用||运算符,我们可以返回第一个真值。 如果所有值都是假值,则返回最后一个值。
(false || {} || null):空对象{}是一个真值。 这是第一个(也是唯一的)真值,它将被返回。one等于{}。
(null || false ||“”):所有值都是假值。 这意味着返回传递的值””。 two等于””。
([] || 0 ||“”):空数组[]是一个真值。 这是第一个返回的真值。 three等于[]。102. 依次输出什么?
const myPromise = () => Promise.resolve(‘I have resolved!’)
function firstFunction() {
myPromise().then(res => console.log(res))
console.log(‘second’)
}async function secondFunction() {
console.log(await myPromise())
console.log(‘second’)
}firstFunction()
secondFunction()
复制代码- A: I have resolved!, second and I have resolved!, second
- B: second, I have resolved! and second, I have resolved!
- C: I have resolved!, second and second, I have resolved!
- D: second, I have resolved! and I have resolved!, second
答案: D
有了promise,我们通常会说:当我想要调用某个方法,但是由于它可能需要一段时间,因此暂时将它放在一边。只有当某个值被resolved/rejected,并且执行栈为空时才使用这个值。
我们可以在async函数中通过.then和await关键字获得该值。 尽管我们可以通过.then和await获得promise的价值,但是它们的工作方式有所不同。
在 firstFunction中,当运行到myPromise方法时我们将其放在一边,即promise进入微任务队列,其他后面的代码(console.log(‘second’))照常运行,因此second被打印出,firstFunction方法到此执行完毕,执行栈中宏任务队列被清空,此时开始执行微任务队列中的任务,I have resolved被打印出。
在secondFunction方法中,我们通过await关键字,暂停了后面代码的执行,直到异步函数的值被解析才开始后面代码的执行。这意味着,它会等着直到 myPromise 以值I have resolved被解决之后,下一行second才开始执行。103. 输出什么?
const set = new Set()
set.add(1)
set.add(“Lydia”)
set.add({ name: “Lydia” })for (let item of set) {
console.log(item + 2)
}
复制代码- A: 3, NaN, NaN
- B: 3, 7, NaN
- C: 3, Lydia2, [Object object]2
- D: “12”, Lydia2, [Object object]2
答案: C
“+”运算符不仅用于数值相加,还可以使用它来连接字符串。 每当JavaScript引擎发现一个或多个值不是数字时,就会将数字强制转化为字符串。
第一个是数字1, 1 + 2返回数字3。
但是,第二个是字符串Lydia。 Lydia是字符串,2是数字:2被强制转换为字符串。 Lydia和2被连接起来,产生字符Lydia2。
{name:“Lydia”}是一个对象。 数字和对象都不是字符串,因此将二者都字符串化。 每当我们对常规对象进行字符串化时,它就会变成“[Object object]”。104. 结果是什么?
Promise.resolve(5)
复制代码- A: 5
- B: Promise {
: 5} - C: Promise {
: 5} - D: Error
答案: C
我们可以将我们想要的任何类型的值传递Promise.resolve,无论是否promise。 该方法本身返回带有已解析值的Promise。 如果您传递常规函数,它将是具有常规值的已解决promise。 如果你通过了promise,它将是一个已经resolved的且带有传的值的promise。
上述情况,我们传了数字5,因此返回一个resolved状态的promise,resolve值为5105. 输出什么?
function compareMembers(person1, person2 = person) {
if (person1 !== person2) {
console.log(“Not the same!”)
} else {
console.log(“They are the same!”)
}
}const person = { name: “Lydia” }
compareMembers(person)
复制代码- A: Not the same!
- B: They are the same!
- C: ReferenceError
- D: SyntaxError
答案: B
对象通过引用传递。 当我们检查对象的严格相等性(===)时,我们正在比较它们的引用。
我们将person2的默认值设置为person对象,并将person对象作为person1的值传递。
这意味着两个值都引用内存中的同一位置,因此它们是相等的。
运行“ else”语句中的代码块,并记录They are the same! 。106. 输出什么?
const colorConfig = {
red: true,
blue: false,
green: true,
black: true,
yellow: false,
}const colors = [“pink”, “red”, “blue”]
console.log(colorConfig.colors[1])
复制代码- A: true
- B: false
- C: undefined
- D: TypeError
答案: D
在JavaScript中,我们有两种访问对象属性的方法:括号表示法或点表示法。 在此示例中,我们使用点表示法(colorConfig.colors)代替括号表示法(colorConfig [“ colors”])。
使用点表示法,JavaScript会尝试使用该确切名称在对象上查找属性。 在此示例中,JavaScript尝试在colorconfig对象上找到名为colors的属性。 没有名为“colors”的属性,因此返回“undefined”。 然后,我们尝试使用[1]访问第一个元素的值。 我们无法对未定义的值执行此操作,因此会抛出Cannot read property ‘1’ of undefined。
JavaScript解释(或取消装箱)语句。 当我们使用方括号表示法时,它会看到第一个左方括号[并一直进行下去,直到找到右方括号]。 只有这样,它才会评估该语句。 如果我们使用了colorConfig [colors [1]],它将返回colorConfig对象上red属性的值。107. 输出什么?
console.log(‘❤️’ === ‘❤️’)
复制代码- A: true
- B: false
答案: A
在内部,表情符号是unicode。 心表情符号的unicode是U+2764 U+FE0F。 对于相同的表情符号,它们总是相同的,因此我们正在将两个相等的字符串相互比较,这将返回true。
108. 哪些方法修改了原数组?
const emojis = [‘✨’, ‘🥑’, ‘😍’]
emojis.map(x => x + ‘✨’)
emojis.filter(x => x !== ‘🥑’)
emojis.find(x => x !== ‘🥑’)
emojis.reduce((acc, cur) => acc + ‘✨’)
emojis.slice(1, 2, ‘✨’)
emojis.splice(1, 2, ‘✨’)
复制代码- A: All of them
- B: map reduce slice splice
- C: map slice splice
- D: splice
答案: D
使用splice方法,我们通过删除,替换或添加元素来修改原始数组。 上述情况,我们从索引1中删除了2个元素(删除了’🥑’和’😍’),并添加了✨emoji表情。
map,filter和slice返回一个新数组,find返回一个元素,而reduce返回一个减小的值。109. 输出什么?
const food = [‘🍕’, ‘🍫’, ‘🥑’, ‘🍔’]
const info = { favoriteFood: food[0] }info.favoriteFood = ‘🍝’
console.log(food)
复制代码- A: [‘🍕’, ‘🍫’, ‘🥑’, ‘🍔’]
- B: [‘🍝’, ‘🍫’, ‘🥑’, ‘🍔’]
- C: [‘🍝’, ‘🍕’, ‘🍫’, ‘🥑’, ‘🍔’]
- D: ReferenceError
答案: A
我们将info对象上的favoriteFood属性的值设置为披萨表情符号“🍕”的字符串。字符串是原始数据类型。在JavaScript中,原始数据类型通过值起作用
在这种情况下,我们将info对象上的favoriteFood属性的值设置为等于food数组中的第一个元素的值,字符串为披萨表情符号(’🍕’ )。字符串是原始数据类型,并且通过值进行交互,我们更改info对象上favoriteFood属性的值。 food数组没有改变,因为favoriteFood的值只是该数组中第一个元素的值的复制,并且与该元素上的元素没有相同的内存引用食物[0]。当我们记录食物时,它仍然是原始数组[‘🍕’,’🍫’,’🥑’,’🍔’]。110. 这个函数干了什么?
JSON.parse()
复制代码- A: Parses JSON to a JavaScript value
- B: Parses a JavaScript object to JSON
- C: Parses any JavaScript value to JSON
- D: Parses JSON to a JavaScript object only
答案: A
使用JSON.parse()方法,我们可以将JSON字符串解析为JavaScript值。
// 将数字字符串化为有效的JSON,然后将JSON字符串解析为JavaScript值:
const jsonNumber = JSON.stringify(4) // ‘4’
JSON.parse(jsonNumber) // 4// 将数组值字符串化为有效的JSON,然后将JSON字符串解析为JavaScript值:
const jsonArray = JSON.stringify([1, 2, 3]) // ‘[1, 2, 3]’
JSON.parse(jsonArray) // [1, 2, 3]// 将对象字符串化为有效的JSON,然后将JSON字符串解析为JavaScript值:
const jsonArray = JSON.stringify({ name: “Lydia” }) // ‘{“name”:”Lydia”}’
JSON.parse(jsonArray) // { name: ‘Lydia’ }
复制代码111. 输出什么?
let name = ‘Lydia’
function getName() {
console.log(name)
let name = ‘Sarah’
}getName()
复制代码- A: Lydia
- B: Sarah
- C: undefined
- D: ReferenceError
答案: D
每个函数都有其自己的执行上下文。 getName函数首先在其自身的上下文(范围)内查找,以查看其是否包含我们尝试访问的变量name。 上述情况,getName函数包含其自己的name变量:我们用let关键字和Sarah的值声明变量name。
带有let关键字(和const)的变量被提升,但是与var不同,它不会被初始化。 在我们声明(初始化)它们之前,无法访问它们。 这称为“暂时性死区”。 当我们尝试在声明变量之前访问变量时,JavaScript会抛出ReferenceError: Cannot access ‘name’ before initialization。
如果我们不在getName函数中声明name变量,则javascript引擎会查看原型练。会找到其外部作用域有一个名为name的变量,其值为Lydia。 在这种情况下,它将打印Lydia:
let name = ‘Lydia’function getName() {
console.log(name)
}getName() // Lydia
复制代码112. 输出什么?
function generatorOne() {
yield [‘a’, ‘b’, ‘c’];
}
function generatorTwo() {
yield* [‘a’, ‘b’, ‘c’];
}
const one = generatorOne()
const two = generatorTwo()
console.log(one.next().value)
console.log(two.next().value)
复制代码- A: a and a
- B: a and undefined
- C: [‘a’, ‘b’, ‘c’] and a
- D: a and [‘a’, ‘b’, ‘c’]
答案: C
通过 yield 关键字, 我们在 Generator 函数里执行yield表达式. 通过 yield 关键字, 我们可以在一个Generator 函数里面执行(yield表达式)另一个 Generator 函数, 或可遍历的对象 (如数组).
在函数 generatorOne 中, 我们通过 yield 关键字 yield 了一个完整的数组 [‘a’, ‘b’, ‘c’]。函数one通过next方法返回的对象的value 属性的值 (one.next().value) 等价于数组 [‘a’, ‘b’, ‘c’].
console.log(one.next().value) // [‘a’, ‘b’, ‘c’]
console.log(one.next().value) // undefined
复制代码
在函数 generatorTwo 中, 我们使用 yield 关键字。就相当于函数two第一个yield的值, 等价于在迭代器中第一个 yield 的值。数组[‘a’, ‘b’, ‘c’]就是这个迭代器. 第一个 yield 的值就是 a, 所以我们第一次调用 two.next().value时, 就返回a。
console.log(two.next().value) // ‘a’
console.log(two.next().value) // ‘b’
console.log(two.next().value) // ‘c’
console.log(two.next().value) // undefined
复制代码113. 输出什么?
console.log(
${(x => x)('I love')} to program)
复制代码- A: I love to program
- B: undefined to program
- C: ${(x => x)(‘I love’) to program
- D: TypeError
答案: A
带有模板字面量的表达式首先被执行。相当于字符串会包含表达式,这个立即执行函数 (x => x)(‘I love’) 返回的值. 我们向箭头函数 x => x 传递 ‘I love’ 作为参数。x 等价于返回的 ‘I love’。这就是结果 I love to program。
114. 将会发生什么?
let config = {
alert: setInterval(() => {
console.log(‘Alert!’)
}, 1000)
}
config = null
复制代码- A: setInterval 的回调不会被调用
- B: setInterval 的回调被调用一次
- C: setInterval 的回调仍然会被每秒钟调用
- D: 我们从没调用过 config.alert(), config 为 null
答案: C
一般情况下当我们将对象赋值为 null, 那些对象会被进行 垃圾回收(garbage collected) 因为已经没有对这些对象的引用了。然而,setInterval的参数是一个箭头函数(所以上下文绑定到对象 config 了),回调函数仍然保留着对 config的引用。只要存在引用,对象就不会被垃圾回收。因为没有被垃圾回收,setInterval 的回调每1000ms (1s)会被调用一次。
115. 哪一个方法会返回 ‘Hello world!’ ?
const myMap = new Map()
const myFunc = () => ‘greeting’
myMap.set(myFunc, ‘Hello world!’)
//1
myMap.get(‘greeting’)
//2
myMap.get(myFunc)
//3
myMap.get(() => ‘greeting’)
复制代码- A: 1
- B: 2
- C: 2 and 3
- D: All of them
答案: B
当通过 set 方法添加一个键值对,一个传递给 set方法的参数将会是键名,第二个参数将会是值。在这个case里,键名为 函数 () => ‘greeting’,值为’Hello world’。 myMap 现在就是 { () => ‘greeting’ => ‘Hello world!’ }。
1 是错的,因为键名不是 ‘greeting’ 而是 () => ‘greeting’。 3 是错的,因为我们给get 方法传递了一个新的函数。对象受 引用 影响。函数也是对象,因此两个函数严格上并不等价,尽管他们相同:他们有两个不同的内存引用地址。116. 输出什么?
const person = {
name: “Lydia”,
age: 21
}
const changeAge = (x = { …person }) => x.age += 1
const changeAgeAndName = (x = { …person }) => {
x.age += 1
x.name = “Sarah”
}
changeAge(person)
changeAgeAndName()
console.log(person)
复制代码- A: {name: “Sarah”, age: 22}
- B: {name: “Sarah”, age: 23}
- C: {name: “Lydia”, age: 22}
- D: {name: “Lydia”, age: 23}
答案: C
函数 changeAge 和函数 changeAgeAndName 有着不同的参数,定义一个 新 生成的对象 { …person }。这个对象有着所有 person 对象 中 k/v 值的副本。
首项, 我们调用 changeAge 函数并传递 person 对象作为它的参数。这个函数对 age 属性进行加一操作。person 现在是 { name: “Lydia”, age: 22 }。
然后,我们调用函数 changeAgeAndName ,然而我们没有传递参数。取而代之,x 的值等价 new 生成的对象: { …person }。因为它是一个新生成的对象,它并不会对对象 person 造成任何副作用。person 仍然等价于 { name: “Lydia”, age: 22 }。117. 下面那个选项将会返回 6?
function sumValues(x, y, z) {
return x + y + z;
}
复制代码- A: sumValues([…1, 2, 3])
- B: sumValues([…[1, 2, 3]])
- C: sumValues(…[1, 2, 3])
- D: sumValues([1, 2, 3])
答案: C
通过展开操作符 …,我们可以 暂开 单个可迭代的元素。函数 sumValues function 接收三个参数: x, y 和 z。…[1, 2, 3] 的执行结果为 1, 2, 3,将会传递给函数 sumValues。
118. 输出什么?
let num = 1;
const list = [“🥳”, “🤠”, “🥰”, “🤪”];
console.log(list[(num += 1)]);
复制代码- A: 🤠
- B: 🥰
- C: SyntaxError
- D: ReferenceError
答案: B
通过 += 操作符,我们对值 num 进行加 1 操作。 num 有初始值 1,因此 1 + 1 的执行结果为 2。数组 list 的第二项为 🥰,console.log(list[2]) 输出 🥰.
119. 输出什么?
const person = {
firstName: “Lydia”,
lastName: “Hallie”,
pet: {
name: “Mara”,
breed: “Dutch Tulip Hound”
},
getFullName() {
return${this.firstName} ${this.lastName};
}
};
console.log(person.pet?.name);
console.log(person.pet?.family?.name);
console.log(person.getFullName?.());
console.log(member.getLastName?.());
复制代码- A: undefined undefined undefined undefined
- B: Mara undefined Lydia Hallie undefined
- C: Mara null Lydia Hallie null
- D: null ReferenceError null ReferenceError
答案: B
通过 ES10 或 TS3.7+可选链操作符 ?.,我们不再需要显式检测更深层的嵌套值是否有效。如果我们尝试获取 undefined 或 null 的值 (nullish),表达将会短路并返回 undefined. person.pet?.name: person 有一个名为 pet 的属性: person.pet 不是 nullish。它有个名为 name 的属性,并返回字符串 Mara。 person.pet?.family?.name: person 有一个名为 pet 的属性: person.pet 不是 nullish. pet 并没有 一个名为 family 的属性, person.pet.family 是 nullish。表达式返回 undefined。 person.getFullName?.(): person 有一个名为 getFullName 的属性: person.getFullName() 不是 nullish 并可以被调用,返回字符串 Lydia Hallie。 member.getLastName?.(): member is not defined: member.getLastName() is nullish. The expression returns undefined.
120. 输出什么?
const groceries = [“banana”, “apple”, “peanuts”];
if (groceries.indexOf(“banana”)) {
console.log(“We have to buy bananas!”);
} else {
console.log(We don't have to buy bananas!);
}
复制代码- A: We have to buy bananas!
- B: We don’t have to buy bananas
- C: undefined
- D: 1
答案: B
我们传递了一个状态 groceries.indexOf(“banana”) 给if条件语句。groceries.indexOf(“banana”) 返回 0, 一个 falsy 的值。因为if条件语句的状态为 falsy,else 块区内的代码执行,并且 We don’t have to buy bananas! 被输出.
121. 输出什么?
const config = {
languages: [],
set language(lang) {
return this.languages.push(lang);
}
};
console.log(config.language);
复制代码- A: function language(lang) { this.languages.push(lang }
- B: 0
- C: []
- D: undefined
答案: D
方法 language 是一个 setter。Setters 并不保存一个实际值,它们的使命在于 修改 属性。当调用方法 setter, 返回 undefined。
122. 输出什么?
const name = “Lydia Hallie”;
console.log(!typeof name === “object”);
console.log(!typeof name === “string”);
复制代码- A: false true
- B: true false
- C: false false
- D: true true
答案: C
typeof name 返回 “string”。字符串 “string” 是一个 truthy 的值,因此 !typeof name 返回一个布尔值 false。 false === “object” 和 false === “string” 都返回 false。 (如果我们想检测一个值的类型,我们不应该用 !== 而不是 !typeof)
123. 输出什么?
const add = x => y => z => {
console.log(x, y, z);
return x + y + z;
};
add(4)(5)(6);
复制代码- A: 4 5 6
- B: 6 5 4
- C: 4 function function
- D: undefined undefined 6
答案: A
函数 add 是一个返回 返回箭头函数的箭头函数 的箭头函数(still with me?)。第一个函数接收一个值为 4 的参数 x。我们调用第二个函数,它接收一个值为 5 的参数 y。然后我们调用第三个函数,它接收一个值为 6 的参数 z。当我们尝试在最后一个箭头函数中获取 x, y 和 z 的值,JS 引擎根据作用域链去找 x 和 y 的值。得到 4 5 6.
124. 输出什么?
async function* range(start, end) {
for (let i = start; i <= end; i++) {
yield Promise.resolve(i);
}
}
(async () => {
const gen = range(1, 3);
for await (const item of gen) {
console.log(item);
}
})();
复制代码- A: Promise {1} Promise {2} Promise {3}
- B: Promise {
} Promise { } Promise { } - C: 1 2 3
- D: undefined undefined undefined
答案: C
我们给 函数range 传递: Promise{1}, Promise{2}, Promise{3},Generator 函数 range 返回一个全是 async object promise 数组。我们将 async object 赋值给变量 gen,之后我们使用for await … of 进行循环遍历。我们将返回的 Promise 实例赋值给 item: 第一个返回 Promise{1}, 第二个返回 Promise{2},之后是 Promise{3}。因为我们正 awaiting item 的值,resolved 状态的 promsie,promise数组的resolved 值 以此为: 1,2,3.
125. 输出什么?
const myFunc = ({ x, y, z }) => {
console.log(x, y, z);
};
myFunc(1, 2, 3);
复制代码- A: 1 2 3
- B: {1: 1} {2: 2} {3: 3}
- C: { 1: undefined } undefined undefined
- D: undefined undefined undefined
答案: D
myFunc 期望接收一个包含 x, y 和 z 属性的对象作为它的参数。因为我们仅仅传递三个单独的数字值 (1, 2, 3) 而不是一个含有 x, y 和 z 属性的对象 ({x: 1, y: 2, z: 3}), x, y 和 z 有着各自的默认值 undefined.
126. 输出什么?
function getFine(speed, amount) {
const formattedSpeed = new Intl.NumberFormat({
‘en-US’,
{ style: ‘unit’, unit: ‘mile-per-hour’ }
}).format(speed)
const formattedAmount = new Intl.NumberFormat({
‘en-US’,
{ style: ‘currency’, currency: ‘USD’ }
}).format(amount)
returnThe driver drove ${formattedSpeed} and has to pay ${formattedAmount}
}
console.log(getFine(130, 300))
复制代码- A: The driver drove 130 and has to pay 300
- B: The driver drove 130 mph and has to pay $300.00
- C: The driver drove undefined and has to pay undefined
- D: The driver drove 130.00 and has to pay 300.00
答案: B
通过方法 Intl.NumberFormat,我们可以格式化任意区域的数字值。我们对数字值 130 进行 mile-per-hour 作为 unit 的 en-US 区域 格式化,结果为 130 mph。对数字值 300 进行 USD 作为 currentcy 的 en-US 区域格式化,结果为 $300.00.
127. 输出什么?
const spookyItems = [“👻”, “🎃”, “🕸”];
({ item: spookyItems[3] } = { item: “💀” });
console.log(spookyItems);
复制代码- A: [“👻”, “🎃”, “🕸”]
- B: [“👻”, “🎃”, “🕸”, “💀”]
- C: [“👻”, “🎃”, “🕸”, { item: “💀” }]
- D: [“👻”, “🎃”, “🕸”, “[object Object]”]
答案: B
通过解构对象们,我们可以从右手边的对象中拆出值,并且将拆出的值分配给左手边对象同名的属性。在这种情况下,我们将值 “💀” 分配给 spookyItems[3]。相当于我们正在篡改数组 spookyItems,我们给它添加了值 “💀”。当输出 spookyItems 时,结果为 [“👻”, “🎃”, “🕸”, “💀”]。
128. 输出什么?
const name = “Lydia Hallie”;
const age = 21;
console.log(Number.isNaN(name));
console.log(Number.isNaN(age));
console.log(isNaN(name));
console.log(isNaN(age));
复制代码- A: true false true false
- B: true false false false
- C: false false true false
- D: false true false true
答案: C
通过方法 Number.isNaN,你可以检测你传递的值是否为 数字值 并且是否等价于 NaN。name 不是一个数字值,因此 Number.isNaN(name) 返回 false。age 是一个数字值,但它不等价于 NaN,因此 Number.isNaN(age) 返回 false. 通过方法 isNaN, 你可以检测你传递的值是否一个 number。name 不是一个 number,因此 isNaN(name) 返回 true. age 是一个 number 因此 isNaN(age) 返回 false.
129. 输出什么?
const randomValue = 21;
function getInfo() {
console.log(typeof randomValue);
const randomValue = “Lydia Hallie”;
}
getInfo();
复制代码- A: “number”
- B: “string”
- C: undefined
- D: ReferenceError
答案: D
通过 const 关键字声明的变量在被初始化之前不可被引用:这被称之为 暂时性死去。在函数 getInfo 中, 变量 randomValue 声明在getInfo 的作用域的此法环境中。在想要对 typeof randomValue 进行log之前,变量 randomValue 仍未被初始化: 错误ReferenceError 被抛出! JS引擎并不会根据作用域链网上寻找该变量,因为我们已经在 getInfo 函数中声明了 randomValue 变量。
130. 输出什么?
const myPromise = Promise.resolve(“Woah some cool data”);
(async () => {
try {
console.log(await myPromise);
} catch {
throw new Error(Oops didn't work);
} finally {
console.log(“Oh finally!”);
}
})();
复制代码- A: Woah some cool data
- B: Oh finally!
- C: Woah some cool data Oh finally!
- D: Oops didn’t work Oh finally!
答案: C
在 try 块区,我们打印 myPromise 变量的 awaited 值: “Woah some cool data”。因为try 块区没有错误抛出,catch 块区的代码并不执行。finally 块区的代码 总是 执行,”Oh finally!” 被输出。
131. 输出什么?
const emojis = [“🥑”, [“✨”, “✨”, [“🍕”, “🍕”]]];
console.log(emojis.flat(1));
复制代码- A: [‘🥑’, [‘✨’, ‘✨’, [‘🍕’, ‘🍕’]]]
- B: [‘🥑’, ‘✨’, ‘✨’, [‘🍕’, ‘🍕’]]
- C: [‘🥑’, [‘✨’, ‘✨’, ‘🍕’, ‘🍕’]]
- D: [‘🥑’, ‘✨’, ‘✨’, ‘🍕’, ‘🍕’]
答案: B
通过方法 flat, 我们可以创建一个新的, 已被扁平化的数组。被扁平化的深度取决于我们传递的值。在这个case里,我们传递了值 1 (并不必要,这是默认值),相当于只有第一层的数组才会被连接。即这个 case 里的 [‘🥑’] and [‘✨’, ‘✨’, [‘🍕’, ‘🍕’]]。连接这两个数组得到结果 [‘🥑’, ‘✨’, ‘✨’, [‘🍕’, ‘🍕’]].
132. 输出什么?
class Counter {
constructor() {
this.count = 0;
}
increment() {
this.count++;
}
}
const counterOne = new Counter();
counterOne.increment();
counterOne.increment();
const counterTwo = counterOne;
counterTwo.increment();
console.log(counterOne.count);
复制代码- A: 0
- B: 1
- C: 2
- D: 3
答案: D
counterOne 是类 Counter 的一个实例。类 Counter 包含一个count 属性在它的构造函数里, 和一个 increment 方法。首先,我们通过 counterOne.increment() 调用方法 increment 两次。现在, counterOne.count 为 2. 然后,我们创建一个新的变量 counterTwo 并将 counterOne 的引用地址赋值给它。因为对象受引用地址的影响,我们刚刚创建了一个新的对象,其引用地址和 counterOne 的等价。因此它们指向同一块内存地址,任何对其的副作用都会影响 counterTwo。现在 counterTwo.count 为 2。 我们调用 counterTwo.increment() 将 count 的值设为 3。然后,我们打印 counterOne 里的count,结果为 3。
133. 输出什么?
const myPromise = Promise.resolve(Promise.resolve(“Promise!”));
function funcOne() {
myPromise.then(res => res).then(res => console.log(res));
setTimeout(() => console.log(“Timeout!”, 0));
console.log(“Last line!”);
}
async function funcTwo() {
const res = await myPromise;
console.log(await res);
setTimeout(() => console.log(“Timeout!”, 0));
console.log(“Last line!”);
}
funcOne();
funcTwo();
复制代码- A: Promise! Last line! Promise! Last line! Last line! Promise!
- B: Last line! Timeout! Promise! Last line! Timeout! Promise!
- C: Promise! Last line! Last line! Promise! Timeout! Timeout!
- D: Last line! Promise! Promise! Last line! Timeout! Timeout!
答案: D
首先,我们调用 funcOne。在函数 funcOne 的第一行,我们调用myPromise promise 异步操作。当JS引擎在忙于执行 promise,它继续执行函数 funcOne。下一行 异步操作 setTimeout,其回调函数被 Web API 调用。 (详情请参考我关于event loop的文章.) promise 和 timeout 都是异步操作,函数继续执行当JS引擎忙于执行promise 和 处理 setTimeout 的回调。相当于 Last line! 首先被输出, 因为它不是异步操作。执行完 funcOne 的最后一行,promise 状态转变为 resolved,Promise! 被打印。然而,因为我们调用了 funcTwo(), 调用栈不为空,setTimeout 的回调仍不能入栈。 我们现在处于 funcTwo,先 awaiting myPromise。通过 await 关键字, 我们暂停了函数的执行直到 promise 状态变为 resolved (或 rejected)。然后,我们输出 res 的 awaited 值(因为 promise 本身返回一个 promise)。 接着输出 Promise!。 下一行就是 异步操作 setTimeout,其回调函数被 Web API 调用。 我们执行到函数 funcTwo 的最后一行,输出 Last line!。现在,因为 funcTwo 出栈,调用栈为空。在事件队列中等待的回调函数(() => console.log(“Timeout!”) from funcOne, and () => console.log(“Timeout!”) from funcTwo)以此入栈。第一个回调输出 Timeout!,并出栈。然后,第二个回调输出 Timeout!,并出栈。得到结果 Last line! Promise! Promise! Last line! Timeout! Timeout!
134. 我们怎样才能在 index.js 中调用 sum.js? 中的 sum?
// sum.js
export default function sum(x) {
return x + x;
}
// index.js
import * as sum from “./sum”;
复制代码- A: sum(4)
- B: sum.sum(4)
- C: sum.default(4)
- D: 默认导出不用 * 来导入,只能具名导出
答案: C
使用符号 ,我们引入文件中的所有值,包括默认和具名。如果我们有以下文件:
// info.js
export const name = “Lydia”;
export const age = 21;
export default “I love JavaScript”;
// index.js
import as info from “./info”;
console.log(info);
复制代码
将会输出以下内容:
{
default: “I love JavaScript”,
name: “Lydia”,
age: 21
}
复制代码
以 sum 为例,相当于以下形式引入值 sum:
{ default: function sum(x) { return x + x } }
复制代码
我们可以通过调用 sum.default 来调用该函数135. 输出什么?
const handler = {
set: () => console.log(“Added a new property!”),
get: () => console.log(“Accessed a property!”)
};
const person = new Proxy({}, handler);
person.name = “Lydia”;
person.name;
复制代码- A: Added a new property!
- B: Accessed a property!
- C: Added a new property! Accessed a property!
- D: 没有任何输出
答案: C
使用 Proxy 对象,我们可以给一个对象添加自定义行为。在这个 case,我们传递一个包含以下属性的对象 handler : set and get。每当我门 设置 属性值时 set 被调用,每当我们 获取 时 get 被调用。 第一个参数是一个空对象 {},作为 person 的值。对于这个对象,自定义行为被定义在对象 handler。如果我们向对象 person 添加属性,set 将被调用。如果我们获取 person 的属性, get 将被调用。 首先,我们向 proxy 对象(person.name = “Lydia”)添加一个属性 name。set 被调用并输出 “Added a new property!”。 然后,我们获取 proxy 对象的一个属性,对象 handler 的属性 get 被调用。输出 “Accessed a property!”。
136. 以下哪一项会对对象 person 有副作用?
const person = { name: “Lydia Hallie” };
Object.seal(person);
复制代码- A: person.name = “Evan Bacon”
- B: person.age = 21
- C: delete person.name
- D: Object.assign(person, { age: 21 })
答案: A
使用 Object.seal 我们可以防止新属性 被添加,或者存在属性 被移除. 然而,你仍然可以对存在属性进行更改。
137. 以下哪一项会对对象 person 有副作用?
const person = {
name: “Lydia Hallie”,
address: {
street: “100 Main St”
}
};
Object.freeze(person);
复制代码- A: person.name = “Evan Bacon”
- B: delete person.address
- C: person.address.street = “101 Main St”
- D: person.pet = { name: “Mara” }
答案: C
使用方法 Object.freeze 对一个对象进行 冻结。不能对属性进行添加,修改,删除。 然而,它仅 对对象进行 浅 冻结,意味着只有 对象中的 直接 属性被冻结。如果属性是另一个 object,像案例中的 address,address 中的属性没有被冻结,仍然可以被修改。
138. 以下哪一项会对对象 person 有副作用?
const person = {
name: “Lydia Hallie”,
address: {
street: “100 Main St”
}
};
Object.freeze(person);
复制代码- A: person.name = “Evan Bacon”
- B: delete person.address
- C: person.address.street = “101 Main St”
- D: person.pet = { name: “Mara” }
答案: C
使用方法 Object.freeze 对一个对象进行 冻结。不能对属性进行添加,修改,删除。 然而,它仅 对对象进行 浅 冻结,意味着只有 对象中的 直接 属性被冻结。如果属性是另一个 object,像案例中的 address,address 中的属性没有被冻结,仍然可以被修改。
139. 输出什么?
const add = x => x + x;
function myFunc(num = 2, value = add(num)) {
console.log(num, value);
}
myFunc();
myFunc(3);
复制代码- A: 2 4 and 3 6
- B: 2 NaN and 3 NaN
- C: 2 Error and 3 6
- D: 2 4 and 3 Error
答案: A
首先我们不传递任何参数调用 myFunc()。因为我们没有传递参数,num 和 value 获取它们各自的默认值:num 为 2, 而 value 为函数 add 的返回值。对于函数 add,我们传递值为2的 num 作为参数。函数 add 返回 4 作为 value 的值。 然后,我们调用 myFunc(3) 并传递值 3 参数 num 的值。我们没有给 value 传递值。因为我们没有给参数 value 传递值,它获取默认值:函数 add 的返回值。对于函数 add,我们传递值为3的 num给它。函数 add 返回 6 作为 value 的值。
140. 输出什么?
class Counter {
#number = 10
increment() {
this.#number++
}
getNum() {
return this.#number
}
}
const counter = new Counter()
counter.increment()
console.log(counter.#number)
复制代码- A: 10
- B: 11
- C: undefined
- D: SyntaxError
答案: D
在 ES2020 中,通过 # 我们可以给 class 添加私有变量。在 class 的外部我们无法获取该值。当我们尝试输出 counter.#number,语法错误被抛出:我们无法在 class Counter 外部获取它!
141. 选择哪一个?
const teams = [
{ name: “Team 1”, members: [“Paul”, “Lisa”] },
{ name: “Team 2”, members: [“Laura”, “Tim”] }
];
function getMembers(members) {
for (let i = 0; i < members.length; i++) {
yield members[i];
}
}
function getTeams(teams) {
for (let i = 0; i < teams.length; i++) {
// ✨ SOMETHING IS MISSING HERE ✨
}
}
const obj = getTeams(teams);
obj.next(); // { value: “Paul”, done: false }
obj.next(); // { value: “Lisa”, done: false }
复制代码- A: yield getMembers(teams[i].members)
- B: yield* getMembers(teams[i].members)
- C: return getMembers(teams[i].members)
- D: return yield getMembers(teams[i].members)
答案: B
为了遍历 teams 数组中对象的属性 members 中的每一项,我们需要将 teams[i].members 传递给 Generator 函数 getMembers。Generator 函数返回一个 generator 对象。为了遍历这个 generator 对象中的每一项,我们需要使用 yield*. 如果我们没有写 yield,return yield 或者 return,整个 Generator 函数不会第一时间 return 当我们调用 next 方法.
142. 输出什么?
const person = {
name: “Lydia Hallie”,
hobbies: [“coding”]
};
function addHobby(hobby, hobbies = person.hobbies) {
hobbies.push(hobby);
return hobbies;
}
addHobby(“running”, []);
addHobby(“dancing”);
addHobby(“baking”, person.hobbies);
console.log(person.hobbies);
复制代码- A: [“coding”]
- B: [“coding”, “dancing”]
- C: [“coding”, “dancing”, “baking”]
- D: [“coding”, “running”, “dancing”, “baking”]
答案: C
函数 addHobby 接受两个参数,hobby 和有着对象 person 中数组 hobbies 默认值的 hobbies。 首相,我们调用函数 addHobby,并给 hobby 传递 “running” 以及给 hobbies 传递一个空数组。因为我们给 hobbies 传递了空数组,”running” 被添加到这个空数组。 然后,我们调用函数 addHobby,并给 hobby 传递 “dancing”。我们不向 hobbies 传递值,因此它获取其默认值 —— 对象 person 的 属性 hobbies。我们向数组 person.hobbies push dancing。 最后,我们调用函数 addHobby,并向 hobby 传递 值 “bdaking”,并且向 hobbies 传递 person.hobbies。我们向数组 person.hobbies push dancing。 pushing dancing 和 baking 之后,person.hobbies 的值为 [“coding”, “dancing”, “baking”]
143. 输出什么?
class Bird {
constructor() {
console.log(“I’m a bird. 🦢”);
}
}
class Flamingo extends Bird {
constructor() {
console.log(“I’m pink. 🌸”);
super();
}
}
const pet = new Flamingo();
复制代码- A: I’m pink. 🌸
- B: I’m pink. 🌸 I’m a bird. 🦢
- C: I’m a bird. 🦢 I’m pink. 🌸
- D: Nothing, we didn’t call any method
答案: B
我们创建了类 Flamingo 的实例 pet。当我们实例化这个实例,Flamingo 中的 constructor 被调用。首相,输出 “I’m pink. 🌸”, 之后我们调用super()。super() 调用父类的构造函数,Bird。Bird 的构造函数被调用,并输出 “I’m a bird. 🦢”。
144. 哪一个选项会导致报错?
const emojis = [“🎄”, “🎅🏼”, “🎁”, “⭐”];
/ 1 / emojis.push(“🦌”);
/ 2 / emojis.splice(0, 2);
/ 3 / emojis = […emojis, “🥂”];
/ 4 / emojis.length = 0;
复制代码- A: 1
- B: 1 and 2
- C: 3 and 4
- D: 3
答案: D
const 关键字意味着我们不能 重定义 变量中的值,它 仅可读。而然,值本身不可修改。数组 emojis 中的值可被修改,如 push 新的值, 拼接,又或者将数组的长度设置为0。
145. 我们需要向对象 person 添加什么,以致执行 […person] 时获得形如 [“Lydia Hallie”, 21] 的输出?
const person = {
name: “Lydia Hallie”,
age: 21
}
[…person] // [“Lydia Hallie”, 21]
复制代码- A: 不需要,对象默认就是可迭代的
- B: Symbol.iterator { for (let x in this) yield this[x] }
- C: Symbol.iterator { for (let x in this) yield Object.values(this) }
- D: *Symbol.iterator { for (let x in this) yield this }
答案: C
对象默认并不是可迭代的。如果迭代规则被定义,则一个对象是可迭代的(An iterable is an iterable if the iterator protocol is present)。我们可以通过添加迭代器symbol [Symbol.iterator] 来定义迭代规则,其返回一个 generator 对象,比如说构建一个 generator 函数 Symbol.iterator {}。如果我们想要返回数组 [“Lydia Hallie”, 21]: yield Object.values(this),这个 generator 函数一定要 yield 对象 person 的Object.values。
146. 输出什么?
let count = 0;
const nums = [0, 1, 2, 3];nums.forEach(num => {
if (num) count += 1
})console.log(count)
复制代码- A: 1
- B: 2
- C: 3
- D: 4
答案: C
forEach循环中的if条件检查num的值是真还是假。 由于nums数组中的第一个数字为0,即:伪造的值,因此if语句的代码块将不会执行。 对于nums数组中的其他3个数字,count只会增加,分别为1、2和3。 由于count被增加了1 3倍,因此count的值是3。
147. 输出什么?
function getFruit(fruits) {
console.log(fruits?.[1]?.[1])
fruits?(console.log(.[1]);)
}getFruit([[‘🍊’, ‘🍌’], [‘🍍’]])
getFruit()
getFruit([[‘🍍’], [‘🍊’, ‘🍌’]])
复制代码- A: null, undefined, 🍌
- B: [], null, 🍌
- C: [], [], 🍌
- D: undefined, undefined, 🍌
答案: D
“?”允许我们选择访问对象内更深层的嵌套属性。我们正在尝试将子项记录在fruits数组的索引“ 1”上的子数组中的索引“ 1”上。如果fruits数组中的索引1上的子数组不存在,它将简单地返回undefined。如果存在“水果”数组中索引“ 1”上的子数组,但是此子数组在其“ 1”索引上没有任何项,则它还将返回undefined。
首先,我们试图将第二项记录在[[[‘🍊’,’🍌’],[‘🍍’]]]的[‘🍍’]`子数组中。此子数组仅包含一个项目,这意味着索引“ 1”上没有任何项目,并返回“ undefined”。
然后,我们在调用getFruits函数时未传递值作为参数,这意味着默认情况下,fruits的值为undefined。由于我们有条件地链接“水果”的索引“ 1”上的项目,因此它返回“未定义”,因为索引“ 1”上的该项目不存在。
最后,我们尝试将第二项记录在[‘🍍’],[‘🍊’,’🍌’]的[‘🍊’,’🍌’]子数组中。该子数组中索引“ 1”上的项是“🍌”,将其记录下来。148. 输出什么?
class Calc {
constructor() {
this.count = 0
}increase() {<br /> this.count ++<br /> }<br />}const calc = new Calc()
new Calc().increase()console.log(calc.count)
复制代码- A: 0
- B: 1
- C: undefined
- D: ReferenceError
答案: A
我们将变量calc设置为等于Calc类的新实例。 然后,我们实例化一个新的Calc实例,并对该实例调用increase方法。 由于count属性位于Calc类的构造函数中,因此count属性不会在Calc的原型上共享。 这意味着对于calc所指向的实例,count的值尚未更新,count仍为0。
149. 输出什么?
const user = {
email: “e@mail.com”,
password: “12345”
}const updateUser = ({ email, password }) => {
if (email) {
Object.assign(user, { email })
}if (password) {<br /> user.password = password<br /> } return user<br />}const updatedUser = updateUser({ email: “new@email.com” })
console.log(updatedUser === user)
复制代码- A: false
- B: true
- C: TypeError
- D: ReferenceError
答案: B
如果将用户的“ email”和“ password”属性的值传递给函数,则“ updateUser”函数将其值更新,此后该函数将返回“ user”对象。 函数“ updateUser”的返回值是“ user”对象,这意味着updatedUser的值是对“ user”指向的同一“ user”对象的引用。 “ updatedUser === user”等于“ true”。
150. 输出什么?
const fruit = [‘🍌’, ‘🍊’, ‘🍎’]
fruit.slice(0, 1)
fruit.splice(0, 1)
fruit.unshift(‘🍇’)
复制代码- A: [‘🍌’, ‘🍊’, ‘🍎’]
- B: [‘🍊’, ‘🍎’]
- C: [‘🍇’, ‘🍊’, ‘🍎’]
- D: [‘🍇’, ‘🍌’, ‘🍊’, ‘🍎’]
答案: C
首先,我们在fruit数组上调用slice方法。 slice方法不会修改原始数组,但会返回从数组中切出的值:香蕉表情符号。 然后,我们在fruit数组上调用splice方法。 拼接方法确实修改了原始数组,这意味着fruit数组现在由[[🍊],’🍎’]组成。 最后,我们在“fruit”数组上调用“ unshift”方法,该方法通过添加提供的值“🍇”作为数组中的第一个元素来修改原始数组。 水果数组现在由“ [“🍇”,“🍊”,“🍎”]组成。
151. 输出什么?
const animals = {};
let dog = { emoji: ‘🐶’ }
let cat = { emoji: ‘🐈’ }animals[dog] = { …dog, name: “Mara” }
animals[cat] = { …cat, name: “Sara” }console.log(animals[dog])
复制代码- A: { emoji: “🐶”, name: “Mara” }
- B: { emoji: “🐈”, name: “Sara” }
- C: undefined
- D: ReferenceError
答案: B
对象键将转换为字符串。
由于“ dog”的值是一个对象,因此“ animals [dog]”实际上意味着我们正在创建一个名为““ Object Object””的新属性,该属性等于新对象。 “ animals [“ object Object”]]现在等于{emoji:“🐶”,名称:“ Mara”}。
“ cat”也是一个对象,这意味着“ animals [cat]”实际上意味着我们正在使用新的cat属性覆盖“ animals [“” object Object“”“]]的值。
因为将dog对象转换为字符串结果“ object Object”,所以记录animals [dog]或实际上是“ animals [” object Object“]都会返回{emoji:”🐈“,名称:” Sara”}`。152. 输出什么?
const user = {
email: “my@email.com”,
updateEmail: email => {
this.email = email
}
}user.updateEmail(“new@email.com”)
console.log(user.email)
复制代码- A: my@email.com
- B: new@email.com
- C: undefined
- D: ReferenceError
答案: A
updateEmail函数是一个箭头函数,未绑定到user对象。 这意味着关键字“ this”不是在引用“ user”对象,而是在这种情况下引用了全局范围。 用户对象内的电子邮件值不会被更新。 记录“ user.email”的值时,将返回“ my@email.com”的原始值。
153. 输出什么?
const promise1 = Promise.resolve(‘First’)
const promise2 = Promise.resolve(‘Second’)
const promise3 = Promise.reject(‘Third’)
const promise4 = Promise.resolve(‘Fourth’)const runPromises = async () => {
const res1 = await Promise.all([promise1, promise2])
const res2 = await Promise.all([promise3, promise4])
return [res1, res2]
}runPromises()
.then(res => console.log(res))
.catch(err => console.log(err))
复制代码- A: [[‘First’, ‘Second’], [‘Fourth’]]
- B: [[‘First’, ‘Second’], [‘Third’, ‘Fourth’]]
- C: [[‘First’, ‘Second’]]
- D: ‘Third’
答案: D
Promise.all方法并行运行传递的promise。 如果一个Promise失败,则Promise.all方法(_rejects)带有rejected的promise的值。 在这种情况下,“ promise3”reject返回了“Third”。 我们正在对runPromises调用进行链接的catch方法中捕获被拒绝的值,以捕获runPromises函数中的所有错误。 因为promise3拒绝了这个值,所以只有Third被记录。
154.当method是下列选项中的那项的时候,将会输出{ name: “Lydia”, age: 22 }?
const keys = [“name”, “age”]
const values = [“Lydia”, 22]const method = / ?? /
Objectmethod => {
return [keys[i], values[i]]
})) // { name: “Lydia”, age: 22 }
复制代码- A: entries
- B: values
- C: fromEntries
- D: forEach
答案: C
fromEntries方法将二维数组转换为对象。 每个子数组中的第一个元素将是键,每个子数组中的第二个元素将是值。 在这种情况下,我们将在“ keys”数组上进行映射,该数组将返回一个数组,其中第一个元素是当前索引上的键数组的项目,第二个元素是当前索引上的值数组的项目。
这将创建一个包含正确键和值的子数组数组,从而导致`{name:“ Lydia”,age:22}155. 输出什么?
const createMember = ({ email, address = {}}) => {
const validEmail = /.+\@.+..+/.test(email)
if (!validEmail) throw new Error(“Valid email pls”)return {<br /> email,<br /> address: address ? address : null<br /> }<br />}const member = createMember({ email: “my@email.com” })
console.log(member)
复制代码- A: { email: “my@email.com”, address: null }
- B: { email: “my@email.com” }
- C: { email: “my@email.com”, address: {} }
- D: { email: “my@email.com”, address: undefined }
答案: C
“address”的默认值是一个空对象“ {}”。 当我们将变量member设置为等于createMember函数返回的对象时,我们没有传递address的值,这意味着address的值是默认的空对象{}。 空对象是真实值,这意味着“address? address:null`,条件返回“ true”。 address的值为空对象“ {}”。
156. 输出什么?
let randomValue = { name: “Lydia” }
randomValue = 23if (!typeof randomValue === “string”) {
console.log(“It’s not a string!”)
} else {
console.log(“Yay it’s a string!”)
}
复制代码- A: It’s not a string!
- B: Yay it’s a string!
- C: TypeError
- D: undefined
答案: B
“ if”语句中的条件检查“!typeof randomValue”的值是否等于““ string””。 “!”运算符将值转换为布尔值。 如果值为真,则返回的值为“ false”;如果值为虚假,则返回的值为“ true”。 在这种情况下,“ typeof randomValue”的返回值是真实值““ string””,这意味着“!typeof randomValue”的值是布尔值“ false”。
!! typeof randomValue ===“ string”总是返回false,因为我们实际上是在检查“ false ===” string“。 由于条件返回了“ false”,因此将运行“ else”语句的代码块,并记录“是的,是字符串!”。作者:将源兵魂
链接:https://juejin.im/post/5f01f892e51d4534a049865b
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。获取页面元素位置与宽高?
- element.clientWidth = content + padding
- element.clientHeight = content + padding
- element.getBoundingClientRect() 返回值情况
- left:包围盒左边 border 以外的边缘距页面左边的距离
- right:包围盒右边 border 以外的边缘距页面左边的距离
- top:包围盒上边 border 以外的边缘距页面顶部的距离
- bottom:包围盒下边 border 以外的便于距页面顶部的距离
- width: content + padding + border
- height: content + padding + border
- 注意,设置外边距时外边距合并的情况
requestAnimationFrame 原理?是同步还是异步?
异步,传入的函数在重绘之前调用 详细参考:- http://web.jobbole.com/91578/
- https://my.oschina.net/bghead/blog/850692
- http://www.zhangxinxu.com/wordpress/2013/09/css3-animation-requestanimationframe-tween-%E5%8A%A8%E7%94%BB%E7%AE%97%E6%B3%95/
js事件机制?点击屏幕上一个按钮,事件是如何传播的?
捕获 冒泡
下面代码输出结果?为什么?
Function.prototype.a = ‘a’;
Object.prototype.b = ‘b’;
function Person(){};
var p = new Person();
console.log(‘p.a: ‘+ p.a); // p.a: undefined
console.log(‘p.b: ‘+ p.b); // p.b: b
复制代码
下面代码输出结果?为什么?
const person = {
namea: ‘menglinghua’,
say: function (){
return function (){
console.log(this.namea);
};
}
};
person.say()(); // undefined
复制代码
const person = {
namea: ‘menglinghua’,
say: function (){
return () => {
console.log(this.namea);
};
}
};
person.say()(); // menglinghua
复制代码
下面代码输出结果?为什么?
setTimeout(() => console.log(‘a’), 0);
var p = new Promise((resolve) => {
console.log(‘b’);
resolve();
});
p.then(() => console.log(‘c’));
p.then(() => console.log(‘d’));
console.log(‘e’);
// 结果:b e c d a
// 任务队列优先级:promise.Trick()>promise的回调>setTimeout>setImmediate
复制代码
async function async1() {
console.log(“a”);
await async2(); //执行这一句后,await会让出当前线程,将后面的代码加到任务队列中,然后继续执行函数后面的同步代码
console.log(“b”);
}
async function async2() {
console.log( ‘c’);
}
console.log(“d”);
setTimeout(function () {
console.log(“e”);
},0);
async1();
new Promise(function (resolve) {
console.log(“f”);
resolve();
}).then(function () {
console.log(“g”);
});
console.log(‘h’);
// 谁知道为啥结果不一样?????????????
// 直接在控制台中运行结果: d a c f h g b e
// 在页面的script标签中运行结果:d a c f h b g e
复制代码
js bind 实现机制?手写一个 bind 方法?
// 代码来自书籍 《javaScript 模式》
if (typeof Function.prototype.bind === “undefined”){
Function.prototype.bind = function (thisArgs){
var fn = this,
slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function (){
return fn.apply(thisArgs, args.concat(slice.call(arguments)));
}
}
}
复制代码
实现 vue 中的 on,emit,off,once,手写代码。
// 参照 vue 源码实现
var EventEmiter = function (){
this._events = {};
};
EventEmiter.prototype.on = function (event, cb){
if (Array.isArray(event)){
for (let i = 0, l = event.length; i < l; i++){
this.on(event[i], cb);
}
} else {
(this._events[event] || (this._events[event] = [])).push(cb);
}
return this;
};
EventEmiter.prototype.once = function (event, cb){
function on () {
this.off(event, cb);
cb.apply(this, arguments);
}
on.fn = cb;
this.on(event, on);
return this;
};
EventEmiter.prototype.off = function (event, cb){
if (!arguments.length){
this._events = Object.create(null);
return this;
}
if (Array.isArray(event)){
for (let i = 0, l = event.length; i < l; i++){
this.off(event[i],cb);
}
return this;
}
if (!cb){
this._events[event] = null;
return this;
}
if (cb){
let cbs = this._events[event];
let i = cbs.length;
while(i—){
if (cb === cbs[i] || cb === cbs[i].fn){
cbs.splice(i, 1);
break;
}
}
return this;
}
};
EventEmiter.prototype.emit = function (event){
let cbs = this._events[event];
let args = Array.prototype.slice.call(arguments, 1);
if (cbs){
for (let i = 0, l = cbs.length; i < l; i++){
cbs[i].apply(this,args);
}
}
};
复制代码
用 js 实现双链表,手写代码?
vue 的双向绑定机制?详细介绍。
哪些操作会引起浏览器重绘和重排?- postion:absolute; left:100px;会不会引起?
- translateX:100px;会不会引起?
- getBoundingClientRect会不会引起?
- getClientWidth、getClientHeight会不会引起?
作者:linghuam
链接:https://juejin.im/post/5a96c6326fb9a063626408c8
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。第 1 题
if(false){
var a = 1;
let b = 2;
}
console.log(a);
console.log(b);
复制代码
查看解析
// 输出
undefinedReferenceError: b is not defined
复制代码
var不会产生块级作用域,let会产生块级作用域。
伪代码相当于:
var a;
if(false){
a = 1;
let b = 2;
}
console.log(a);
console.log(b);
复制代码第 2 题
var a = 1;
if(true){
console.log(a);
let a = 2;
}
复制代码
查看解析
// 输出ReferenceError: Cannot access ‘a’ before initialization
复制代码
let声明的变量不会提升,并且会产生暂存死区。在let声明变量之前访问变量会抛出错误。第 3 题
var a = {n: 1}
var b = a
a.x = a = {n: 2}console.log(a.n, b.n);
console.log(a.x, b.x);
复制代码
查看解析
// 输出2 1
undefined {n: 2}
复制代码
var b = a,此时a和b指向同一个对象。
.运算符比 = 运算符高,先计算
a.x,此时
b = {
n:1,
x:undefined
}相当于给对象添加了x属性。
a.x = a = {n:2};
计算完a.x,再计算 = ,赋值是从右向左,此时a指向一个新对象。
a = {
n:2
}a.x已经执行过了,此时对象的x属性赋值为a,此时
对象 = {
n:1,
x:{
n:2
}
}即:
a = {
n:2
}b = {
n:1,
x:{
n:2
}
}复制代码
查看运算符优先级第 4 题
console.log(c);
var c;
function c(a) {
console.log(a);
var a = 3;
function a(){
}
}
c(2);
复制代码
查看解析
// 输出function c(a){
console.log(a);
var a = 3;
function a(){
}
}function a(){
}
复制代码
变量提升也有优先级, 函数声明 > arguments > 变量声明第 5 题
var c = 1;
function c(c) {
console.log(c);
var c = 3;
}
console.log(c);
c(2);
复制代码
查看解析
// 输出1
TypeError: c is not a function
复制代码
由于函数声明会提升,当函数外的console.log(c)执行时,c已经被赋值为1。因此,执行c(2)时会抛出TypeError,因为1不是函数。第 6 题
var name = ‘erdong’;
(function () {
if (typeof name === ‘undefined’) {
var name = ‘chen’;
console.log(name);
} else {
console.log(name);
}
})();
复制代码
查看解析
// 输出chen
复制代码
自执行函数执行时,会先进行变量提升(这里涉及到执行上下文不过多说,一定要搞懂执行上下文),在自执行函数执行时,伪代码为:
var name = ‘erdong’;
(function () {
var name; // 变量name会提升到当前作用域顶部
if (typeof name === ‘undefined’) {
name = ‘chen’
console.log(name)
} else {
console.log(name)
}
})();复制代码
所以会执行if中的console.log(name)第 7 题
var a = 10;
function test() {
a = 100;
console.log(a);
console.log(this.a);
var a;
console.log(a);
}
test();
复制代码
查看解析
// 输出100
10
100
复制代码
test()为函数独立调用,作用域中的this绑定为全局对象window。
test函数执行时,var a被提升到了作用域顶部,因此函数作用域中存在一个变量a。所以在函数中访问的a都是局部作用域中的a。第 8 题
if (!(‘a’ in window)) {
var a = 1;
}
console.log(a);
复制代码
查看解析
// 输出
undefined
复制代码
由于if后的{}不会产生块级作用域(不包含let,const时),此时的伪代码为:
var a;
if (!(a in window)) {
a = 1;
}
console.log(a);
复制代码
var a相当于window.a。因此!(a in window)转成布尔值为false,不会执行a = 1。所有console.log(a)输出undefined。第 9 题
var a = 1;
function c(a, b) {
console.log(a);
a = 2;
console.log(a);
}
c();
复制代码
查看解析
//输出undefined
2
复制代码
跟第4题类似。第 10 题
var val=1;
var obj={
val:2,
del:function(){
console.log(this);
this.val*=2;
console.log(val);
}
}obj.del();
复制代码
查看解析
// 输出
obj(指向的值)1
复制代码
当通过obj.del()调用del函数时,del函数作用域中的this绑定为obj。
在函数作用域中访问val时,由于函数中并没有变量val,因此实际上访问的是全局作用域中的val,即 1。
这里考察的是this的指向,一定要熟练掌握。第 11 题
var name = “erdong”;
var object = {
name: “chen”,
getNameFunc: function () {
return function () {
return this.name;
}
}
}
console.log(object.getNameFunc()());
复制代码
查看解析
// 输出erdong
复制代码
object.getNameFunc()(),先执行object.getNameFunc()返回一个函数:
function () {
return this.name;
}
复制代码
返回的函数再执行,相当于
(function () {
return this.name;
})();
复制代码
此时的this绑定为window。因此输出全局变量name的值erdong。第 12 题
var name = “erdong”;
var object = {
name: “chen”,
getNameFunc: function () {
var that = this;
return function () {
return that.name;
}
}
}
console.log(object.getNameFunc()());复制代码
查看解析
//输出chen
复制代码
object.getNameFunc()执行时,此时getNameFunc中的this绑定为object,因此that = object。object.getNameFunc()返回的函数再执行时,产生闭包,因此返回的函数也能访问到外层作用域中的变量that,因此object.name为object.name,即 chen。第 13 题
(function() {
var a = b = 3;
})();
console.log(typeof a === ‘undefined’);
console.log(typeof b === ‘undefined’);
复制代码
查看解析
// 输出true
false
复制代码
首先要明白var a = b = 3是怎样执行的,伪代码:
b = 3;
var a = b;
复制代码
因此在自执行函数执行时,b由于未经var等操作符声明,为全局变量。a为函数作用域中的局部变量。因此在外面访问a和b时,其值分别为ReferenceError: a is not defined和3。但是typeof检测未声明的变量不会抛出错误,会返回’undefined’。因此typeof a和typeof b分别返回’undefined’和’number’第 14 题
var a = 6;
setTimeout(function () {
a = 666;
}, 0)
console.log(a);
复制代码
查看解析
//输出6
复制代码
setTimeout为宏任务。即使设置延迟为0ms,也是等待同步代码执行完才会执行。因此console.log(a)输出 6第 15 题
function fn1() {
var a = 2;
function fn2 () {
a++;
console.log(a);
}
return fn2;
}
var f = fn1();
f();
f();
复制代码
查看解析
// 输出3
4
复制代码
由于fn1函数执行后返回函数fn2,此时产生了闭包。因此fn2中a访问的是fn1作用域中的变量a,因此第一次a++,之后a为3,第二次之后a为4。第 16 题
var a = (function(foo){
return typeof foo.bar;
})({foo:{bar:1}});console.log(a);
复制代码
查看解析
//输出undefined
复制代码
实参foo的值为{foo:{bar:1},因此typeof foo.bar为undefined。
typeof foo.foo.bar为number。第 17 题
function f(){
return f;
}
console.log(new f() instanceof f);复制代码
查看解析
//输出false
复制代码
由于构造函数f的返回值为f。因此new f()的值为f。所以console.log(new f() instanceof f)为console.log(f instanceof f),即 false。第 18 题
function A () {
}
A.prototype.n = 1;var b = new A();
A.prototype = {
n: 2,
m: 3
}
var c = new A();console.log(b.n, b.m);
console.log(c.n, c.m);
复制代码
查看解析
// 输出1,undefined
2,3
复制代码
var b = new A(); 实例化b时,A的prototype为
A.prototype = {
constructor:A,
n:1
}
复制代码
当访问b.n和b.m时,通过原型链找到A.prototype指向的对象上,即b.n = 1,b.m = undefined。
var c = new A(); 实例化c时,A的prototype为
A.prototype = {
n: 2,
m: 3
}
复制代码
当访问a.n和a.m时,通过原型链找到A.prototype指向的对象上,此时A.prototype重写,因此a.n = 2,b.m = 3。第 19 题
var F = function(){};
var O = {};
Object.prototype.a = function(){
console.log(‘a’)
}
Function.prototype.b = function(){
console.log(‘b’)
}
var f = new F();F.a();
F.b();
O.a();
O.b();
复制代码
查看解析
// 输出a
b
a
TypeError: O.b is not a function复制代码
F为函数,它也能访问Object原型上的方法,O为对象,不能访问Function原型上的方法。
F的原型链为:
F => F.proto => Function.prototype => Function.prototype.proto => Object.prototype
复制代码
由于Object.prototype在F的原型链上,所以F能访问Object.prototype上的属性和方法。即: F.a(),F.b()能正常访问。
O的原型链为:
O => O.proto => Object.prototype
复制代码
由于Function.prototype不在O的原型链上,因此O不能访问Function.prototype上的方法,即O.b()抛出错误。
如果你对原型和原型链掌握的好,试着理解下面的示例:
console.log(Object instanceof Function);console.log(Function instanceof Object);
console.log(Function instanceof Function);
复制代码
第 20 题
function Person() {
getAge = function () {
console.log(10)
}
return this;
}Person.getAge = function () {
console.log(20)
}Person.prototype.getAge = function () {
console.log(30)
}var getAge = function () {
console.log(40)
}function getAge() {
console.log(50)
}Person.getAge();
getAge();
Person().getAge();
new Person.getAge();
getAge();
new Person().getAge();
复制代码
查看解析
// 输出20
40
10
20
10
30
复制代码
Person.getAge();此时执行的是Person函数上getAge方法。
Person.getAge = function () {
console.log(20)
}
复制代码
所以输出:20。
getAge();此时执行的是全局中的getAge方法。此时全局getAge方法为:
function () {
console.log(40)
}
复制代码
所以输出:40。
Person().getAge();由于Person()单独执行所以,作用域中的this绑定为window,相当于window.getAge()。同上,执行的都是全局getAge 方法,但是Person执行时,内部执行了
getAge = function () {
console.log(10)
}
复制代码
因此全局getAge方法现在为:
function () {
console.log(10)
}
复制代码
所以输出:10。
new Person.getAge();此时相当于实例化Person.getAge这个函数,伪代码:
var b = Person.getAge;
new b();
复制代码
所以输出:20
getAge();执行全局getAge方法,由于在Person().getAge()执行时把全局getAge方法赋值为:
function () {
console.log(10)
}
复制代码
所以输出:10。
new Person().getAge();此时调用的是Person原型上的getAge方法:
Person.prototype.getAge = function () {
console.log(30)
}
复制代码
所以输出:30。
这里要注意:1.变量提升及提升后再赋值。2.调用构造函数时,带()和不带()的区别。第 21 题
console.log(false.toString());
console.log([1, 2, 3].toString());
console.log(1.toString());
console.log(5..toString());
复制代码
查看解析
// 输出‘false’
‘1,2,3’
Uncaught SyntaxError: Invalid or unexpected token
‘5’
复制代码
当执行1.toString();时,由于1.也是有效数字,因此此时变成(1.)toString()。没有用.调用toString方法,因此抛出错误。
正确的应该是:
1..toString();
1 .toString();
(1).toString();
复制代码第 22 题
console.log(typeof NaN === ‘number’);
复制代码
查看解析
//输出true
复制代码
NaN为不是数字的数字。虽然它不是数字,但是它也是数字类型。第 23 题
console.log(1 + “2” + “2”);
console.log(1 + +”2” + “2”);
console.log(1 + -“1” + “2”);
console.log(+”1” + “1” + “2”);
console.log( “A” - “B” + “2”);
console.log( “A” - “B” + 2);
复制代码
查看解析
//输出‘122’
‘32’
‘02’
‘112’
‘NaN2’
NaN
复制代码
首先要明白两点:- +a,会把a转换为数字。-a会把a转换成数字的负值(如果能转换为数字的话,否则为NaN)。
- 字符串与任何值相加都是字符串拼接。
console.log(1 + “2” + “2”);简单的字符串拼接,即结果为:’122’。
console.log(1 + +”2” + “2”);这里相当于console.log(1 + 2 + “2”);,然后再字符串拼接。即结果为:’32’。
console.log(1 + -“1” + “2”);这里相当于console.log(1 + -1 + “2”);,然后再字符串拼接。即结果为:’02’。
console.log(+”1” + “1” + “2”);这里相当于console.log(1 + “1” + “2”);,然后再字符串拼接。即结果为:’112’。
console.log( “A” - “B” + “2”);,由于’A’ - ‘B’ = NaN,所以相当于console.log( NaN + “2”);, 然后再字符串拼接。即结果为:’NaN2’。
console.log( “A” - “B” + 2);同上,相当于console.log(NaN + 2),由于NaN+任何值还是NaN,即结果为:NaN。第 24 题
var a = 666;
console.log(++a);
console.log(a++);
console.log(a);
复制代码
查看解析
// 输出667
667
668
复制代码
++a先执行+1操作,再执行取值操作。 此时a的值为667。因此输出667。
a++先执行取值操作,再执行+1。 此时输出667,随后a的值变为668。
—a和a—同理。
使用这类运算符时要注意:
1)这里的++、—不能用作于常量。比如
1++; // 抛出错误
复制代码
2)如果a不是数字类型,会首先通过Number(a),将a转换为数字。再执行++等运算。第 25 题
console.log(typeof a);
function a() {}
var a;
console.log(typeof a);
复制代码
查看解析
// 输出‘function’
‘function’
复制代码
跟第4题类似。函数会优先于变量声明提前。因此会忽略var a。第 26 题
var a;
var b = ‘undefined’;
console.log(typeof a);
console.log(typeof b);
console.log(typeof c);复制代码
查看解析
// 输出
‘undefined’
‘string’
‘undefined’
复制代码
a为声明未赋值,默认为undefined,b的值为字符串’undefined’,c为未定义。
typeof一个未定义的变量时,不会抛出错误,会返回’undefined’。注意typeof返回的都是字符串类型。第 27 题
var x = 1;
if(function f(){}){
x += typeof f;
}
console.log(x);
复制代码
查看解析
//输出1undefined
复制代码
function f(){}当做if条件判断,其隐式转换后为true。但是在()中的函数不会声明提升,因此f函数在外部是不存在的。因此typeof f = ‘undefined’,所以x += typeof f,相当于x = x + ‘undefined’为’1undefined’第 28 题
var str = “123abc”;
console.log(typeof str++);
复制代码
查看解析
// 输出‘number’
复制代码
在24题解析时提到,使用++运算符时(无论是前置还是后置),如果变量不是数字类型,会首先用Number()转换为数字。因此typeof str++相当于typeof Number(str)++。由于后置的++是先取值后计算,因此相当于typeof Number(“123abc”)。即typeof NaN,所以输出’number’。第 29 题
console.log(‘b’ + ‘a’ + +’a’+’a’);
复制代码
查看解析
// 输出baNaNa
复制代码
‘b’ + ‘a’ + +’a’+’a’相当于’ba’ + +’a’+’a’,+’a’会将’a’转换为数字类型,即+’a’ = NaN。所以最终得到’ba’ + NaN +’a’,通过字符串拼接,结果为:baNaNa第 30 题
var obj = {n: 1};
function fn2(a) {
a.n = 2;
}
fn2(obj);
console.log(obj.n);
复制代码
查看解析
// 输出2
复制代码
函数传递参数时,如果是基本类型为值传递,如果是引用类型,为引用地址的值传递。其实都是值传递。因此形参a和obj引用地址相同,都指向同一个对象。当执行a.n,实际上共同指向的对象修改了,添加了个n属性,因此obj.n为2。第 31 题
var x = 10;
function fn() {
console.log(x);
}
function show(f) {
var x = 20;
f();
}
show(fn);
复制代码
查看解析
// 输出10
复制代码
JavaScript采用的是词法作用域,它规定了函数内访问变量时,查找变量是从函数声明的位置向外层作用域中查找,而不是从调用函数的位置开始向上查找。因此fn函数内部访问的x是全局作用域中的x,而不是show函数作用域中的x。第 32 题
Object.prototype.bar = 1;
var foo = {
goo: undefined
};console.log(foo.bar);
console.log(‘bar’ in foo);console.log(foo.hasOwnProperty(‘bar’));
console.log(foo.hasOwnProperty(‘goo’));
复制代码
查看解析
//输出1
true
false
true复制代码
in操作符:检测指定对象(右边)原型链上是否有对应的属性值。 hasOwnProperty方法:检测指定对象自身上是否有对应的属性值。两者的区别在于in会查找原型链,而hasOwnProperty不会。
示例中对象foo自身上存在goo属性,而它的原型链上存在bar属性。
通过这个例子要注意如果要判断foo上是否有属性goo,不能简单的通过if(foo.goo){}判断,因为goo的值可能为undefined或者其他可能隐式转换为false的值。第 33 题
Object.prototype.bar = 1;
var foo = {
moo: 2
};
for(var i in foo) {
console.log(i);
}
复制代码
查看解析
// 输出‘moo’
‘bar’
复制代码
for…in…遍历对象上除了Symbol以外的可枚举属性,包括原型链上的属性。第 34 题
function foo1() {
return {
bar: “hello”
};
}
function foo2() {
return
{
bar: “hello”
};
}
console.log(foo1());
console.log(foo2());
复制代码
查看解析
// 输出{ bar: “hello” }
undefined
复制代码
两个函数唯一区别就是return后面跟的值,一个换行一个不换行。
当我们书写代码时忘记在结尾书写;时,JavaScript解析器会根据一定规则自动补上;。
return
{
bar: “hello”
}
=> 会被解析成
return;
{
bar: “hello”
};
复制代码
因此函数执行后会返回undefined。第 35 题
console.log((function(){ return typeof arguments; })());
复制代码
查看解析
// 输出‘object’
复制代码
arguments为类数组,类型为object。因此typeof arguments = ‘object’。第 36 题
console.log(Boolean(false));
console.log(Boolean(‘0’));
console.log(Boolean(‘’));
console.log(Boolean(NaN));
复制代码
查看解析
//输出false
true
false
fasle复制代码
只有下面几种值在转换为布尔值时为false:
+0,-0,NaN,false,’’,null,undefined。复制代码
除此之外的值在转换为布尔值的时候全部为true。第 37 题
console.log(Array(3));
console.log(Array(2,3));
复制代码
查看解析
// 输出[empty × 3]
[2,3]
复制代码
使用Array()创建数组时,要注意传入的值的类型和数量。第 38 题
console.log(0.1 + 0.2 == 0.3);
复制代码
查看解析
// 输出false
复制代码第 39 题
var a=[1, 2, 3];
console.log(a.join());
复制代码
查看解析
//输出1,2,3
复制代码
join方法如果省略参数,默认以,分隔。第 40 题
var a = [3];
var b = [1];
console.log(a - b);复制代码
查看解析
// 输出2
复制代码
在执行a - b时,a和b都要转换为数字。首先a先转换为字符串,[3] => [3].toString() => ‘3’,然后Number(3) => 3。b同理。因此转换之后为3 - 1 = 2。
作者:Erdong
链接:https://juejin.im/post/5ee03947e51d457889262921
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构?
基本数据类型:Undefined、Null、Boolean、Number、String
值类型:数值、布尔值、null、undefined。
引用类型:对象、数组、函数。
堆栈数据结构:是一种支持后进先出(LIFO)的集合,即后被插入的数据,先被取出!
js数组中提供了以下几个方法可以让我们很方便实现堆栈:
shift:从数组中把第一个元素删除,并返回这个元素的值。
unshift: 在数组的开头添加一个或更多元素,并返回新的长度
push:在数组的中末尾添加元素,并返回新的长度
pop:从数组中把最后一个元素删除,并返回这个元素的值。
2.声明函数作用提升?声明变量和声明函数的提升有什么区别?
(1) 变量声明提升:变量申明在进入执行上下文就完成了。
只要变量在代码中进行了声明,无论它在哪个位置上进行声明, js引擎都会将它的声明放在范围作用域的顶部;(2) 函数声明提升:执行代码之前会先读取函数声明,意味着可以把函数申明放在调用它的语句后面。
只要函数在代码中进行了声明,无论它在哪个位置上进行声明, js引擎都会将它的声明放在范围作用域的顶部;(3) 变量or函数声明:函数声明会覆盖变量声明,但不会覆盖变量赋值。
同一个名称标识a,即有变量声明var a,又有函数声明function a() {},不管二者声明的顺序,函数声明会覆盖变量声明,也就是说,此时a的值是声明的函数function a() {}。注意:如果在变量声明的同时初始化a,或是之后对a进行赋值,此时a的值变量的值。eg: var a; var c = 1; a = 1; function a() { return true; } console.log(a);
3.判断数据类型?
typeof返回的类型都是字符串形式,可以判断function的类型;在判断除Object类型的对象时比较方便。
判断已知对象类型的方法: instanceof,后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。
4.异步编程?
方法1:回调函数,优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。方法2:时间监听,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以“去耦合”(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。
方法3:发布/订阅,性质与“事件监听”类似,但是明显优于后者。
方法4:Promises对象,是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。
简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。
5.事件流?事件捕获?事件冒泡?
事件流:从页面中接收事件的顺序。也就是说当一个事件产生时,这个事件的传播过程,就是事件流。IE中的事件流叫事件冒泡;事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档)。对于html来说,就是当一个元素产生了一个事件,它会把这个事件传递给它的父元素,父元素接收到了之后,还要继续传递给它的上一级元素,就这样一直传播到document对象(亲测现在的浏览器到window对象,只有IE8及下不这样
事件捕获是不太具体的元素应该更早接受到事件,而最具体的节点应该最后接收到事件。他们的用意是在事件到达目标之前就捕获它;也就是跟冒泡的过程正好相反,以html的click事件为例,document对象(DOM级规范要求从document开始传播,但是现在的浏览器是从window对象开始的)最先接收到click事件的然后事件沿着DOM树依次向下传播,一直传播到事件的实际目标;
6.如何清除一个定时器?
window.clearInterval();
window.clearTimeout();
7.如何添加一个dom对象到body中?innerHTML和innerText区别?
body.appendChild(dom元素);
innerHTML:从对象的起始位置到终止位置的全部内容,包括Html标签。
innerText:从起始位置到终止位置的内容, 但它去除Html标签
分别简述五个window对象、属性成员对象
window.event window.document window.history
window.screen window.navigator window.external
Window对象的属性如下:
window //窗户自身
window.self //引用本窗户window=window.self
window.name //为窗户命名
window.defaultStatus //设定窗户状态栏信息
window.location //URL地址,配备布置这个属性可以打开新的页面
8.数据持久化技术(ajax)?简述ajax流程
1)客户端产生js的事件
2)创建XMLHttpRequest对象
3)对XMLHttpRequest进行配置
4)通过AJAX引擎发送异步请求
5)服务器端接收请求并且处理请求,返回html或者xml内容
6)XML调用一个callback()处理响应回来的内容
7)页面局部刷新
9.回调函数?
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
10.什么是闭包?* 堆栈溢出有什么区别? 内存泄漏? 那些操作会造成内存泄漏?怎么样防止内存泄漏?
闭包:就是能够读取其他函数内部变量的函数。
堆栈溢出:就是不顾堆栈中分配的局部数据块大小,向该数据块写入了过多的数据,导致数据越界,结果覆盖了别的数据。经常会在递归中发生。
内存泄露是指:用动态存储分配函数内存空间,在使用完毕后未释放,导致一直占据该内存单元。直到程序结束。指任何对象在您不再拥有或需要它之后仍然存在。造成内存泄漏:
setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
防止内存泄露:
1、不要动态绑定事件;
2、不要在动态添加,或者会被动态移除的dom上绑事件,用事件冒泡在父容器监听事件;
3、如果要违反上面的原则,必须提供destroy方法,保证移除dom后事件也被移除,这点可以参考Backbone的源代码,做的比较好;
4、单例化,少创建dom,少绑事件。
11.平时工作中怎么样进行数据交互?如果后台没有提供数据怎么样进行开发?mock数据与后台返回的格式不同意怎么办?
由后台编写接口文档、提供数据接口实、前台通过ajax访问实现数据交互;
在没有数据的情况下寻找后台提供静态数据或者自己定义mock数据;
返回数据不统一时编写映射文件 对数据进行映射。
12 简述ajax执行流程
基本步骤:
var xhr =null;//创建对象
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject(“Microsoft.XMLHTTP”);
}
xhr.open(“方式”,”地址”,”标志位”);//初始化请求
xhr.setRequestHeader(“”,””);//设置http头信息
xhr.onreadystatechange =function(){}//指定回调函数
xhr.send();//发送请求
13.自执行函数?用于什么场景?好处?
自执行函数:1、声明一个匿名函数2、马上调用这个匿名函数。
作用:创建一个独立的作用域。好处:防止变量弥散到全局,以免各种js库冲突。隔离作用域避免污染,或者截断作用域链,避免闭包造成引用变量无法释放。利用立即执行特性,返回需要的业务函数或对象,避免每次通过条件判断来处理
场景:一般用于框架、插件等场景
14.html和xhtml有什么区别?
HTML是一种基本的WEB网页设计语言,XHTML是一个基于XML的标记语言。
1.XHTML 元素必须被正确地嵌套。
2.XHTML 元素必须被关闭。
3.标签名必须用小写字母。
4.空标签也必须被关闭。
5.XHTML 文档必须拥有根元素。
15. 什么是构造函数?与普通函数有什么区别?
构造函数:是一种特殊的方法、主要用来创建对象时初始化对象,总与new运算符一起使用,创建对象的语句中构造函数的函数名必须与类名完全相同。
与普通函数相比只能由new关键字调用,构造函数是类的标示
16. 通过new创建一个对象的时候,函数内部有哪些改变
function Person(){}
Person.prototype.friend = [];
Person.prototype.name = ‘’;
// var a = new Person();
// a.friend[0] = ‘王琦’;
// a.name = ‘程娇’;
// var b = new Person();
// b.friend?
// b.name?
1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2、属性和方法被加入到 this 引用的对象中。
3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。
17.事件委托?有什么好处?
(1)利用冒泡的原理,把事件加到父级上,触发执行效果
(2)好处:新添加的元素还会有之前的事件;提高性能。
18.window.onload ==? DOMContentLoaded ?
一般情况下,DOMContentLoaded事件要在window.onload之前执行,当DOM树构建完成的时候就会执行DOMContentLoaded事件,而window.onload是在页面载入完成的时候,才执行,这其中包括图片等元素。大多数时候我们只是想在DOM树构建完成后,绑定事件到元素,我们并不需要图片元素,加上有时候加载外域图片的速度非常缓慢。
19.节点类型?判断当前节点类型?
1. 元素节点
2. 属性节点
3. 文本节点
8. 注释节点
9. 文档节点
通过nodeObject.nodeType判断节点类型:其中,nodeObject 为DOM节点(节点对象)。该属性返回以数字表示的节点类型,例如,元素节点返回 1,属性节点返回 2 。
20.如何合并两个数组?数组删除一个元素?
//三种方法。
(1)var arr1=[1,2,3];
var arr2=[4,5,6];
arr1 = arr1.concat(arr2);
console.log(arr1);
(2)var arr1=[1,2,3];
var arr2=[4,5,6];
Array.prototype.push.apply(arr1,arr2);
console.log(arr1);
(3)var arr1=[1,2,3];
var arr2=[4,5,6];
for (var i=0; i < arr2.length; i++) {
arr1.push( arr2[i] );
}
console.log(arr1);
21.强制转换 显式转换 隐式转换?
//强制类型转换:
Boolean(0) // => false - 零
Boolean(new object()) // => true - 对象
Number(undefined) // => NaN
Number(null) // => 0
String(null) // => “null”
parseInt( )
parseFloat( )
JSON.parse( )
JSON.stringify ( )
隐式类型转换:
在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可以和数字相加。之所以不同的数据类型之间可以做运算,是因为JavaScript引擎在运算之前会悄悄的把他们进行了隐式类型转换的
(例如:x+”” //等价于String(x)
+x //等价于Number(x)
x-0 //同上
!!x //等价于Boolean(x),是双叹号)显式转换:
如果程序要求一定要将某一类型的数据转换为另一种类型,则可以利用强制类型转换运算符进行转换,这种强制转换过程称为显示转换。
显示转换是你定义让这个值类型转换成你要用的值类型,是底到高的转换。例 int 到float就可以直接转,int i=5,想把他转换成char类型,就用显式转换(char)i
22. Jq中如何实现多库并存?
Noconfict 多库共存就是“$ ”符号的冲突。方法一: 利用jQuery的实用函数$.noConflict();这个函数归还$的名称控制权给另一个库,因此可以在页面上使用其他库。这时,我们可以用”jQuery “这个名称调用jQuery的功能。 $.noConflict();
jQuery(‘#id’).hide();
…..
//或者给jQuery一个别名
var $j=jQuery
$j(‘#id’).hide();
…..方法二: (function($){})(jQuery)
方法三: jQuery(function($){})
通过传递一个函数作为jQuery的参数,因此把这个函数声明为就绪函数。 我们声明$为就绪函数的参数,因为jQuery总是吧jQuery对象的引用作为第一个参数传递,所以就保证了函数的执行。
23.Jq中get和eq有什么区别?
get() :取得其中一个匹配的元素。num表示取得第几个匹配的元素,get多针对集合元素,返回的是DOM对象组成的数组 eq():获取第N个元素,下标都是从0开始,返回的是一个JQuery对象
24.如何通过原生js 判断一个元素当前是显示还是隐藏状态?
if( document.getElementById(“div”).css(“display”)===‘none’)
if( document.getElementById(“div”).css(“display”)===‘block’)
$(“#div”).is(“:hidden”); // 判断是否隐藏
$(“#div”).is(“:visible”)
25.Jq如何判断元素显示隐藏?
//第一种:使用CSS属性
var display =$(‘#id’).css(‘display’);
if(display == ‘none’){ alert(“我是隐藏的!”); }
//第二种:使用jquery内置选择器
<div id=“test”> <p>仅仅是测试所用</p>
if($(“#test”).is(“:hidden”)){ $(“#test”).show(); //如果元素为隐藏,则将它显现 }else{ $(“#test”).hide(); //如果元素为显现,则将其隐藏 }
//第三种:jQuery判断元素是否显示 是否隐藏
var node=$(‘#id’);
if(node.is(‘:hidden’)){ //如果node是隐藏的则显示node元素,否则隐藏
node.show();
}else{
node.hide();
}
26.移动端上什么是点击穿透?
点击穿透现象有3种:
点击穿透问题:点击蒙层(mask)上的关闭按钮,蒙层消失后发现触发了按钮下面元素的click事件跨页面点击穿透问题:如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转另一种跨页面点击穿透问题:这次没有mask了,直接点击页内按钮跳转至新页,然后发现新页面中对应位置元素的click事件被触发了解决方案:
1、只用touch
最简单的解决方案,完美解决点击穿透问题
把页面内所有click全部换成touch事件( touchstart 、’touchend’、’tap’)2、只用click
下下策,因为会带来300ms延迟,页面内任何一个自定义交互都将增加300毫秒延迟3、tap后延迟350ms再隐藏mask
改动最小,缺点是隐藏mask变慢了,350ms还是能感觉到慢的4、pointer-events
比较麻烦且有缺陷, 不建议使用mask隐藏后,给按钮下面元素添上 pointer-events: none; 样式,让click穿过去,350ms后去掉这个样式,恢复响应缺陷是mask消失后的的350ms内,用户可以看到按钮下面的元素点着没反应,如果用户手速很快的话一定会发现
27.Jq绑定事件的几种方式?on bind ?
jQuery中提供了四种事件监听方式,分别是bind、live、delegate、on,对应的解除监听的函数分别是unbind、die、undelegate、offBind( )是使用频率较高的一种,作用就是在选择到的元素上绑定特定事件类型的监听函数;
Live( )可以对后生成的元素也可以绑定相应的事件,处理机制就是把事件绑定在DOM树的根节点上,而不是直接绑定在某个元素上;
Delegate( )采用了事件委托的概念,不是直接为子元素绑定事件,而是为其父元素(或祖先元素也可)绑定事件,当在div内任意元素上点击时,事件会一层层从event target向上冒泡,直至到达你为其绑定事件的元素;
on( )方法可以绑定动态添加到页面元素的事件,on()方法绑定事件可以提升效率;
28.Jq中如何将一个jq对象转化为dom对象?
方法一:
jQuery对象是一个数据对象,可以通过[index]的方法,来得到相应的DOM对象。
如:var $v =$(“#v”) ; //jQuery对象
var v=$v[0]; //DOM对象
alert(v.checked) //检测这个checkbox是否被选中方法二:
jQuery本身提供,通过.get(index)方法,得到相应的DOM对象
如:var $v=$(“#v”); //jQuery对象
var v=$v.get(0); //DOM对象
alert(v.checked) //检测这个checkbox是否被选中
29.Jq中有几种选择器?分别是什么?
层叠选择器、基本过滤选择器、内容过滤选择器、可视化过滤选择器、属性过滤选择器、子元素过滤选择器、表单元素选择器、表单元素过滤选择器
30.Jq中怎么样编写插件?
//第一种是类级别的插件开发:
//1.1 添加一个新的全局函数 添加一个全局函数,我们只需如下定义:
jQuery.foo = function() {
alert(‘This is a test. This is only a test.’); };
//1.2 增加多个全局函数 添加多个全局函数,可采用如下定义:
jQuery.foo = function() {
alert(‘This is a test. This is only a test.’); };
jQuery.bar = function(param) {
alert(‘This function takes a parameter, which is “‘ + param + ‘“.’); }; 调用时和一个函数的一样的:jQuery.foo();jQuery.bar();或者$.foo();$.bar(‘bar’);
//1.3 使用jQuery.extend(object);
jQuery.extend({
foo: function() {
alert(‘This is a test. This is only a test.’);
},
bar: function(param) {
alert(‘This function takes a parameter, which is “‘ + param +‘“.’);
}
});
//1.4 使用命名空间
// 虽然在jQuery命名空间中,我们禁止使用了大量的javaScript函数名和变量名。
// 但是仍然不可避免某些函数或变量名将于其他jQuery插件冲突,因此我们习惯将一些方法
// 封装到另一个自定义的命名空间。
jQuery.myPlugin = {
foo:function() {
alert(‘This is a test. This is only a test.’);
},
bar:function(param) {
alert(‘This function takes a parameter, which is “‘ + param + ‘“.’);
}
};
//采用命名空间的函数仍然是全局函数,调用时采用的方法:
$.myPlugin.foo();
$.myPlugin.bar(‘baz’);
//通过这个技巧(使用独立的插件名),我们可以避免命名空间内函数的冲突。
//第二种是对象级别的插件开发
//形式1:
(function($){
$.fn.extend({
pluginName:function(opt,callback){
// Our plugin implementation code goes here.
}
})
})(jQuery);
//形式2:
(function($) {
$.fn.pluginName = function() {
// Our plugin implementation code goes here.
};
})(jQuery);
//形参是$,函数定义完成之后,把jQuery这个实参传递进去.立即调用执行。
//这样的好处是,我们在写jQuery插件时,也可以使用$这个别名,而不会与prototype引起冲突
31.$(‘div+.ab’)和$(‘.ab+div’) 哪个效率高?
$(‘div+.ab’)效率高
32.$.map和$.each有什么区别
map()方法主要用来遍历操作数组和对象,会返回一个新的数组。$.map()方法适用于将数组或对象每个项目新阵列映射到一个新数组的函数;
each()主要用于遍历jquery对象,返回的是原来的数组,并不会新创建一个数组。
33.编写一个 getElementsByClassName 封装函数?
<body>
<input type=“submit” id = “sub” class=“ss confirm btn” value=“提交”/>
<script> window.onload = function(){
//方法一
var Opt = document.getElementById(‘sub’);
var getClass = function(className,tagName){
if(document.getElementsByTagName){
var Inp = document.getElementsByTagName(tagName);
for(var i=0; i<Inp.length; i++){
if((new RegExp(‘(\s|^)’ +className +‘(\s|$)’)).test(Inp[i].className)){
return Inp[i];
}
}
}else if(document.getElementsByClassName){
return document.getElementsByClassName(className);
}
}
//方法二
var aa = getClass(“confirm”, “input”);
function getClass(className, targetName){
var ele = [];
var all = document.getElementsByTagName(targetName || ““);
for(var i=0; i<all.length; i++){
if(all[i].className.match(new RegExp(‘(\s|^)’+confirm+‘(\s|$)’))){
ele[ele.length] = all[i];
}
}
return ele;
}
//方法三
function getObjsByClass(tagName, className){
if(document.getElementsByClassName){
alert(“document.getElementsByClassName”);
return document.getElementsByClassName(className);
}else{
var el = [];
var _el = document.getElementsByTagName(tagName);
for(var i=0; i<_el.length; i++){
if(_el[i].className.indexOf(className) > -1){
alert(_el[i]);
el[_el.length] = _el[i];
}
}
alert(el);
return el;
}
}
}
</script>
</body>
34.简述下工作流程
我在之前的公司工作流程大概是这样的:公司定稿会结束以后,会进行简单的技术研讨,然后我们前端会进行先期的技术准备。前端切图人员会进行psd设计稿切图,并且将css文件进行整合。我们主要编写JS部分,其中包括搭建前端框架(大项目),编写js业务和数据持久化操作,我们也会编写js插件并且进行封装方便使用,还有就是编写JS前端组建和JS测试单元,最后将完成的JS部分与切图人员提供的HTML页面进行整合。最后对完成的页面进行功能测试、页面兼容、产品还原。然后对产品进行封存,提交测试。如果出现BUG会返回给我们开发人员进行修改,再提交测试,最后测试成功,进行版本封存。等到程序全部上线的时候进行线上测试。
*35.一般使用什么版本控制工具?svn如何对文件加锁
svn加锁目的:为了避免多个人同一时间对同一个文件改动的相互覆盖,版本控制系统就必须有一套冲突处理机制。svn加锁两种策略:乐观加锁:所有签出的文件都是可读写的,对文件的修改不必获得文件的锁,当你修改完文件签入时,会首先要求你更新本地文件,版本控制系统不会覆盖你的本地修改,而是会让你自己合并冲突后签入。
严格加锁:所有签出的文件都是只读的,任何对文件的修改必须要获得文件的锁,如果其他人没有拥有该文件的锁,那么版本控制系统就会授权给你文件的锁,并将文件设置为可编辑的。
svn两种加锁步骤:乐观加锁:选择你想要获取锁定的文件,然后右键菜单点击TortoiseSVN 选取获取锁定。
严格加锁:在想要采取严格加锁的文件或目录上点击右键,使用TortoiseSVN 属性菜单,点击新建属性,选择需要锁定。
36. git 和 svn的区别?
SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了。Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
37. jquery和zepto有什么区别?
1.针对移动端程序,Zepto有一些基本的触摸事件可以用来做触摸屏交互(tap事件、swipe事件),Zepto是不支持IE浏览器的,这不是Zepto的开发者Thomas Fucks在跨浏览器问题上犯了迷糊,而是经过了认真考虑后为了降低文件尺寸而做出的决定,就像jQuery的团队在2.0版中不再支持旧版的IE(6 7 8)一样。因为Zepto使用jQuery句法,所以它在文档中建议把jQuery作为IE上的后备库。那样程序仍能在IE中,而其他浏览器则能享受到Zepto在文件大小上的优势,然而它们两个的API不是完全兼容的,所以使用这种方法时一定要小心,并要做充分的测试。2.Dom操作的区别:添加id时jQuery不会生效而Zepto会生效。
3.zepto主要用在移动设备上,只支持较新的浏览器,好处是代码量比较小,性能也较好。
jquery主要是兼容性好,可以跑在各种pc,移动上,好处是兼容各种浏览器,缺点是代码量大,同时考虑兼容,性能也不够好。
38. $(function(){})和window.onload 和 $(document).ready(function(){})
window.onload:用于当页面的所有元素,包括外部引用文件,图片等都加载完毕时运行函数内的函数。load方法只能执行一次,如果在js文件里写了多个,只能执行最后一个。$(document).ready(function(){})和$(function(){})都是用于当页面的标准DOM元素被解析成DOM树后就执行内部函数。这个函数是可以在js文件里多次编写的,对于多人共同编写的js就有很大的优势,因为所有行为函数都会执行到。而且$(document).ready()函数在HMTL结构加载完后就可以执行,不需要等大型文件加载或者不存在的连接等耗时工作完成才执行,效率高。
39. Jq中 attr 和 prop 有什么区别
对于HTML元素本身就带有的固有属性,在处理时,使用prop方法。
对于HTML元素我们自己自定义的DOM属性,在处理时,使用attr方法。
40. 简述下 this 和定义属性和方法的时候有什么区别?Prototype?
this表示当前对象,如果在全局作用范围内使用this,则指代当前页面对象window; 如果在函数中使用this,则this指代什么是根据运行时此函数在什么对象上被调用。 我们还可以使用apply和call两个全局方法来改变函数中this的具体指向。prototype本质上还是一个JavaScript对象。 并且每个函数都有一个默认的prototype属性。
在prototype上定义的属性方法为所有实例共享,所有实例皆引用到同一个对象,单一实例对原型上的属性进行修改,也会影响到所有其他实例。
41. 什么是预编译语音|预编译处理器?
Sass是一种CSS预处理器语言,通过编程方式生成CSS代码。因为可编程,所以操控灵活性自由度高,方便实现一些直接编写CSS代码较困难的代码。同时,因为Sass是生成CSS的语言,所以写出来的Sass文件是不能直接用的,必须经过编译器编译成CSS文件才能使用。
CSS 预处理器是一种语言用来为 CSS 增加一些编程的的特性,无需考虑浏览器的兼容性问题,例如你可以在 CSS 中使用变量、简单的程序逻辑、函数等等在编程语言中的一些基本技巧,可以让你的 CSS 更见简洁,适应性更强,代码更直观等诸多好处。最常用的css预处理器有sass、less css、 stylus。
42.ajax 和 jsonp ?
ajax和jsonp的区别:
相同点:都是请求一个url
不同点:ajax的核心是通过xmlHttpRequest获取内容
jsonp的核心则是动态添加
