1.谈一谈JavaScript作用域链
- 当执行一段JavaScript代码(全局代码或函数)时,JavaScript引擎会创建一个作用域又称为执行上下文(Execution Context),在页面加载后会首先创建一个全局的作用域,然后每执行一个函数,会建立一个对应的作用域,从而形成一条作用域链。每个作用域都有一条对应的作用域链,链头是全局作用域,链尾是当前函数作用域。
- 作用域链的作用是用于解析标识符,当函数被创建时(不是执行),会将this,arguments,命名参数和该函数中所有局部变量添加到该当前作用域中,当JavaScript需要查找变量X的时候(这个过程称为变量解析),它首先会从作用域链中的链尾也就是当前作用域进行查找是否有X属性,如果没有找到就顺着作用域链继续查找,直到查找到链头,也就是全局作用域链,仍未找到该变量的话,就认为这段代码的作用域上不存在x变量,并抛出引用错误(ReferenceError)的异常。
2.如何理解JavaScript原型链
- JavaScript中每个对象都有一个prototype属性,我们称之为原型,而原型的值也是一个对象,因此它也有自己的原型,这样就串联起来了一条原型链,原型链的链头是object,它的prototype比较特殊,值为null。
- 原型链的作用是用于对象继承,函数A的原型属性(prototype property)是一个对象,当这个函数被用作函数来创建实例时,该函数的原型属性被作为原型赋值给所有对象实例,比如我们新建一个数组,数组的方法便从数组的原型上继承而来。
- 当访问对象的一个属性时,首先查找对象本身,找到则返回;未找到则继续查找原型对象的属性(如果还找不到实际上还会沿着原型链向上查找,直至到根)。只要没有被覆盖的话,对象原型的属性就能在所有的实例中找到,若整个原型链未找到则返回undefined。
3.JavaScript原型,原形链?有什么特点?
- 原型对象也是普通的对象,是对象一个自带隐式__proto__属性,原型也有可能有自己的原型,如果一个原型对象的原型为null的话,我们就称为原型链。
- 原形链是由一些用来继承和共享属性的对象组成的(有限的)对象链。
4.如何查找构造函数和原型中的属性?
- 构造函数.prototype 查看构造函数的原型属性
- 实例对象 .__proto__查看实例对象的构造函数的原型
- 实例对象.proto.constructor查看实例对象的构造函数
5.JavaScript如何实现继承?
- 构造继承
- 原型继承
- 实例继承
- 拷贝继承
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式
function Parent(){
this.name = 'wang';
}
function Child(){
this.age = 28;
}
Child.prototype = new Parent();//继承了Parent,通过原型
var demo = new Child();
alert(demo.age); //子类中的属性
alert(demo.name);//得到被继承的属性
|
6.JavaScript如何实现继承?
1. 借用构造函数。也叫伪造对象或经典继承。
- 思路:在子类构造函数的内部调用超类型构造函数。可以通过使用apply()和call()方法在新创建的对象上执行构造函数。
- 缺点:方法都在构造函数中定义,函数的复用就无从谈起。在超类型的原型中定义的方法,对子类而言也是不可见的,结果所有的类型都只能使用构造函数模式。
1
2
3
4
5
6
7
8
9
10
11
|
function SuperType() {
this.colors = ["red","blue","green"];
}
function SubType() {
SuperType.call(this); //继承了SuperType
}
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); //"red","blue","green","black"
var instance2 = new SubType();
console.log(instance2.colors); //"red","blue","green"
|
2. 原型链继承
- 思路:借助原型可以基于已有的对象创建对象,同时还不必因此创建自定义类型
- 在object()函数内部,先创建一个临时的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例==原型链继承的思想可用以下函数来说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
function object(o) {
function F(){}
F.prototype = o;
return new F();
}
//例子
var person = {
name:"EvanChen",
friends:["Shelby","Court","Van"];
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
console.log(person.friends);//"Shelby","Court","Van","Rob","Barbie"
|
3.组合继承
- 指的是将原型链和借用构造函数的技术组合在一起,从而发挥二者之长。
- 思路:使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现实例属性的继承
- 优点:即通过在原型上定义发法实现了函数复用,又能保证每一个实例都有它自己的数组。
- 组合继承避免了原型链和借用构造函数的缺陷。融合了他们的优点。成为JavaScript中常用的继承模式
例子
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
|
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this,name);//继承属性
this.age = age;
}
//继承方法
SubType.prototype = new SuperType();
Subtype.prototype.constructor = Subtype;
Subtype.prototype.sayAge = function() {
console.log(this.age);
}
var instance1 = new SubType("EvanChen",18);
instance1.colors.push("black");
consol.log(instance1.colors);//"red","blue","green","black"
instance1.sayName(); //"EvanChen"
instance1.sayAge(); //18
var instance2 = new SubType("EvanChen666",20);
console.log(instance2.colors);//"red","blue","green"
instance2.sayName(); //"EvanChen666"
instance2.sayAge(); //20
|
4.寄生式继承
- 思路:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有的工作一样返回对象
例子
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function createAnother(original) {
var clone = object(original); //通过调用函数创建一个新对象
clone.sayHi = function () { //以某种方式来增强这个对象
alert("hi");
};
return clone; //返回这个对象
}
var person = {
name:"EvanChen",
friends:["Shelby","Court","Van"];
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi();///"hi"
|
5.寄生组合式继承。
- 思路:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法
- 本质上,就是寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型
基本模型如下所示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
function inheritProperty(subType, superType) {
var prototype = object(superType.prototype);//创建对象
prototype.constructor = subType;//增强对象
subType.prototype = prototype;//指定对象
}
//例子
function SuperType(name){
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function (){
alert(this.name);
};
function SubType(name,age){
SuperType.call(this,name);
this.age = age;
}
inheritProperty(SubType,SuperType);
SubType.prototype.sayAge = function() {
alert(this.age);
}
|
- 原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式
1
2
3
4
5
6
7
8
9
10
11
12
|
function Parent(){
this.name = 'wang';
}
function Child(){
this.age = 28;
}
Child.prototype = new Parent();//继承了Parent,通过原型
var demo = new Child();
alert(demo.age);
alert(demo.name);//得到被继承的属性
|
7.数组去重
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function uniq(array){
var temp = []; //一个新的临时数组
for(var i = 0; i < array.length; i++){
if(temp.indexOf(array[i]) == -1){
temp.push(array[i]);
}
}
return temp;
}
var aa = [1,2,2,4,9,6,7,5,2,3,5,6,5];
console.log(aa)
console.log(uniq(aa))
|
7.面向对象和类的区别?
- 简单的说类是对象的模板。
- 在js中没有类,所以在js中所谓的类就是构造函数,对象就是有构造函数创建出来的实例对象。面向对象就是使用面向对象的方式处理问题,面向对象是向过程进行封装。
- 对象的概念,面向对象编程的程序实际就是多个对象的集合,我们可以把所有的事物都抽象成对象,在程序设计中可以看作:对象=属性+方法。属性就是对象的数据,而方法就是对象的行为
- 类的概念,类是对象的模板,而对象是类的实例化。举个例子,汽车设计图可以看作是类,而具体的汽车就是对象。再比如有一个类是表示人,然后可以通过人这个模板来实例化出张三,李四…
8.面向对象有三大特性
- 抽象性,需要通过核心数据和特定环境才能描述对象的具体意义
- 封装性,封装就是讲数据和功能组合到一起,在js中对象就是键值对的集合,对象将属性和方法封装起来,方法将过程封装起来
- 继承性,将别人的属性的方法成为自己的,传统继承基于模板(类),js中继承基于构造函数
9.new操作符具体干了什么呢?
- 创建了一个空对象,并且this变量引用该对象,同时还继承了该函数的原型。
- 属性和方法被加入到this引用的对象中。
- 新创建的对象由this所引用,并且最后隐式的返回this。
1
2
3
|
var obj={};
obj.__proto__=Base.prototype;
Base.call(obj);
|
10.JavaScript的基本数据类型
- object number function boolean undefined null
11.js有哪些内置对象
- 数据封装类对象:Object、Array、Boolean、Number、String
- 其他对象:Function、Arguments、Math、Date、RegExp、Error
12.GET和POST的区别,何时使用POST?
- GET:一般用于信息获取,使用URL传递参数,对发送信息的数量也有限制,一般在2000个字符
- POST:一般用于修改服务器上的资源,对发送的信息没有限制
- GET方式需要使用Request.QueryString来获取变量的值,而POST方式通过Request.Form来获取变量的值,也就是说GET是通过地址栏传值,而Post是通过提交表单来传值。
- 然而,在以下情况中,请使用POST请求:
- 无法使用缓存文件(更新服务器上的文件或数据库)
- 向服务器发送大量数据(POST没有数据量限制)
- 发送包含未知字符的用户输入时,POST比GET更稳定也更可靠
13.Flash、Ajax各自的优缺点,在使用中如何取舍?
- Flash适合处理多媒体,矢量图形、访问机器;对css、处理文本上不足,不容易被搜索。
- Ajax对css、文本支持很好、支持搜索;多媒体、矢量图形、机器访问不足。
- 共同点:与服务器的无刷新传递消息、用户离线和在线状态,操作DOM
14.ajax过程
- 创建XMLHttpRequest对象,也就是创建一个异步调用对象。
- 创建一个新的HTTP请求,并指想向该HTTP请求的方法、URL及验证信息。
- 设置响应HTTP请求状态变化的函数。
- 发送HTTP请求。
- 获取异步调用返回的数据。
- 使用JavaScript和DOM实现局部刷新。
15.js延迟加载的方式有哪些?
defer和async,动态创建DOM方式(用得最多),按需异步载入js
16.如何解决跨越问题?
jsonp,iframe,window.name,window.postMessage
17.在js的计时器运行原理是怎样的,为什么可以触发计时器效果?计时器是多线程吗?
- JavaScript引擎只有一个线程,强迫异步事件排队等待被执行。
- setTimeout和setInterval本质上不同的地方是他们如何执行异步代码的。
- 如果一个定时器正在执行的时候被阻塞了,那么它将会被推迟到下一个可能的执行点,这既是使得延迟时间有可能会超过声明定时器时设置的值。
- Interval如果有足够的时间来执行(大于指定的延迟),那么它将会无延迟的一个紧接着一个执行。
- 原理:
计时器通过设定一定的时间段(毫秒)来异步的执行一段代码。因为JavaScript是一个单线程,计时器提供了一种绕过这种语言限制来执行代码的能力。
- 总结:
计时器是单线程的,需要等待上一个执行完,如果上一个没有执行完,下一个需要延迟执行,直到上一个执行完
18.例举3种强制类型转换和2种隐式类型转换?
- 强制(parseInt,parseFloat,number)
- 隐式(== ===)
19.split() join()的区别
前者是切割成数组的形式,后者是将数组转换成字符串
20.数组方法pop()push()unshift()shift()
- pop()尾部删除
- push()尾部添加
- shift()头部删除
- unshift()头部添加
21.IE和DOM事件流的区别
- 执行顺序不一样,
- 参数不一样、
- 事件加不加on、
- this指向问题
22.ajax请求的时候get和post方式的区别
- 一个在url后面 一个放在虚拟载体里面
- 有大小限制
- 安全问题
- 应用不同:一个是论坛等只需要请求的,一个是类似需改 密码的
23.IE的标准下有哪些兼容性的写法
1
2
3
|
var ev = ev || window.event
var clientWidth = document.documentElement.clientWidth || document.body.clientWidth
var target = ev.srcElement||ev.target
|
24.JavaScript有几种类型的值?你能画一下他们的内存图?
- 栈:原始数据类型(Undefined,null,Boolean,Number,String)
- 堆:引用数据类型(对象,数组和函数)
- 两种类型的区别是:存储位置不同
- 原始类型直接存储在栈(stack)中的简单数据段,占据空间小,大小固定,属于被频繁使用数据,所以放入栈中存储;
- 引用数据类型在堆(heap)中的对象,占据空间大,大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体
25.ajax请求时,如何解释json数据
- 使用eval parse,鉴于安全性考虑,使用parse更靠谱
26.事件委托是什么
让事件利用冒泡的原理,让自己的所触发的事件,让他的父元素代替执行!
27.请说说事件委托机制?这样做有什么好处?
事件委托,就是某个事件本来该自己干的,但是自己不干,交给别人来干,就叫事件委托。
打个比方:一个button对象,本来自己需要监控自身的点击事件,但是自己不来监控这个点击事件,让自己的父节点来监控自己的点击事件。
好处
- 提高性能:例如,当有很多li同时需要注册时间的时候,如果使用传统方法来注册事件的话,需要给每一个li注册事件。然而如果使用委托事件的话,就只需要将事件委托给该一个元素即可。这样就能提高性能
- 新添加的元素还会有之前的事件
28.闭包是什么,有什么特性,对页面有什么影响?简要介绍你理解的闭包
- 闭包就是能够读取其他函数内部变量的函数
- “官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
- 通俗的讲:就是函数a的内部函数b,被函数a外部的一个变量引用的时候,就创建了一个闭包。
- ①.封闭性:外界无法访问闭包内部的数据,如果在闭包内声明变量,外界是无法访问的,除非闭包主动向外界提供访问接口;
- ②.持久性:一般的函数,调用完毕之后,系统自动注销函数,而对于闭包来说,在外部函数被调用之后,闭包结构依然保存在
- 系统中,闭包中的数据依然存在,从而实现对数据的持久使用。
- 优点:
- ① 减少全局变量。
- ② 减少传递函数的参数量
- ③ 封装;
- 缺点:
- 使用闭包会占有内存资源,过多的使用闭包会导致内存溢出等.
29.添加 插入 替换 移除 到某个接点的方法
- obj.appendChild()
- obj.insertBefore()
- obj.replaceChild()
- obj.removeChild()
30.DOM怎样添加、移动、复制、创建和查找节点
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
// 添加、移除、替换、插入
appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子节点前插入一个新的子节点
// 查找
getElementsByTagName() //通过标签名称
getElementsByName()//通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
getElementById() //通过元素Id,唯一性
|
31."==“和”===“的不同
前者会自动转换类型,后者不会
32.请说出==和===的区别?
- ==判断内容是否相等不比较类型
1
|
console.log(1=="1");//true
|
- ===判断内容相等且类型也相等
1
|
console.log(1==="1"); //false
|
33.编写一个b继承a的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function A(name){
this.name = name;
this.sayHello = function() {
alert(this.name + " say Hello!");
};
}
function B(name,id){
this.temp = A;
this.temp(name); //相当于new A();
delete this.temp;
this.id = id;
this.checkId = function(ID){
alert(this.id==ID)
};
}
|
34.如何阻止事件冒泡和默认事件
1
2
3
4
5
6
7
8
9
|
function stopBubble(e){
if (e && e.stopPropagation){
e.stopPropagation()
}
else {
window.event.cancelBubble=true
}
}
return false //阻止默认事件
|
35.什么是事件冒泡/捕获
- 事件冒泡:子元素事件的触发会影响父元素事件
- 开关事件冒泡:
- A. 开启事件冒泡:
element.addEventListener(eventName,handler,false);
- B. 关闭事件冒泡:假设传统方式事件的返回值为e,就可以通过e.stopPropagation()来关闭事件冒泡;
- 事件捕获:父元素的事件会影响子元素的事件;
- 开启事件捕获:
element.addEventListener(eventName,hadler,true)
36.下面程序执行后弹出什么样的结果?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function fn() {
this.a = 0;
this.b = function() {
console.log(this.a)
}
}
fn.prototype = {
b: function() {
this.a = 20;
console.log(this.a);
},
c: function() {
this.a = 30;
console.log(this.a);
}
}
var myfn = new fn();
myfn.b(); // 0
myfn.c(); // 30
|
37.谈谈this对象的理解
- this是js的一个关键字,随着函数使用场合不同,this的值会发生变化。
- 但是有一个总原则,那就是this指的是调用函数的那个对象。
- this一般情况下:是全局对象Global。作为方法调用,那么this就是指这个对象
38. this对象的理解
- this总是指向函数的直接调用者(而非间接调用者);
- 如果有new关键字,this指向new出来的那个对象;
- 在事件中,this指向触发这个事件的对象,特殊的是,IE中attachEcent中this总是指向全局对象Window;
39. this对象的理解
- this是一个关键字,它代表函数运行时,自动生成一个内部对象,只能在函数内部使用
- 作为纯粹的函数调用this指向全局对象
- 作为对象的方法调用this指向调用对象
- 作为构造函数被调用this指向新的对象(new会改变this的指向)
- apply调用this指向apply方法的第一个参数
- this总是指向函数的直接调用者(而并非间接调用者);
- 如果有new关键字,this指向new出来的那个对象;
- 在事件中,this指向这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window;
40.下面程序的结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
function fun(n,o) {
console.log(o)
return {
fun:function(m){
return fun(m,n);
}
};
}
var a = fun(0);
a.fun(1);
a.fun(2);
a.fun(3);
var b = fun(0).fun(1).fun(2).fun(3);
var c = fun(0).fun(1);
c.fun(2);
c.fun(3);
//答案:
//a: undefined,0,0,0
//b: undefined,0,1,2
//c: undefined,0,1,1
|
41. 下面程序的输出结果
1
2
3
4
5
6
7
8
9
10
11
12
|
var name = 'World!';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
//输出
//Goodbye Jack
|
42.了解Node?Node的使用场景都有哪些?
- 高并发,聊天,实时消息推送
43、介绍下最常用的一款框架
- jQuery, rn, angular等
44. 对于前端自动化构建工具有了解吗?简单介绍一下
- Gulp,Grunt等
45. 说一下什么是JavaScript的同源策略?
一段脚本只能读取来自同一来源的窗口和文档的属性,这里的同一源指的是主机名,协议和端口号的组合
46. eval是指做什么的?
- 它的功能是把对应的字符串解析成JS代码并运行;
- 应该避免使用eval,不安全,非常耗性能(2次、一次解析成js语句,一次执行);
- 由JSON字符串转换为JSON对象的时候可以用eval,val obj=eval(’(’+str+’)')
47.请列举字符串操作的方法?
- chartCodeAt方法返回一个整数,代表指定位置字符的Unicode编码;
- chartAt方法返回指定索引位置处的字符。如果超出有效范围的索引值返回空字符串;
- slice方法返回字符串的片段
- substring方法返回位于String对象中指定位置的子字符串。
- substr方法返回一个从指定位置开始的指定长度的子字符串。
- indexOf方法返回String对象内第一次出现子字符串位置。如果没有找到子字符串。则返回-1;
- lastIndexOf方法返回String对象中字符串最后出现的位置。如果没有匹配到子字符串,则返回-1;
- search方法返回与正则表达式查找内容匹配的第一个字符串的位置;
- concat方法返回字符串值,该值包含了两个或多个提供的字符串的连接;
- split将一个字符串分割为子字符串,然后将结果作为字符串数组返回;
48.什么是window对象?什么是document对象?
- window对象是指浏览器打开的窗口
- document对象是Document对象(HTML文档对象)的一个只读引用,window对象的一个属性。
49.null和undefined的区别?
null是表示"无"的对象,转为数值时为0;
undefined是表示"无"的原始值,转为数值时为NaN。
Q1
- 变量被声明了,但没有赋值,就等于undefined。
调用函数时
- 应该提供的参数没有提供该参数等于undefined。
- 对象没有赋值的属性,该属性的值为undefined.
- 函数没有返回值时,默认返回undefined。
Q2
- 作为函数的参数,表示该函数的参数不是对象
- 作为对象原型链的终点。
50.null,undefined的区别?
- null 表示一个对象是"没有值"的值,也就是值为"空”;
- undefined 表示一个变量声明了没有初始化(赋值);
- undefined不是一个有效的JSON,而null是;
- undefined的类型(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: 不知道(没有被告诉)
51.JSON的了解?
- JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它是基于JavaScript的一个子集。数据格式简单,易于读写,占用带宽小。
- 格式:采用键值对,例如:
{age:12,name:'back'}
- json(JavaScript Object Notation)是一种轻量级的数据交换格式。
- 它是基于JavaScript的一个子集。数据格式简单,易于读写,占用带宽小
如:{"age":"12",""}
- json字符串转换为json对象
1
2
3
|
var obj=eval('('+str+')');
var obj=str.parseJSON();
var obj=JSON.parse(str);
|
- json对象转换为json字符串
1
2
|
var last=obj.toJSONString();
var last=JSON.stringify(obj);
|
52.call()和play()的区别和作用?
- apply()函数有两个参数:第一个参数是上下文,第二个参数是参数组成的数组。
如果上下文是null,则使用全局对象代替。
如:function.apply(thi是,[1,2,3]);
- call()的第一个参数是上下文,后续是实例传入的参数序列。
如:function.call(this,1,2,3);
53.32、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
28
29
30
31
32
33
34
35
36
37
38
39
40
|
// 以下是展示三种方法
// 方法1
Array.prototype.unique1 = function () {
var n = []; //一个新的临时数组
//遍历当前数组
for (var i = 0; i < this.length; i++) {
//如果当前数组的第i已经保存进了临时数组,那么跳过,
//否则把当前项push到临时数组里面
if (n.indexOf(this[i]) == -1) {
n.push(this[i]);
}
}
return n;
}
// 方法2
Array.prototype.unique2 = function() {
var n = {},r=[]; //n为hash表,r为临时数组
//遍历当前数组
for(var i = 0; i < this.length; i++) {
//如果hash表中没有当前项
if (!n[this[i]]) {
n[this[i]] = true; //存入hash表
r.push(this[i]); //把当前数组的当前项push到临时数组里面
}
}
return r;
}
// 方法3
Array.prototype.unique3 = function() {
var n = [this[0]]; //结果数组
//从第二项开始遍历
for(var i = 1; i < this.length; i++) {
//如果当前数组的第i项在当前数组中第一次出现的位置不是i,
//那么表示第i项是重复的,忽略掉。否则存入结果数组
if (this.indexOf(this[i]) == i) {
n.push(this[i]);
}
}
return n;
}
|
54.js操作获取和设置cookie
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
|
//创建cookie
function setCookie(name, value, expires, path, domain, secure) {
var cookieText = encodeURIComponent(name) + '=' + encodeURIComponent(value);
if (expires instanceof Date) {
cookieText += '; expires=' + expires;
}
if (path) {
cookieText += '; expires=' + expires;
}
if (domain) {
cookieText += '; domain=' + domain;
}
if (secure) {
cookieText += '; secure';
}
document.cookie = cookieText;
}
//获取cookie
function getCookie(name) {
var cookieName = encodeURIComponent(name) + '=';
var cookieStart = document.cookie.indexOf(cookieName);
var cookieValue = null;
if (cookieStart > -1) {
var cookieEnd = document.cookie.indexOf(';', cookieStart);
if (cookieEnd == -1) {
cookieEnd = document.cookie.length;
}
cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
}
return cookieValue;
}
//删除cookie
function unsetCookie(name) {
document.cookie = name + "= ; expires=" + new Date(0);
}
|
55.说几条写JavaScript的基本规范?
- 不要在同一行声明多个变量
- 请使用===/!==来比较true/false或者数值
- 使用对象字面量替代new Array这种形式
- 不要使用全局函数
- switch语句必须带有default分支
- If语句必须使用大括号
- for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污
56.什么是闭包
- 闭包就是能够读取其他函数内部变量的函数
- 闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域
- 闭包的特性:
- 函数内再嵌套函数
- 内部函数可以引用外层的参数和变量
- 参数和变量不会被垃圾回收机制回收
- 说说你对闭包的理解
- 使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念
- 闭包 的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中
- 闭包的另一个用处,是封装对象的私有属性和私有方法
- 好处:能够实现封装和缓存等;
- 坏处:就是消耗内存、不正当使用会造成内存溢出的问题
- 使用闭包的注意点
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露
- 解决方法是,在退出函数之前,将不使用的局部变量全部删除
57.说说你对作用域链的理解
- 作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的
- 简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期
58.JavaScript原型,原型链 ? 有什么特点?
- 每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时
- 如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念
- 关系:instance.constructor.prototype = instance.proto
- 特点:
- JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变
- 当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象
59.请解释什么是事件代理
- 事件代理(Event Delegation),又称之为事件委托。
是 JavaScript 中常用绑定事件的常用技巧。
顾名思义,“事件代理”即是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务。
事件代理的原理是DOM元素的事件冒泡。
使用事件代理的好处是可以提高性能
- 可以大量节省内存占用,减少事件注册,比如在table上代理所有td的click事件就非常棒
- 可以实现当新增子对象时无需再次对其绑定
60.Javascript如何实现继承?
- 构造继承
- 原型继承
- 实例继承
- 拷贝继承
- 原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式
1
2
3
4
5
6
7
8
9
10
11
12
13
|
function Parent(){
this.name = 'wang';
}
function Child(){
this.age = 28;
}
Child.prototype = new Parent();//继承了Parent,通过原型
var demo = new Child();
alert(demo.age);
alert(demo.name);//得到被继承的属性
|
51.谈谈This对象的理解
- this总是指向函数的直接调用者(而非间接调用者)
- 如果有new关键字,this指向new出来的那个对象
- 在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window
52.事件模型
- W3C中定义事件的发生经历三个阶段:捕获阶段(capturing)、目标阶段(targetin)、冒泡阶段(bubbling)
- 冒泡型事件:当你使用事件冒泡时,子级元素先触发,父级元素后触发
- 捕获型事件:当你使用事件捕获时,父级元素先触发,子级元素后触发
- DOM事件流:同时支持两种事件模型:捕获型事件和冒泡型事件
- 阻止冒泡:在W3c中,使用stopPropagation()方法;在IE下设置cancelBubble = true
- 阻止捕获:阻止事件的默认行为,例如click - <a>后的跳转。在W3c中,使用preventDefault()方法,在IE下设置window.event.returnValue = false
53.new操作符具体干了什么呢?
- 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型
- 属性和方法被加入到 this 引用的对象中
- 新创建的对象由 this 所引用,并且最后隐式的返回 this
54.Ajax原理
- Ajax的原理简单来说是在用户和服务器之间加了—个中间层(AJAX引擎),通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。使用户操作与服务器响应异步化。这其中最关键的一步就是从服务器获得请求数据
- Ajax的过程只涉及JavaScript、XMLHttpRequest和DOM。XMLHttpRequest是ajax的核心机制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// 1. 创建连接
var xhr = null;
xhr = new XMLHttpRequest()
// 2. 连接服务器
xhr.open('get', url, true)
// 3. 发送请求
xhr.send(null);
// 4. 接受请求
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
success(xhr.responseText);
} else { // fail
fail && fail(xhr.status);
}
}
}
|
- ajax 有那些优缺点?
- 优点:
- 通过异步模式,提升了用户体验.
- 优化了浏览器和服务器之间的传输,减少不必要的数据往返,减少了带宽占用.
- Ajax在客户端运行,承担了一部分本来由服务器承担的工作,减少了大用户量下的服务器负载。
- Ajax可以实现动态不刷新(局部刷新)
- 缺点:
- 安全问题 AJAX暴露了与服务器交互的细节。
- 对搜索引擎的支持比较弱。
- 不容易调试。
55.如何解决跨域问题?
jsonp、iframe、window.name、window.postMessage、服务器上设置代理页面
56.模块化开发怎么做?
立即执行函数,不暴露私有成员
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();
|
57.异步加载JS的方式有哪些?
- defer,只支持IE
- async:
- 创建script,插入到DOM中,加载完毕后callBack
58.那些操作会造成内存泄漏?
- 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在
- setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏
- 闭包使用不当
59.XML和JSON的区别?
- 数据体积方面
- JSON相对于XML来讲,数据的体积小,传递的速度更快些。
- 数据交互方面
- JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互
- 数据描述方面
- 传输速度方面
60.谈谈你对webpack的看法
- WebPack 是一个模块打包工具,你可以使用WebPack管理你的模块依赖,并编绎输出模块们所需的静态文件。
- 它能够很好地管理、打包Web开发中所用到的HTML、Javascript、CSS以及各种静态文件(图片、字体等),让开发过程更加高效。
- 对于不同类型的资源,webpack有对应的模块加载器。webpack模块打包器会分析模块间的依赖关系,最后 生成了优化且合并后的静态资源
61.说说你对AMD和Commonjs的理解
- CommonJS是服务器端模块的规范,Node.js采用了这个规范。CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数
- AMD推荐的风格通过返回一个对象做为模块对象,CommonJS的风格通过对module.exports或exports的属性赋值来达到暴露模块对象的目的
62.常见web安全及防护原理
- sql注入原理
就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
- 总的来说有以下几点
- 永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双"-“进行转换等
- 永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取
- 永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接
- 不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息
- XSS原理及防范
Xss(cross-site scripting)攻击指的是攻击者往Web页面里插入恶意html标签或者javascript代码。
比如:攻击者在论坛中放一个看似安全的链接,骗取用户点击后,窃取cookie中的用户私密信息;
或者攻击者在论坛中加一个恶意表单,当用户提交表单的时候,却把信息传送到攻击者的服务器中,而不是用户原本以为的信任站点
- XSS防范方法
- 首先代码里对用户输入的地方和变量都需要仔细检查长度和对”<”,”>”,”;”,”’”等字符做过滤;其次任何内容写到页面之前都必须加以encode,避免不小心把html tag 弄出来。这一个层面做好,至少可以堵住超过一半的XSS 攻击
- XSS与CSRF有什么区别吗?
- XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。
- CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。
- 要完成一次CSRF攻击,受害者必须依次完成两个步骤
- 登录受信任网站A,并在本地生成Cookie
- 在不登出A的情况下,访问危险网站B
- CSRF的防御
- 服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数
- 通过验证码的方法
63.用过哪些设计模式?
- 工厂模式:
- 工厂模式解决了重复实例化的问题,但还有一个问题,那就是识别问题,因为根本无法
- 主要好处就是可以消除对象间的耦合,通过使用工程方法而不是new关键字
- 构造函数模式
- 使用构造函数的方法,即解决了重复实例化的问题,又解决了对象识别的问题,该模式与工厂模式的不同之处在于
- 直接将属性和方法赋值给 this对象;
64.为什么要有同源限制?
- 同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议
- 举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。
- offsetWidth/offsetHeight返回值包含content + padding + border,效果与e.getBoundingClientRect()相同
- clientWidth/clientHeight返回值只包含content + padding,如果有滚动条,也不包含滚动条
- scrollWidth/scrollHeight返回值包含content + padding + 溢出内容的尺寸
66.javascript有哪些方法定义对象
- 对象字面量: var obj = {};
- 构造函数: var obj = new Object();
- Object.create(): var obj = Object.create(Object.prototype);
67.常见兼容性问题?
- png24位的图片在iE6浏览器上出现背景,解决方案是做成PNG8
- 浏览器默认的margin和padding不同。
解决方案是加一个全局的* {margin:0;padding:0;}
来统一,
但是全局效率很低,一般是如下这样解决:
1
2
3
4
|
body,ul,li,ol,dl,dt,dd,form,input,h1,h2,h3,h4,h5,h6,p{
margin:0;
padding:0;
}
|
- IE下,event对象有x,y属性,但是没有pageX,pageY属性
- Firefox下,event对象有pageX,pageY属性,但是没有x,y属性.
68.说说你对promise的了解
-
依照 Promise/A+ 的定义,Promise 有四种状态:
- pending: 初始状态, 非 fulfilled 或 rejected.
- fulfilled: 成功的操作.
- rejected: 失败的操作.
- settled: Promise已被fulfilled或rejected,且不是pending
-
另外, fulfilled与 rejected一起合称 settled
-
Promise 对象用来进行延迟(deferred) 和异步(asynchronous) 计算
-
Promise 的构造函数
1
2
3
4
5
6
7
|
var promise = new Promise(function(resolve, reject) {
if (...) { // succeed
resolve(result);
} else { // fails
reject(Error(errMessage));
}
});
|
-
Promise 实例拥有 then 方法(具有 then 方法的对象,通常被称为thenable)。
它的使用方法如下:
promise.then(onFulfilled, onRejected)
-
接收两个函数作为参数,
- 一个在 fulfilled 的时候被调用,
- 一个在rejected的时候被调用,
- 接收参数就是 future,onFulfilled 对应resolve, onRejected对应 reject
69.vue、react、angular
- Vue.js
一个用于创建 web 交互界面的库,是一个精简的 MVVM。它通过双向数据绑定把 View 层和 Model 层连接了起来。实际的 DOM 封装和输出格式都被抽象为了Directives 和 Filters
- AngularJS
是一个比较完善的前端MVVM框架,包含模板,数据双向绑定,路由,模块化,服务,依赖注入等所有功能,模板功能强大丰富,自带了丰富的 Angular指令
- React
React 仅仅是 VIEW 层是facebook公司。推出的一个用于构建UI的一个库,能够实现服务器端的渲染。用了virtual dom,所以性能很好。
70.Node的应用场景
- 特点:
- 它是一个Javascript运行环境
- 依赖于Chrome V8引擎进行代码解释
- 事件驱动
- 非阻塞I/O
- 单进程,单线程
- 优点:
- 高并发(最重要的优点)
- 缺点:
- 只支持单核CPU,不能充分利用CPU
- 可靠性低,一旦代码某个环节崩溃,整个系统都崩溃
71.谈谈你对AMD、CMD的理解
- CommonJS是服务器端模块的规范,Node.js采用了这个规范。CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数
- AMD推荐的风格通过返回一个对象做为模块对象,CommonJS的风格通过对module.exports或exports的属性赋值来达到暴露模块对象的目的
72.那些操作会造成内存泄漏?
- 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在
- setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏
- 闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
73.web开发中会话跟踪的方法有哪些
- cookie
- session
- url重写
- 隐藏input
- ip地址
74.介绍js的基本数据类型
- Undefined、Null、Boolean、Number、String
75.介绍js有哪些内置对象?
- Object 是 JavaScript 中所有对象的父对象
- 数据封装类对象:Object、Array、Boolean、Number 和 String
- 其他对象:Function、Arguments、Math、Date、RegExp、Error
76.javascript创建对象的几种方式?
javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用JSON;
但写法有很多种,也能混合使用
- 对象字面量的方式
1
2
3
4
5
6
|
person={
firstname:"Mark",
lastname:"Yun",
age:25,
eyecolor:"black"
};
|
- 用function来模拟无参的构造函数
1
2
3
4
5
6
7
8
9
|
function Person(){}
//定义一个function,如果使用new"实例化",该function可以看作是一个Class
var person=new Person();
person.name="Mark";
person.age="25";
person.work=function(){
alert(person.name+" hello...");
}
person.work();
|
3.用function来模拟参构造函数来实现(用this关键字定义构造的上下文属性)
1
2
3
4
5
6
7
8
9
10
|
function Pet(name,age,hobby){
this.name=name;//this作用域:当前对象
this.age=age;
this.hobby=hobby;
this.eat=function(){
console.log("我叫"+this.name+",我喜欢"+this.hobby+",是个程序员");
}
}
var maidou =new Pet("麦兜",25,"coding");//实例化、创建对象
maidou.eat();//调用eat方法
|
4.用工厂方式来创建(内置对象)
1
2
3
4
5
6
7
|
var wcDog =new Object();
wcDog.name="旺财";
wcDog.age=3;
wcDog.work=function(){
alert("我是"+wcDog.name+",汪汪汪......");
}
wcDog.work();
|
- 用原型方式来创建
1
2
3
4
5
6
7
|
function Dog(){}
Dog.prototype.name="旺财";
Dog.prototype.eat=function(){
alert(this.name+"是个吃货");
}
var wangcai =new Dog();
wangcai.eat();
|
- 用混合方式来创建
1
2
3
4
5
6
7
8
9
|
function Car(name,price){
this.name=name;
this.price=price;
}
Car.prototype.sell=function(){
alert("我是"+this.name+",我现在卖"+this.price+"万元");
}
var camry =new Car("凯美瑞",27);
camry.sell();
|
77.eval是做什么的?
- 它的功能是把对应的字符串解析成JS代码并运行
- 应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)
- 由JSON字符串转换为JSON对象的时候可以用eval,var obj =eval(’(’+ str +’)')
78. null,undefined 的区别?
- undefined 表示不存在这个值。
- undefined :是一个表示"无"的原始值或者说表示"缺少值”,就是此处应该有一个值,但是还没有定义。当尝试读取时会返回 undefined
- 例如变量被声明了,但没有赋值时,就等于undefined
- null 表示一个对象被定义了,值为“空值”
- null : 是一个对象(空对象, 没有任何属性和方法)
- 例如作为函数的参数,表示该函数的参数不是对象;
- 在验证null时,一定要使用 === ,因为 ==无法分别null 和 undefined
79、[“1”, “2”, “3”].map(parseInt) 答案是多少?
- [1, NaN, NaN]因为 parseInt 需要两个参数 (val, radix),其中radix 表示解析时用的基数。
- map传了 3个(element, index, array),对应的 radix 不合法导致解析失败。
80、javascript 代码中的"use strict";是什么意思 ? 使用它区别是什么?
- use strict是一种ECMAscript 5 添加的(严格)运行模式,这种模式使得 Javascript 在更严格的条件下运行,使JS编码更加规范化的模式,消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为
81、JSON 的了解?
- JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式
- 它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小
- JSON字符串转换为JSON对象:
1
2
3
|
var obj =eval('('+ str +')');
var obj = str.parseJSON();
var obj = JSON.parse(str);
|
- JSON对象转换为JSON字符串:
1
2
|
var last=obj.toJSONString();
var last=JSON.stringify(obj);
|
81、js延迟加载的方式有哪些?
defer和async、动态创建DOM方式(用得最多)、按需异步载入js
82、同步和异步的区别?
- 同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作
- 异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容
83、渐进增强和优雅降级
- 渐进增强 :针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
- 优雅降级 :一开始就构建完整的功能,然后再针对低版本浏览器进行兼容
84、defer和async
- defer并行加载js文件,会按照页面上script标签的顺序执行
- async并行加载js文件,下载完成立即执行,不会按照页面上script标签的顺序执行
85、说说严格模式的限制
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 不能使用with语句
- 禁止this指向全局对象
85、attribute和property的区别是什么?
- attribute是dom元素在文档中作为html标签拥有的属性;
- property就是dom元素在js中作为对象拥有的属性。
- 对于html的标准属性来说,attribute和property是同步的,是会自动更新的
- 但是对于自定义的属性来说,他们是不同步的
86、谈谈你对ES6的理解
- 新增模板字符串(为JavaScript提供了简单的字符串插值功能)
- 箭头函数
- for-of(用来遍历数据—例如数组中的值。)
- arguments对象可被不定参数和默认参数完美代替。
- ES6将promise对象纳入规范,提供了原生的Promise对象。
- 增加了let和const命令,用来声明变量。
- 增加了块级作用域。
- let命令实际上就增加了块级作用域。
- 还有就是引入module模块的概念
87、ECMAScript6 怎么写class么,为什么会出现class这种东西?
这个语法糖可以让有OOP基础的人更快上手js,至少是一个官方的实现了
但对熟悉js的人来说,这个东西没啥大影响;一个Object.creat()搞定继承,比class简洁清晰的多
88、什么是面向对象编程及面向过程编程,它们的异同和优缺点
- 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了
- 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为
- 面向对象是以功能来划分问题,而不是步骤
89.面向对象编程思想
- 基本思想是使用对象,类,继承,封装等基本概念来进行程序设计
- 优点
- 易维护
采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的
- 易扩展
- 开发工作的重用性、继承性高,降低重复工作量。
- 缩短了开发周期
90.对web标准、可用性、可访问性的理解
- 可用性(Usability):产品是否容易上手,用户能否完成任务,效率如何,以及这过程中用户的主观感受可好,是从用户的角度来看产品的质量。可用性好意味着产品质量高,是企业的核心竞争力
- 可访问性(Accessibility):Web内容对于残障用户的可阅读和可理解性
- 可维护性(Maintainability):一般包含两个层次,一是当系统出现问题时,快速定位并解决问题的成本,成本低则可维护性好。二是代码是否容易被人理解,是否容易修改和增强功能。
91.如何通过JS判断一个数组?
- instanceof方法
1
2
3
|
//instanceof 运算符是用来测试一个对象是否在其原型链原型构造函数的属性
var arr = [];
arr instanceof Array; // true
|
- constructor方法
1
2
3
|
//constructor属性返回对创建此对象的数组函数的引用,就是返回对象相对应的构造函数
var arr = [];
arr.constructor == Array; //true
|
- 最简单的方法
这种写法,是 jQuery 正在使用的
1
2
3
4
5
|
Object.prototype.toString.call(value) == '[object Array]'
// 利用这个方法,可以写一个返回数据类型的方法
var isType = function (obj) {
return Object.prototype.toString.call(obj).slice(8,-1);
}
|
- ES5新增方法isArray()
1
2
3
4
|
var a = new Array(123);
var b = new Date();
console.log(Array.isArray(a)); //true
console.log(Array.isArray(b)); //false
|
92、谈一谈let与var的区别?
- let命令不存在变量提升,如果在let前使用,会导致报错
- 如果块区中存在let和const命令,就会形成封闭作用域
- 不允许重复声明,因此,不能在函数内部重新声明参数
93.map与forEach的区别?
- forEach方法,是最基本的方法,就是遍历与循环,默认有3个传参:分别是遍历的数组内容item、数组索引index、和当前遍历数组Array
- map方法,基本用法与forEach一致,但是不同的,它会返回一个新的数组,所以在callback需要有return值,如果没有,会返回undefined
94、谈一谈你理解的函数式编程?
- 简单说,“函数式编程"是一种"编程范式”(programming paradigm),也就是如何编写程序的方法论
它具有以下特性:闭包和高阶函数、惰性计算、递归、函数是"第一等公民"、只用"表达式"
95、谈一谈箭头函数与普通函数的区别?
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
- 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误
- 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替
- 不可以使用yield命令,因此箭头函数不能用作Generator函数
96、谈一谈函数中this的指向吧?
- this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
- 《javascript语言精髓》中大概概括了4种调用方式:
- 方法调用模式
- 函数调用模式
- 构造器调用模式
graph LR
A–>B
- apply/call调用模式
97、异步编程的实现方式?
- 回调函数
- 优点:简单、容易理解
- 缺点:不利于维护,代码耦合高
- 事件监听(采用时间驱动模式,取决于某个事件是否发生):
- 优点:容易理解,可以绑定多个事件,每个事件可以指定多个回调函数
- 缺点:事件驱动型,流程不够清晰
- 发布/订阅(观察者模式)
- 类似于事件监听,但是可以通过‘消息中心’,了解现在有多少发布者,多少订阅者
- Promise对象
- 优点:可以利用then方法,进行链式写法;可以书写错误时的回调函数;
- 缺点:编写和理解,相对比较难
- Generator函数
- 优点:函数体内外的数据交换、错误处理机制
- 缺点:流程管理不方便
- async函数
- 优点:内置执行器、更好的语义、更广的适用性、返回的是Promise、结构清晰。
- 缺点:错误处理机制
98、对原生Javascript了解程度
- 数据类型、运算、对象、Function、继承、闭包、作用域、原型链、事件、RegExp、JSON、Ajax、DOM、BOM、内存泄漏、跨域、异步装载、模板引擎、前端MVC、路由、模块化、Canvas、ECMAScript
99、Js动画与CSS动画区别及相应实现
- CSS3的动画的优点
- 在性能上会稍微好一些,浏览器会对CSS3的动画做一些优化
- 代码相对简单
- 缺点
- JavaScript的动画正好弥补了这两个缺点,控制能力很强,可以单帧的控制、变换,同时写得好完全可以兼容IE6,并且功能强大。对于一些复杂控制的动画,使用javascript会比较靠谱。而在实现一些小的交互动效的时候,就多考虑考虑CSS吧
100. JS 数组和对象的遍历方式,以及几种方式的比较
通常我们会用循环的方式来遍历数组。但是循环是 导致js 性能问题的原因之一。
一般我们会采用下几种方式来进行数组的遍历
- for in循环
- for循环
- forEach
- 这里的 forEach回调中两个参数分别为 value,index
- forEach 无法遍历对象
- IE不支持该方法;Firefox 和 chrome 支持
- forEach 无法使用 break,continue 跳出循环,且使用 return 是跳过本次循环
- 这两种方法应该非常常见且使用很频繁。但实际上,这两种方法都存在性能问题
- 在方式1中,for-in需要分析出array的每个属性,这个操作性能开销很大。用在 key 已知的数组上是非常不划算的。所以尽量不要用for-in,除非你不清楚要处理哪些属性,例如 JSON对象这样的情况
- 在方式2中,循环每进行一次,就要检查一下数组长度。读取属性(数组长度)要比读局部变量慢,尤其是当 array 里存放的都是 DOM 元素,因为每次读取都会扫描一遍页面上的选择器相关元素,速度会大大降低
101、gulp是什么?
- gulp是前端开发过程中一种基于流的代码构建工具,是自动化项目的构建利器;
它不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成
- Gulp的核心概念:流
- 流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。
在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向
- gulp正是通过流和代码优于配置的策略来尽量简化任务编写的工作
- Gulp的特点:
- 易于使用:通过代码优于配置的策略,gulp 让简单的任务简单,复杂的任务可管理
- 构建快速 利用 Node.js 流的威力,你可以快速构建项目并减少频繁的 IO 操作
- 易于学习 通过最少的 API,掌握 gulp 毫不费力,构建工作尽在掌握:如同一系列流管道
102、说一下Vue的双向绑定数据的原理
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调