js 面试题
JS 的基本数据类型和引用数据类型
基本数据类型:undefined、null、boolean、number、string、symbol
引用数据类型:object、array、function
介绍 JS 有哪些内置对象?
数据封装类对象:Object、Array、Boolean、Number、String
其他对象:Function、Arguments、Math、Date、RegExp、Error
ES6 新增对象:Symbol、Map、Set、Promises、Proxy、Reflect
JavaScript 有几种类型的值?,你能画一下他们的内存图吗
原始数据类型(Undefined,Null,Boolean,Number、String)– 栈
引用数据类型(对象、数组和函数)– 堆
两种类型的区别是:存储位置不同:
原始数据类型是直接存储在栈 (stack) 中的简单数据段,占据空间小、大小固定,属于被频繁使用数据;
引用数据类型存储在堆 (heap) 中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能;
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。
当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
如何编写高性能的 JavaScript?
遵循严格模式:”use strict”; 将 js 脚本放在页面底部,加快渲染页面; 将 js 脚本将脚本成组打包,减少请求; 使用非阻塞方式下载 js 脚本; 尽量使用局部变量来保存全局变量; 尽量减少使用闭包; 使用 window 对象属性方法时,省略 window; 尽量减少对象成员嵌套; 缓存 DOM 节点的访问
通过避免使用 eval() 和 Function() 构造器; 给 setTimeout() 和 setInterval() 传递函数而不是字符串作为参数; 尽量使用直接量创建对象和数组; 最小化重绘 (repaint) 和回流(reflow)
解释 JavaScript 中的作用域与变量声明提升?
JavaScript 作用域:
在 Java、C 等语言中,作用域为 for 语句、if 语句或 {} 内的一块区域,称为作用域;
而在 JavaScript 中,作用域为 function(){}内的区域,称为函数作用域。
JavaScript 变量声明提升:
在 JavaScript 中,函数声明与变量声明经常被 JavaScript 引擎隐式地提升到当前作用域的顶部。
声明语句中的赋值部分并不会被提升,只有名称被提升
函数声明的优先级高于变量,如果变量名跟函数名相同且未赋值,则函数声明会覆盖变量声明
如果函数有多个同名参数,那么最后一个参数(即使没有定义)会覆盖前面的同名参数
介绍 JavaScript 的原型,原型链?有什么特点?
原型:
JavaScript 的所有对象中都包含了一个 [proto] 内部属性,这个属性所对应的就是该对象的原型
JavaScript 的函数对象,除了原型 [proto] 之外,还预置了 prototype 属性
当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型 [proto]。
原型链:
当一个对象调用的属性 / 方法自身不存在时,就会去自己 [proto] 关联的前辈 prototype 对象上去找
如果没找到,就会去该 prototype 原型 [proto] 关联的前辈 prototype 去找。依次类推,直到找到属性 / 方法或 undefined 为止。从而形成了所谓的“原型链”
原型特点:
JavaScript 对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变
Javascript 如何实现继承?
构造函数绑定:使用 call 或 apply 方法,将父对象的构造函数绑定在子对象上
function Cat(name,color){
Animal.apply(this, arguments);
this.name = name;
this.color = color;
}
实例继承:将子对象的 prototype 指向父对象的一个实例
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
拷贝继承:如果把父对象的所有属性和方法,拷贝进子对象
function extend(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
}
原型继承:将子对象的 prototype 指向父对象的 prototype
function extend(Child, Parent) {var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
ES6 语法糖 extends:class ColorPoint extends Point {}
class ColorPoint extends Point {constructor(x, y, color) {super(x, y); // 调用父类的 constructor(x, y)
this.color = color;
}
toString() {return this.color + ' ' + super.toString(); // 调用父类的 toString()}
}
谈谈 this 对象的理解
this 总是指向函数的直接调用者
如果有 new 关键字,this 指向 new 出来的实例对象
在事件中,this 指向触发这个事件的对象
IE 下 attachEvent 中的 this 总是指向全局对象 Window
JS 阻止冒泡和取消默认事件(默认行为)
js 冒泡和捕获是事件的两种行为,使用 event.stopPropagation()起到阻止捕获和冒泡阶段中当前事件的进一步传播。使用 event.preventDefault()可以取消默认事件
防止冒泡和捕获
w3c 的方法是 e.stopPropagation(),IE 则是使用 e.cancelBubble = true
stopPropagation 也是事件对象(Event) 的一个方法,作用是阻止目标元素的冒泡事件,但是会不阻止默认行为。什么是冒泡事件?如在一个按钮是绑定一个”click”事件,那么”click”事件会依次在它的父级元素中被触发。stopPropagation 就是阻止目标元素的事件冒泡到父级元素
取消默认事件
w3c 的方法是 e.preventDefault(),IE 则是使用 e.returnValue = false;
preventDefault 它是事件对象(Event) 的一个方法,作用是取消一个目标元素的默认行为。既然是说默认行为,当然是元素必须有默认行为才能被取消,如果元素本身就没有默认行为,调用当然就无效了。什么元素有默认行为呢?如链接,提交按钮 <input type=”submit”> 等。当 Event 对象的 cancelable 为 false 时,表示没有默认行为,这时即使有默认行为,调用 preventDefault 也是不会起作用的
事件的三个阶段
捕获、目标、冒泡
介绍事件“捕获”和“冒泡”执行顺序和事件的执行次数?
按照 W3C 标准的事件:首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段
事件执行次数(DOM2-addEventListener):元素上绑定事件的个数
注意 1:前提是事件被确实触发
注意 2:事件绑定几次就算几个事件,即使类型和功能完全一样也不会“覆盖”
事件执行顺序:判断的关键是否目标元素
非目标元素:根据 W3C 的标准执行:捕获 -> 目标元素 -> 冒泡(不依据事件绑定顺序)
目标元素:依据事件绑定顺序:先绑定的事件先执行(不依据捕获冒泡标准)
最终顺序:父元素捕获 -> 目标元素事件 1 -> 目标元素事件 2 -> 子元素捕获 -> 子元素冒泡 -> 父元素冒泡
注意:子元素事件执行前提 事件确实“落”到子元素布局区域上,而不是简单的具有嵌套关系
在一个 DOM 上同时绑定两个点击事件:一个用捕获,一个用冒泡。事件会执行几次,先执行冒泡还是捕获?
该 DOM 上的事件如果被触发,会执行两次(执行次数等于绑定次数)
如果该 DOM 是目标元素,则按事件绑定顺序执行,不区分冒泡 / 捕获
如果该 DOM 是处于事件流中的非目标元素,则先执行捕获,后执行冒泡
事件的代理 / 委托
事件委托是指将事件绑定目标元素的到父元素上,利用冒泡机制触发该事件
优点:
可以减少事件注册,节省大量内存占用
可以将事件应用于动态添加的子元素上
缺点:使用不当会造成事件在不应该触发时触发
示例:
ulEl.addEventListener(‘click’, function(e){
var target = event.target || event.srcElement;
if(!!target && target.nodeName.toUpperCase() === "LI"){console.log(target.innerHTML);
}
}, false);
IE 与火狐的事件机制有什么区别?如何阻止冒泡?
IE 只事件冒泡,不支持事件捕获;火狐同时支持件冒泡和事件捕获