web前端面试题:JS、ES6篇

web前端面试题:JS、ES6篇

    • JS是一种什么样的语言?
    • JS数据类型有哪些?
    • 介绍JS有哪些内置对象?
    • 栈与堆的区别?
    • 什么是闭包?闭包有什么作用?
    • for...in、for...of、forEach、Map的区别
      • for...in
      • for...of
      • forEach与Map
    • 判断是否为数组的方法
    • 如何阻止事件冒泡和默认事件?
    • ☆call和apply的区别和作用?
    • 双等与三等的区别?
    • null和undefined的区别?
    • js检测对象中是否存在某个属性
    • push()、pop()、shift()、unshift()分别是什么功能?
    • 如何用原生js给一个按钮绑定两个onclick事件?
    • 拖拽会用到哪些事件?
    • JS中定时器有哪些?他们的区别及用法是什么?
    • 一次性插入1000个div,如何优化插入的性能
    • ☆说说JS原型和原型链
    • 什么是事件代理
    • Javascript如何实现继承?
      • 原型链继承:
      • 构造继承
      • 实例继承、
      • 拷贝继承
      • 组合继承
      • 寄生组合继承
    • 什么是伪数组,伪数组如何转换为标准数组?
    • DOM节点的增删改查
    • 如何解决跨域问题?
    • 异步加载JS的方式有哪些?
    • 哪些操作会造成内存泄漏?
    • 往期回顾

JS是一种什么样的语言?

  1. 解释性脚本语言,代码不进行预编译
  2. 主要用来向HTML页面添加交互行为
  3. 可以直接嵌入HTML页面,但单独写成JS文件有利于结构和行为的分离
  4. 跨平台性,在绝大多数浏览器的支持下,可以在多种平台下运行:linux、windows

JS数据类型有哪些?

基本类型: String、Number、boolean、null、undefined。
引用类型:object、function、Array、Date。

介绍JS有哪些内置对象?

object是Javascript中所有对象的父对象
数据封装类对象:Object、Array、Boolean、Number和String
其他对象:Function、Arguments、Math、Date、RegExp、Error

栈与堆的区别?

1.栈与堆的储存位置不同;
2.原始数据是储存在栈中简单数据段,体积小,大小固定,属于频繁使用的数据.
3.引用数据类型是储存在堆中的对象,占据的空间大,如果储存在栈中会影响运行性能,引用数据类型在栈中指明了自己的所在地。当代码解析时,会先从栈中获取地址,然后再从堆中获取实体;

什么是闭包?闭包有什么作用?

概念:闭包就是能够读取其他函数内部变量的函数
优点
- 逻辑连续,当闭包作为另一个函数调用参数时,避免脱离当前逻辑而单独编写额外逻辑。
- 方便调用上下文的局部变量。
- 加强封装性,是第2点的延伸,可以达到对变量的保护作用。
缺点:消耗内存,不正当使用会造成内存溢出。

for…in、for…of、forEach、Map的区别

for…in

  1. for…in以原始插入顺序访问对象的可枚举属性,包括从原型继承而来的可枚举属性。
  2. for…in用于遍历数组时,可以将数组看作对象,数组下标看作属性名。但用for…in遍历数组时不一定会按照数组的索引顺序。

for…of

  1. for…of语句在可迭代对象(Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,为每个不同属性的值执行语句。
  2. 使用for…in循环时,获得的是数组的下标;使用for…of循环时,获得的是数组的元素值。
  3. for…of遍历Map时,可以获得整个键值对对象:
let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);

for (let entry of iterable) {
  console.log(entry);
}
// ["a", 1]
// ["b", 2]
// ["c", 3]

也可以只获得键值:

let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);

for (let [key] of iterable) {
  console.log(key);
}
//a
//b
//c

或者分别获得键与值:

let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);

for (let [key,value] of iterable) {
  console.log(key+':'+value);
}
//a:1
//b:2
//c:3

forEach与Map

相同点:

  • 只能遍历数组,且循环遍历数组中的每一项
  • 包含的匿名函数都是三个参数(item,index,input)(当前项,当前项的索引,原始数组
  • 在IE6-8下都不兼容

不同点:

  • map()返回值是修改后的数组,可以用’链式’连接;forEach()无返回值
  • forEach()不能使用continue, break;
  • map()速度最快

判断是否为数组的方法

console.log( arr instanceof Array );
console.log( arr.construct == Array);
console.log( Array.isArray( arr ));
console.log( Object.prototype.toString.call(arr) ===[object Array]);

如何阻止事件冒泡和默认事件?

cancelBunnle(IE);
return false;
event.preventDefault( );
event.stopPropagation( );

☆call和apply的区别和作用?

含义:

  • apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, argsArray); 即A对象调用B对象的方法。
  • call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2); 即A对象调用B对象的方法。

相同点:

  • 可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由thisObj指定的新对象

不同点:

  • apply()最多只能有两个参数,call可以传入多个参数

总结:

  • 实际上,apply和call的功能是一样的,只是传入的参数列表形式不同

双等与三等的区别?

  • ===为等同符,当左边与右边的值与类型都完全相等时,会返回true;
  • ==为等值符,用来判断值是否相同,不会判断类型是否相同

null和undefined的区别?

  • null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在对象
  • undefined主要指定义了变量,但是并未赋值

js检测对象中是否存在某个属性

  • 使用in关键字,console.log(“属性名” in 对象名);
  • 使用对象的hasOwnProperty()方法,console.log(对象.hasOwnProperty(“属性名”));
  • 使用undefined判断,console.log(o.x!==undefined)
  • 在条件语句中判断,if(o.x) o.x+=1;

push()、pop()、shift()、unshift()分别是什么功能?

  • push 方法 将新元素添加到一个数组中,并返回数组的新长度值。
var a=[1,2,3,4]; a.push(5);
  • pop 方法 移除数组中的最后一个元素并返回该元素。
var a=[1,2,3,4]; a.pop();
  • shift 方法 移除数组中的第一个元素并返回该元素。
var a=[1,2]; alert(a.shift());
  • unshift 方法 将指定的元素插入数组开始位置并返回该数组。

如何用原生js给一个按钮绑定两个onclick事件?

 var btn4 = document.getElementById("btn4");
 btn4.addEventListener("click",hello1);
 btn4.addEventListener("click",hello2);

拖拽会用到哪些事件?

  • dragstart:拖拽开始时在被拖拽元素上触发此事件,监听器需要设置拖拽所需数据,从操作系统拖拽文件到浏览器时不触发此事件.
  • dragenter:拖拽鼠标进入元素时在该元素上触发,用于给拖放元素设置视觉反馈,如高亮
  • dragover:拖拽时鼠标在目标元素上移动时触发.监听器通过阻止浏览器默认行为设置元素为可拖放元素.
  • dragleave:拖拽时鼠标移出目标元素时在目标元素上触发.此时监听器可以取消掉前面设置的视觉效果.
  • drag:拖拽期间在被拖拽元素上连续触发
  • drop:鼠标在拖放目标上释放时,在拖放目标上触发.此时监听器需要收集数据并且执行所需操作.如果是从操作系统拖放文件到浏览器,需要取消浏览器默认行为.
  • dragend:鼠标在拖放目标上释放时,在拖拽元素上触发.将元素从浏览器拖放到操作系统时不会触发此事件.

JS中定时器有哪些?他们的区别及用法是什么?

  • setTimeout 只执行一次
  • setInterval 会一直重复执行

一次性插入1000个div,如何优化插入的性能

  • 使用Fragment(document.createDocumentFragment( ))
  • Documentfragments是DOM节点,它们不是DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树中。因为文档片段存在于内存中,并不在DOM树中,所以讲子元素插入到文档片段时不会引起页面回流。因为使用文档片段会带来更好的性能
  • 先创建一个div,后续的复制这个元素,避免重复创建元素,再放到元素片段里面
   var divFragment = document.createDocumentFragment(); 
      let div = document.createElement(“div”); 
      forvar i = 0; i <1000; i ++{ 
            divFragment.append(div.cloneNode())
      } 
      document.body.appendChild(divFragment);

☆说说JS原型和原型链

原型:

  • 函数都要prototype(显示原型)属性,而prototype会自动初始化一个空对象,这个对象就是原型对象
  • 原型对象中会有一个constructor属性,这个属性将指向了函数本身
  • 实例化对象都有一个_proto_(隐式原型)属性,_proto_属性指向原型对象

原型链:

  • 从实例对象往上找构造这个实例的相关对象,然后这个关联的对象再往上找,找到创造它的上一级的原型对象,以此类推,一直到object.prototype原型对象终止,原型链结束.
  • 原型链中的原型对象中的内容,是会被不同的实例,所共有的

什么是事件代理

  • 事件代理 即“事件委托”,都是基于事件冒泡原理的。
  • 可以大量节省内存占用,减少事件注册
  • 可以实现 新增子对象时无需再次对其绑定

Javascript如何实现继承?

原型链继承:

特点:

  • 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
  • 父类新增原型方法/原型属性,子类都能访问到
  • 简单,易于实现

缺点:

  • 要想为子类新增属性和方法,必须要在new Child()这样的语句之后执行,不能放到构造器中
  • 无法实现多继承
  • 来自原型对象的引用属性被所有实例共享

构造继承

特点:

  • 解决了1中,子类实例共享父类引用属性的问题
  • 创建子类实例时,可以向父类传递参数
  • 可以实现多继承(call多个父类对象)

缺点:

  • 实例并不是父类的实例,只是子类的实例
  • 只能继承父类的实例属性与方法,不能继承原型属性、方法
  • 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

实例继承、

特点:

  • 不限制调用方法,不管是new子类()还是子类(),返回的对象具有相同的效果

缺点:

  • 实例是父类的实例, 不是子类的实例
  • 不支持多继承

拷贝继承

特点:

  • 支持多继承

缺点:

  • 效率较低,内存占用高(因为要拷贝父类的属性)
  • 无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)

组合继承

特点:

  • 弥补了方法2的缺陷,可以继承实例属性、方法,也可以继承原型属性和方法
  • 既是子类的实例,也是父类的实例
  • 不存在引用属性共享的问题
  • 可传参
  • 函数可复用

缺点:

  • 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

寄生组合继承

特点:

  • 堪称完美

缺点:

  • 实现较为复杂

什么是伪数组,伪数组如何转换为标准数组?

伪数组定义:

  • 伪数组是一个对象
  • 这个对象必须要有length属性,且必须是number类型
  • 如果这个对象的length不为0,那么必须要有按照下标存储的数据
  • obj instanceof Array ===false 但是有length属性

伪数组三大特性:

  • 具有length属性
  • 按索引方式存储数据
  • 不具有数组的push,pop等方法

伪数组案例:

var obj3 = { length: 0 };
var obj4 = { 0: '888', length: 1 };
var obj5 = { 99: 'abc', length: 100 }

伪数组转化:

  • 将伪数组转化为标准数组需要用到数组原型中的方法 slice
例如: Array.prototype.slice.call( 伪数组名称 );
  • 使用[].slice.call()
[].slice.call(伪数组);  
  • 使用ES6中Array.from方法
Array.from(伪数组);  

DOM节点的增删改查

  1. 查找
    getElementById( ) getElementsByClassName( ) getElementsByTagName( )
    querySelector( ) 返回第一个匹配的元素 querySelectorAll( ) 返回全部匹配的元素
  2. 插入
    appendChild( ) 末尾插入
    insertBefore( ) 特定位置插入
  3. 替换
    replaceChild( ) 接受两个参数, 第一个为要插入的节点, 第二个为要替换的节点
  4. 删除
    removeChild( )

如何解决跨域问题?

1、jsonp跨域
JSONP(JSON with Padding:填充式JSON),应用JSON的一种新方法
JSON、JSONP的区别:
- JSON返回的是一串数据、JSONP返回的是脚本代码(包含一个函数调用)
- JSONP 只支持get请求、不支持post请求

2、nginx反向代理:
3、PHP端修改header
4、document.domain
5、window.name

异步加载JS的方式有哪些?

  • defer,只支持IE
  • async:
  • 创建script,插入到DOM中,加载完毕后callBack

哪些操作会造成内存泄漏?

  • 内存泄漏:指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。

  • 哪些操作会造成内存泄露

    1.意外的全局变量引起的内存泄露

    function leak(){
      leak="xxx";//leak成为一个全局变量,不会被回收
    }
    

    2.闭包引起的内存泄露

    function bindEvent(){
      var obj=document.createElement("XXX");
      obj.οnclick=function(){
        //Even if it's a empty function
      }
    }
    

    3.没有清理的DOM元素引用

    var elements={
        button: document.getElementById("button"),
        image: document.getElementById("image"),
        text: document.getElementById("text")
    };
    function doStuff(){
        image.src="http://some.url/image";
        button.click():
        console.log(text.innerHTML)
    }
    function removeButton(){
        document.body.removeChild(document.getElementById('button'))
    }
    

往期回顾

web前端面试题:HTML、CSS篇

你可能感兴趣的:(web前端面试题:JS、ES6篇)