INTERVIEW
@code-char:"```"
code:before,code:after{
concent:@code-char;
background:red;
}
- JavaScript的typeof返回的数据类型
- object number function boolean underfind string
typeof isNaN => function
- object number function boolean underfind string
- javascript的数据类型
- 5种基本数据类型: string、number、boolean、null、undefined
- 1种复杂类型:object (复杂的键控集合) 属性的容器,属性值除undefined
- object包括: Object、Function、String、Number、Boolean、Array、Regxp、Date、Globle、Math、Error以及宿主环境提供的Object类型
- 检测数组的方式
- Array.isArray(arr); -----// es5
if(typeof Array.isArray==="undefined"){ Array.isArray = function(arg){ return Object.prototype.toString.call(arg)==="[object Array]"; }; };
- toString.call(arr); -----// ”[object Array]”
- arr.constructor; -----// function Array() { [native code] };
- arr instanceof Array; -----// 判断是否是某个构造函数的实例
- 事件流
- DOM事件流: 事件捕获阶段 =>目标元素阶段=>事件冒泡阶段
- 传统事件绑定:不支持事件流;绑定多次前面的被覆盖
- w3c:addEventListener/attachEvent
- 事件冒泡:事件开始由最具体的元素接受,然后逐级向上传播
- 事件捕捉:事件由最不具体的节点先接收,然后逐级向下,一直到最具体的
- DOM事件流: 事件捕获阶段 =>目标元素阶段=>事件冒泡阶段
- Javascript创建对象的几种方式
- 1.对象字面量、Object构造函数
- 2.纯构造函数
- 3.空构造函数+原型
- 4.混合构造函数+原型
- 5.动态原型
- 6.寄生构造函数
- 7.Object.create() -----// ES5 ie9+
寄生构造函数[^1]
[^1]:——其实是工厂模式的变种,只不过是放在其他构造函数中创建对象
function SpecialArray(){
var values = [];
values.push.apply(values, arguments);
values.toPipedString = function(){
return this.join("|");
};
return values;
}
var colors = new SpecialArray("red", "blue", "green");
alert(colors.toPipedString()); //"red|blue|green"
- 构造函数继承和原型链继承有什么区别
- 在原型中的方法消耗的内存更小,因为在内存中原型只有一个,其中的方法可以被所有的实例共享,实例化的时候并不会在内存中在复制一份,而构造函数中的方法每次都要再复制一份
- 构造函数中定义的属性和方法要比原型中的优先级高,如果定义了同名称的属性和方法,构造函数中的方法将会覆盖原型中的方法
- 如何阻止事件冒泡和默认事件
- e. stopPropagation(); -----// 标准浏览器阻止事件冒泡
- event.canceBubble=true; -----// ie9之前
- 弹出索引
// 方式一、事件对象
for(var i = 0; i < dom.length; i++) {
dom[i].onclick = function(e) {
var e = window.e || e;
var target = e.target || e.srcElement;
return target;
};
};
// 方式二、闭包实现
for(var i = 0; i < dom.length; i++) {
dom[i].onclick = (function (index) {
return function () {
return index;
};
})(i);
}
- 编写一个数组去重的方法
- 法一、
- 先创建一个空数组,用来保存最终的结果
- 循环原数组中的每个元素
- 再对每个元素进行二次循环,判断是否有与之相同的元素,如果没有,将把这个元素放到新数组中
- 返回这个新数组
- 法二、数组的indexOf()方法返回给定元素能找在数组中找到的第一个索引值,否则返回-1。
- 法一、
var removeMore = function(arr) {
var newArr = [];
for(var i = 0; i < arr.length; i++) //遍历当前数组
{
//如果当前数组的第i已经保存进了临时数组,那么跳过,
//否则把当前项push到临时数组里面
if (newArr.indexOf(arr[i]) === -1) newArr.push(arr[i]);
}
return newArr;
};
var arr = [1,3,3,4,6,0,8,6];
//方法1
function unqiue(arr){
var json = {};
var result = [];
for(var i=0;i
- 深度克隆的方法
var json = {a:6,b:4,c:[1,2,3]};
function clone(obj){
var oNew = new obj.constructor(obj.valueOf());
if(obj.constructor === Object){
for(var i in obj){
oNew[i] = obj[i];
// 递归调用
if(typeof(oNew[i]) === 'object'){
clone(oNew[i]);
}
}
}
return oNew;
}
- 数组嵌套对象的排序
// 将arr按age属性降序排列
var arr = [
{"name": "wang","age": 18},
{"name": "liu","age": 34},
{"name": "wu","age": 57},
{"name": "qiu","age": 9},
{"name": "lie","age": 14}
];
// 1.冒泡排序法
function sequence(arr) {
for(var i = 0; i < arr.length; i++) {
for(var j = 0; j < arr.length; j++) {
if(arr[i].age < arr[j].age) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
};
};
return arr;
};
// 2.数组的**sort**方法
function sequence(arr) {
var down = function(x,y) {
return (x.age < y.age) ? 1 : -1;
};
arr.sort(down);
return arr;
}
// 多属性(键值)排序
var sequence = function(name,minor) {
return function (o,p) {
var a,b;
if(o && p && typeof o === 'object' && typeof p === 'object') {
a = o[name];
b = p[name];
if(a === b) {
return typeof minor === 'function' ? minor(o,p) : 0;
}
if(typeof a === typeof b) {
return a < b ? 1 : -1;
}
return typeof a < typeof b ? -1 : 1;
} else {
throw {
name : 'error';
};
}
};
};
- while方式获取页面中所有的checkbox
var domList = document.getElementsByTagName(‘input’);
var checkBoxList = [];//返回的所有的checkbox
var len = domList.length; //缓存到局部变量
while (len--) {
if (domList[len].type === ‘checkbox’) {
checkBoxList.push(domList[len]);
}
};
- undefined会在以下三种情况下产生:
- 一个变量定义了却没有被赋值
- 想要获取一个对象上不存在的属性或者方法
- 一个数组中没有被赋值的元素
- 将字符串提取成json格式内容
var url="http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx";
var str=url.substr(url.indexOf("?")+1);
var arr=str.split('&');
var obj={};
for (var i = 0; i < arr.length; i++) {
var arri = arr[i]; //a=1
var i2=arri.split("=");//["a","1"]
obj[i2[0]]=i2[1]; //obj["a"]="1";
};
- 求一个字符串的字节长度
function countByts(str) {
if(!arguments.length || !s) return null;
if("" === s) return 0;
var len = 0;
for(var i = 0; i < str.length; i++) {
if(str.charCodeAt(i) > 255) len += 2;
else len++;
};
return len;
}
- trim函数
if (!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+/, "").replace(/\s+$/,"");//\s匹配空白字符:回车、换行、制表符tab 空格
}
}
// test the function
var str = " \t\n test string ".trim();
alert(str == "test string"); // alerts "true"
- Javascript中callee和caller的作用?
- arguments.callee:获得当前函数的引用;callee是返回正在被执行的function函数,也就是所指定的function对象的正文(自定义的函数 fun)。
- caller是返回一个对函数的引用,该函数调用了当前函数;如果不是由其他函数调用的,那么返回值就是null
function fn(){
console.log(arguments.callee==fn); // true
console.log(fn.caller); // fn2
}
function fn2(){
fn(); //此时fn.caller就指向了fn2这个函数
}
fn2();
- 浏览器对象模型BOM里常用的至少4个对象,window对象的常用方法至少5个
- 对象:window document location screen history navigator
- 方法:alert() confirm() prompt() open() close()
- 查询字符串
- window.location.search 返回值:?name=wang&id=mysql (问号后面的字符串)
- window.location.hash 返回值:#age (锚点及之后的字符串)
- window.location.reload() 刷新当前页面
- BOM对象 window对象
- window对象,是JS的最顶层对象,其他的BOM对象都是window对象的属性;
- document对象,文档对象;
- location对象,浏览器当前URL信息;
- navigator对象,浏览器本身信息;
- screen对象,客户端屏幕信息;
- history对象,浏览器访问历史信息;
- bind(), live(), delegate()的区别
- bind: 绑定事件,对新添加的事件不起作用(不支持动态添加),方法用于将一个处理程序附加到每个匹配元素的事件上并返回jQuery对象。
- live: 方法将一个事件处理程序附加到与当前选择器匹配的所有元素(包含现有的或将来添加的)的指定事件上并返回jQuery对象。
- delegate: 方法基于一组特定的根元素将处理程序附加到匹配选择器的所有元素(现有的或将来的)的一个或多个事件上。
- 简述link和import的区别?
- link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS。
- link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载。
- link是XHTML标签,无兼容问题;@import是在CSS2.1提出的,低版本的浏览器不支持。
- link支持使用Javascript控制DOM去改变样式;而@import不支持。
- 原生方式转换URL的search为json对象
var getJson = function(str) {
var item;
var result = [];
// 只有一个键值对
if(search.indexOf("&") < 0) {
item = str.splite('=');
result[item[0]] = item[1];
}
// 多个键值对,以&符分开
else{
var splitArr = str.split('&');
for(var i = 0; i < splitArr.length; i++){
item = splitArr[i].split('=');
result[item[0]] = item[1];
};
}
return result;
}
- readyonly和disable的区别
- readonly只针对input(text / password)和textarea有效,
- 而disabled对于所有的表单元素都有效,当表单元素在使用了disabled后,当我们将表单以POST或GET的方式提交的话,这个元素的值不会被传递出去,而readonly会将该值传递出去
- ajax的工作原理
- Ajax通过XMLHttpRequest对象来向服务器发起异步请求,从服务器获取数据,然后用JavaScript来操作DOM元素而更新页面,也就是JavaScript可以及时向服务器提出请求和处理相应,而不阻塞后续代码的执行,达到无刷新页面就可以请求的效果。XMLHttpRequest是Ajax的核心机制。
- ajax是多种技术组合起来的一种浏览器和服务器交互技术,基本思想是允许一个互联网浏览器向一个远程页面/服务做异步的http调用,并且用接收的数据来局部更新当前页面
- ajax交互模型:
- 同步:脚本会停留并等待服务器响应然后继续
异步:脚本允许页面继续其进程并处理可能的回复
- 同步ajax有什么影响
- 异步加载js的方案
- defer:只支持ie
- async:
- 动态加载script标签,加载完了回调
/* 异步加载script方案 */ function loadSctipt (url,callback) { var script = document.createElement('script'); script.type = "text/Javascript"; if(script.readyState) { // 兼容IE浏览器 script.onreadystatechange = function () { if(script.readyState === 'loaded' || script.readyState === 'complete') { script.onreadystatechange = null; callback(); } }; } else { // 其他浏览器 script.onload = function() { callback(); }; } script.src = url; document.body.appendChild(script); };
- ajax请求(请求和响应)
- 1.请求行:
xhr.open('get','index.php');
(get可以不设置) - 2.请求头:
xhr.setRequestHeader('ContentType',text/html);
===>告诉浏览器以何种方式解析 - 3.请求主体:
xhr.send(null);
- 1.获取行状态(包括状态码&状态信息):
xhr.status & xhr.statusText
- 2.获取响应头
- 获取指定头信息:
xhr.getRequestHeader('Content-Type');
- 获取所有响应头信息:
xhr.getAllRequestHeaders();
- 获取指定头信息:
- 3.响应主体:
xhr.responseText; || xhr.responseXML;
- 1.请求行:
// 创建一个xhr实例
var xhr = new XMLHttpRequest();
// 发起http请求
xhr.open('get','index.php');
xhr.send(null);
// 接收服务器响应
xhr.onreadystatechange = function () {
if(xhr.readyState === 4 && xhr.status === 200) {
// 接收到结果
var result = xhr.responseText;
}
};
- javascript的同源策略[^2]
- 协议:http,ftp https
- 主机名;localhost 127.0.0.1
- 端口名:80:
- http协议的默认端口:80
- https:协议的默认端口是8083
- 同源策略带来的麻烦:ajax在不同域名下的请求无法实现;如果说想要请求其他来源的js文件,或者json数据,那么可以通过jsonp来解决
[^2]:一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合
- 跨域解决方案
- 顶级域名相同的可以通过domain.name来解决,即同时设置domain.name = 顶级域名
- document.domain + iframe
- window.name + iframe
- location.hash + iframe
- window.postMessage()
参考资料:(http://rickgray.me/2015/09/03/solutions-to-cross-domain-in-browser.html) - JSONP ---- JSON with Padding(只能以GET方式请求)
- 原理:其本质是利用了标签具有可跨域的特性,由服务端返回一个预先定义好的Javascript函数的调用,并且将服务器数据以该函数参数的形式传递过来,此方法需要前后端配合完成。
- jsonp跨区解决
- img等标签:支持数据发送,不能拿到服务端数据
- link标签:link[ref="stylesheet"]
- script:
var script = document.createElement('script'); script.src = 'http://localhost:3000/?start=1&count=10'; // 服务端地址 document.body.appendChild(script); // 发送请求 /* 由于脚本执行完成过后才能拿到数据 */ // 1. script.addEventListener('load',function(){ result = data; }); // 2.被动的方式 function callback(data) { result = data; };
- HTTP状态消息
- 200:请求已成功,请求所希望的响应头或数据体将随此响应返回。
- 302:请求的资源临时从不同的 URI响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的
- 304:如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。304响应禁止包含消息体,因此始终以消息头后的第一个空行结尾。
- 403:服务器已经理解请求,但是拒绝执行它。
- 404:请求失败,请求所希望得到的资源未被在服务器上发现。
- 500:服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器端的源代码出现错误时出现。
- js数组类型中的常用方法
方法 | 描述 |
---|---|
concat() | 连接两个或更多的数组,并返回结果。 |
join() | 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。 |
pop() | 删除并返回数组的最后一个元素。 |
push() | 向数组的末尾添加一个或更多元素,并返回新的长度。 |
shift() | 删除并返回数组的第一个元素 |
unshift() | 向数组的开头添加一个或更多元素,并返回新的长度。 |
slice() | 从某个已有的数组返回选定的元素 |
reverse() | 颠倒数组中元素的顺序。 |
sort() | 对数组的元素进行排序 |
splice() | 删除元素,并向数组添加新元素。 |
toSource() | 返回该对象的源代码。 |
toString() | 把数组转换为字符串,并返回结果。 |
toLocaleString() | 把数组转换为本地数组,并返回结果。 |
valueOf() | 返回数组对象的原始值 |
- Array.prototype.slice.call(fakeArray)将数组转化为真正的Array对象
- 运算符遇上未定义的变量
- 如果其中一个数是NaN,则结果就是NaN
- 如果乘积超过了ECMAScript设定的范围,那么就会返回Infinity、-Infinity
- 如果参与乘法运算的某个操作数不是数值,js引擎会先调用Number()将这个数变成一个数值类型,
- POST请求使用的情形
- 无法使用缓存文件(更新服务器上的文件或数据库)
- 向服务器发送大量数据(POST 没有数据量限制)
- 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
- 严格模式
- 全局变量显式声明;静态绑定;禁止使用with语句;eval中定义的变量都是局部变量
- 禁止this关键字指向全局对象;禁止在函数内部遍历调用栈 arguments.callee
- 严格模式下无法删除变量。只有configurable设置为true的对象属性,才能被删除
- 正常模式下,对一个对象的只读属性进行赋值,不会报错,只会默默地失败。严格模式下,将报错。
- 严格模式下,对一个使用getter方法读取的属性进行赋值,会报错。
- 严格模式下,对禁止扩展的对象添加新属性,会报错。
- 严格模式下,删除一个不可删除的属性,会报错。
- 正常模式下,如果对象有多个重名属性,最后赋值的那个属性会覆盖前面的值。严格模式下,这属于语法错误。
- 正常模式下,如果函数有多个重名的参数,可以用arguments[i]读取。严格模式下,这属于语法错误。
- 正常模式下,整数的第一位如果是0,表示这是八进制数,比如0100等于十进制的64。严格模式禁止这种表示法,整数第一位为0,将报错。
- 不允许对arguments赋值
- arguments不再追踪参数的变化
- 严格模式只允许在全局作用域或函数作用域的顶层声明函数。也就是说,不允许在非函数的代码块内声明函数;if else while for 无法声明函数
- 严格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。
- new 操作符的作用
- 1、创建一个空对象,并且 this变量引用该对象,同时还继承了该函数的原型。
- 2、属性和方法被加入到 this 引用的对象中。
- 3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。
- 模块化开发
- 模块化开发模式:浏览器端requirejs,seajs;服务器端node.js;ES6模块化;fis、webpack等前端整体模块化解决方案;grunt、gulp等前端工作流的使用
- 何检测一个变量是一个String类型
- typeof str
- str.constructor
- toString.call()
- 渐进增强和优雅降级之间的不同
- 优雅降级: (graceful degradation,一开始就构建站点的完整功能,然后针对浏览器测试和修复)
- 渐进增强: (progressive enhancement,一开始只构建站点的最少特性,然后不断针对各浏览器追加功能)
- “优雅降级”和“渐进增强”都关注于同一网站在不同设备里不同浏览器下的表现程度。关键的区别则在于它们各自关注于何处,以及这种关注如何影响工作的流程。
- 什么是FOUC?你如何来避免FOUC?
- 由于css引入使用了@import 或者存在多个style标签以及css文件在页面底部引入使得css文件加载在html之后导致页面闪烁、花屏,用link加载css文件,放在head标签里面
- 前端页面的构成
- html结构层:为页面搭建框架
- css样式层:修饰页面
- js交互层:利用脚本代码为页面增加动态效果与交互
- HTML5新添加的标签
- 音频、视频、拖放、画布、SVG、地理定位、应用缓存、表单元素