- 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是一种什么样的语言?
- 解释性脚本语言,代码不进行预编译
- 主要用来向HTML页面添加交互行为
- 可以直接嵌入HTML页面,但单独写成JS文件有利于结构和行为的分离
- 跨平台性,在绝大多数浏览器的支持下,可以在多种平台下运行: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
- for…in以原始插入顺序访问对象的可枚举属性,包括从原型继承而来的可枚举属性。
- for…in用于遍历数组时,可以将数组看作对象,数组下标看作属性名。但用for…in遍历数组时不一定会按照数组的索引顺序。
for…of
- for…of语句在可迭代对象(Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,为每个不同属性的值执行语句。
- 使用for…in循环时,获得的是数组的下标;使用for…of循环时,获得的是数组的元素值。
- 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”);
for(var 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节点的增删改查
- 查找
getElementById( ) getElementsByClassName( ) getElementsByTagName( )
querySelector( ) 返回第一个匹配的元素 querySelectorAll( ) 返回全部匹配的元素 - 插入
appendChild( ) 末尾插入
insertBefore( ) 特定位置插入 - 替换
replaceChild( ) 接受两个参数, 第一个为要插入的节点, 第二个为要替换的节点 - 删除
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'))
}