1. 观察者模式和发布订阅模式不同
其实订阅模式有一个调度中心,对订阅事件进行统一管理。而观察者模式可以随意注册事件,调用事件,虽然实现原理都雷同,设计模式上有一定的差别,实际代码运用中差别在于:订阅模式中,可以抽离出调度中心单独成一个文件,可以对一系列的订阅事件进行统一管理
2. Javascript实现继承、创建对象的几种方式?
- 定义类的4种方法
- 工厂方法
- 构造函数方法
- 原型方法
- 组合使用构造函数和原型方法(使用最广)实现了属性定义和方法定义的分离
- 实现继承的3种方法
- 借用构造函数法(又叫经典继承)
- 对象冒充
- 组合继承(最常用)
3. JS面向对象
“面向对象”(Object Oriented,简称OO)是一种以事物为中心的编程思想,从宏观方面思考问题。
面向对象的编程产生的历史原因:由于面向过程编程在构造系统时,无法解决重用,维护,扩展的问题,而且逻辑过于复杂,代码晦涩难懂,提高程序的重用性,灵活性和可扩展性
面向对象的方法主要是把事物给对象化,对象包括属性与行为.
类是创建对象的模板,一个类可以创建多个对象。对象是类的实例化。
类是 抽象的,不占用存储空间;而对象具体的,占用存储空间
- 封装
- 构造函数模式
- Prototype模式
-
Prototype模式的验证方法
-
isPrototypeOf():某个
proptotype
对象和某个实例之间的关系 -
hasOwnProperty():每个实例对象都有一个
hasOwnProperty()
方法,判断属性是本地还是继承自prototype
对象的属性 - in运算符:某个实例是否含有某个属性,不管是不是本地属性
-
isPrototypeOf():某个
- 继承
- 构造函数绑定(使用call或apply将父对象的构造函数绑定在子对象)
- prototype模式(子对象的prototype对象,指向父对象的实例,子对象的实例,就能继承父对象了)
- 直接继承prototype(父对象中不变的属性可直接写入prototype,子对象直接继承父对象prototype)
- 利用空对象作为中介(解决把父对象的prototype对象的constructor属性被改掉)
- 拷贝继承
- 多态
-
面向对象编程5大基本原则
- 单一职责原则:一个类只专注于做一件事和只有一个引起他变的原因
- 开闭原则:模块和函数应该对扩展是开放,对修改是封闭的
- 里氏替换原则:子类型必须能够替换他们的基类型
- 依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象
- 接口隔离原则:建立单一接口,细化接口,接口中的方法尽量少
4. 渐进增强与优雅降级
渐进增强:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进,达到更好的用户体验。
优雅降级:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
5. 原型和原型链(原型对象继承)的关系
原型
- 所有函数(除一些内建函数)都有prototype属性
- prototype指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)
原型链(原型对象继承)
- 对象继承其原型对象,而原型对象继承它的原型对象
原型与构造函数的关系就是,
- 构造函数内部有一个名为 prototype 的属性,通过这个属性就能访问到原型
- 原型能够访问到构造函数,通过 constructor
实例通过__proto__
访问到原型
原型链是一种关系,实例对象和原型对象之间的关系,关系是通过原型(proto)来联系的
实例对象中有proto,是对象,叫原型,不是标准的属性,浏览器使用,并且有的浏览器不支持构造函数中有prototype属性,也是对象,叫原型
注意 原型中的方法是可以互相访问的
实例对象使用属性或方法的规则
实例对象使用的属性或方法,现在实例中查找,如果有则使用自身的属性或方法,
如果没有,则通过proto指向的原型对象 查找方法,找到则使用,
如果找不到则继续向proto寻找,直到未找到时报错
构造函数和实例对象和原型对象之间的关系
构造函数可以实例化对象
构造函数中有一个属性叫prototype,是构造函数的原型对象
构造函数的原型对象(prototype)中有一个constructor 构造器,这个构造器指向的就是自己所在的原型对象所在的构造函数
实例对象的原型对象(proto) 指向的是该构造函数的原型对象(prototype)
构造函数的原型对象(prototype)中的方法是可以被实例对象直接访问
参考文章:原型链和利用原型实现继承
6. Event对象中,target和currentTarget的区别?
currentTarget是当事件遍历DOM时,标识事件的当前目标。它总是引用事件处理程序附加到的元素,而不是event.target,event.target标识事件发生的元素
7. 说一说什么是事件冒泡,如何阻止事件冒泡?如何阻止默认事件?
事件冒泡是指 事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接受,然后逐级向上传播到较为不具体的节点(文档)
阻止事件冒泡的方法。
调用当前事件对象的stopPropagation()方法
阻止默认事件
调用当前事件对象的preventDefault()方法
8. 是否了解事件委托?
利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件
当此事件处理程序被触发时,通过当前事件对象中的target来确认究竟是在哪个元素触发的事件,从而达到一次注册 处理多个元素触发事件的目的
页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件
9. 什么是事件循环
JavaScript是单线程的,“主线程”负责执行所有的同步任务,一旦所有同步任务执行完成,则立即从“任务队列”中读取最优先的任务放到“主线程”中执行,如此循环往复
向“任务队列”插入的是一个个事件处理函数(确切的说是函数地址)或定时任务(setTimeout的回调)
10. 本地对象、内置对象和宿主对象
内部对象/本地对象
-
定义:与宿主无关的对象,ECMA-262 (规则)定义的类(引用类型)
- 本地对象:Array、Boolean、Date、Function、Global、Math、Number、Object、RegExp、String以及各种错误类对象,包括Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError。(16个)
- 内置对象:其中Global和Math这两个对象又被称为“内置对象”。
- 区别:普通本地对象/内部对象需要实例化,内置对象不需要实例化。
宿主对象/浏览器对象:
- 定义:执行JS脚本的环境(宿主)提供的对象。
- 特点:依赖于宿主,带来浏览器兼容问题,增加开发难度。
宿主对象包括BOM和DOM对象,浏览器对象有很多,如Window和Document等等。
自定义对象
开发人员自己定义的对象。
11. 事件
-
IE和W3C不同绑定事件解绑事件的方法有什么区别,参数是什么,以及事件对象ev有什么区别
W3C:target.addEventListener(event,listener,useCapture);
event——事件类型;
listener——事件触发时执行的函数;
useCapture——指定时间是否再补货或冒泡阶段执行,为true时事件句柄在捕获阶段执行,为false(默认false)时,事件句柄在冒泡阶段执行。
对应的事件移除:removeEventListener(event,function,capture/bubble);
-
事件的三个阶段:捕获、 处于目标、 冒泡
-
阻止事件冒泡:event.stopPropagation()
12. 函数防抖与函数节流
函数防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时
适合多次事件一次响应的情况
如果有人进电梯(触发事件),那电梯将在10秒钟后出发(执行事件监听器),这时如果又有人进电梯了(在10秒内再次触发该事件),我们又得等10秒再出发(重新计时
function debounce(fn, wait) {
var timeout = null;
return function() {
if(timeout !== null)
clearTimeout(timeout);
timeout = setTimeout(fn, wait);
}
}
// 处理函数
function handle() {
console.log(Math.random());
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));
适用场景
- 给按钮加函数防抖防止表单多次提交。
- 对于输入框连续输入进行AJAX验证时,用函数防抖能有效减少请求次数。
- 判断
scroll
是否滑到底部,滚动事件
+函数防抖
函数节流:规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效
适用场景
- 游戏中的刷新率
- DOM元素拖拽
- Canvas画笔功能
适合大量事件按时间做平均分配触发
function parse(obj, str) {
var arr = str.replace('[', '.').replace(']', '').split('.');
for(var i=0;i<arr.length;i++) {
if (obj[arr[i]]) {
obj = obj[arr[i]];
}else {
return 'undefined';
}
}
return obj;
}
网友评论