闭包
- 含义:闭包就是能够读取其他函数内部的变量
- 优点:可以避免全局变量的污染
- 缺点:闭包的变量不会被回收
function outer() {
var a = 666;
function inner() {
console.log(a);
}
return inner;
}
作用域
- 作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问
- 简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期
原型链
- 谈谈你对原型链的理解
每一个构造函数都有prototype属性,该属性指向原型
每一个实例都有_proto_属性,该属性指向原型
每一个原型都有construtor属性,该属性指向构造函数
Object原型对象最终指向null
- 经典题目
function Foo() {
getName = function () {
console.log(1);
};
return this;
}
Foo.getName = function () {
console.log(2);
}
Foo.prototype.getName = function () {
console.log(3);
}
var getName = function () {
console.log(4);
}
function getName() {
console.log(5);
}
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
ajax
var xhr = new XMLHttpRequest()
xhr.open('get', url, true)
xhr.send(null);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
success(xhr.responseText);
} else {
fail && fail(xhr.status);
}
}
数组扁平化(加强巩固)
const flatten = (arr) => {
let result = [];
arr.forEach((item, i, arr) => {
if (Array.isArray(item)) {
result = result.concat(flatten(item));
} else {
result.push(arr[i])
}
})
return result;
};
const flatten = (arr) => arr.toString().split(',');
function flatten(arr){
return arr.reduce(function(prev, cur){
return prev.concat(Array.isArray(cur) ? flatten(cur) : cur)
}, [])
}
function flatten(arr){
while(arr.some(item => Array.isArray(item))){
arr = [].concat(...arr);
}
return arr;
}
- ES2019 新增了 Array.prototype.flat 方法,可以直接扁平化,还能任意指定层数
- some + [].concat.apply
const flatten = (arr) => {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat.apply([], arr);
}
return arr;
}
this指向
var name = "windowsName";
function a() {
var name = "Cherry";
console.log(this.name);
console.log("inner:" + this);
}
a();
console.log("outer:" + this)
var name = "windowsName";
var a = {
name: "Cherry",
fn: function () {
console.log(this.name);
}
}
a.fn();
var name = "windowsName";
var a = {
fn: function () {
console.log(this.name);
}
}
window.a.fn();
var name = "windowsName";
var a = {
name: null,
fn: function () {
console.log(this.name);
}
}
var f = a.fn;
f();
var name = "windowsName";
function fn() {
var name = 'Cherry';
innerFunction();
function innerFunction() {
console.log(this.name);
}
}
fn()
- 改变 this 的指向
使用 ES6 的箭头函数
在函数内部使用 _this = this
使用 apply、call、bind
new 实例化一个对象
事件流
- 三个阶段:捕获阶段(capturing)、目标阶段(targeting)、冒泡阶段(bubbling)
- 阻止冒泡:在W3c中,使用stopPropagation()方法;在IE下设置cancelBubble = true
- 阻止捕获:阻止事件的默认行为,例如click - a 后的跳转。在W3c中,使用preventDefault()方法,在IE下设置window.event.returnValue = false
判断是否是数组(加强巩固)
var a = [];
a instanceof Array;
a.constructor === Array;
Array.prototype.isPrototypeOf(a);
Object.getPrototypeOf(a) === Array.prototype;
Object.prototype.toString.apply(a) === '[object Array]';
Array.isArray(a);
Array.isArray({ 0: 'a', length: 1 });
defer与async的区别
- async: 加载后立即执行,两者下载的过程不会阻塞 DOM,但执行会
- defer: 与 async 的区别在于,脚本需要等到文档解析后( DOMContentLoaded 事件前)执行
事件委托
- 事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件
<ul id="ul"></ul>
<script>
let ul = document.querySelector('#ul')
ul.addEventListener('click', (event) => {
console.log(event.target);
})
</script>
- 减少事件注册,节约内存
- 实现当新增子对象时无需再次对其绑定
数组常用方法(加强巩固)
- map: 遍历数组,返回回调返回值组成的新数组
- forEach: 无法break,可以用try/catch中throw new Error来停止
- filter: 过滤
- some: 有一项返回true,则整体为true
- every: 有一项返回false,则整体为false
- join: 通过指定连接符生成字符串
- push / pop: 末尾推入和弹出,改变原数组, 返回推入/弹出项
- unshift / shift: 头部推入和弹出,改变原数组,返回操作项
- sort(fn) / reverse: 排序与反转,改变原数组
- concat: 连接数组,不影响原数组, 浅拷贝
- slice(start, end): 返回截断后的新数组,不改变原数组
- splice(start, number, value...): 返回删除元素组成的数组,value为插入项,改变原数组
- indexOf / lastIndexOf(value, fromIndex): 查找数组项,返回对应的下标
- reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur为当前值(从第二项开始)
作用域
- 函数作用域
指在函数内声明的所有变量在函数体内始终是可见的,可以在整个函数的范围内使用及复用
- 块级作用域
指在变量声明的代码段之外是不可见的。参考:ES6的let以及const
- 词法作用域
指函数在定义它们的作用域里运行,而不是在执行它们的作用域里运行.而JavaScript采用的就是词法作用域,也称为静态作用域
执行上下文(加强巩固)
- 它包含三个部分
变量对象(VO)
作用域链(词法作用域)
this指向
- 它的类型
全局执行上下文
函数执行上下文
eval执行上下文
- 代码执行过程
创建 全局上下文 (global EC)
全局执行上下文 (caller) 逐行 自上而下 执行。遇到函数时,函数执行上下文 (callee) 被push到执行栈顶层
函数执行上下文被激活,成为 active EC, 开始执行函数中的代码,caller 被挂起
函数执行完后,callee 被pop移除出执行栈,控制权交还全局上下文 (caller),继续执行
数组去重
- Array.from(new Set(arr))
- [...new Set(arr)]
- splice()
- indexOf()
- includes()
- Map()
- Sort()
继承(加强巩固)
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function () {
return this.property;
}
function SubType() {
this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
return this.subproperty;
}
var instance = new SubType();
console.log(instance.getSuperValue());
function SuperType(){
this.color=["red","green","blue"];
}
function SubType(){
SuperType.call(this);
}
var instance1 = new SubType();
instance1.color.push("black");
alert(instance1.color);
var instance2 = new SubType();
alert(instance2.color);
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;
}
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors);
instance1.sayName();
instance1.sayAge();
var instance2 = new SubType("Greg", 27);
alert(instance2.colors);
instance2.sayName();
instance2.sayAge();
function object(obj){
function F(){}
F.prototype = obj;
return new F();
}
function createAnother(original){
var clone = object(original);
clone.sayHi = function(){
alert("hi");
};
return clone;
}
function inheritPrototype(subType, superType){
var prototype = Object.create(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;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
}
var instance1 = new SubType("xyc", 23);
var instance2 = new SubType("lxy", 23);
instance1.colors.push("2");
instance1.colors.push("3");
function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}
MyClass.prototype = Object.create(SuperClass.prototype);
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
MyClass.prototype.constructor = MyClass;
MyClass.prototype.myMethod = function() {
};
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea()
}
calcArea() {
return this.height * this.width;
}
}
const rectangle = new Rectangle(10, 20);
console.log(rectangle.area);
-----------------------------------------------------------------
class Square extends Rectangle {
constructor(length) {
super(length, length);
this.name = 'Square';
}
get area() {
return this.height * this.width;
}
}
const square = new Square(10);
console.log(square.area);
dom 操作有哪些 api
- 创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
- 添加、移除、替换、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //插入
- 查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
判断变量的几种方式,有哪些不同
- typeof
typeOf能判断出一个变量的类型,但是只能判断出number,string,function,boolean,undefined,null和其他对象类型返回结果都为object
- instanceof
instanceof能判断出一个对象是否是另一个类的实例
- Object.prototype.toString.call
Object.prototype.toString.call能判断出所有变量的类型,返回值为[Object ***]
null和undefined的区别
三大家族(offset、scroll、client)
- offsetWidth/offsetHeight
返回值包含content + padding + border,效果与e.getBoundingClientRect()相同
- clientWidth/clientHeight
返回值只包含content + padding,如果有滚动条,也不包含滚动条
- scrollWidth/scrollHeight
返回值包含content + padding + 溢出内容的尺寸
谈谈对CommonJS,AMD,CMD,ES6 Module的理解
| 规范 | 代表 | 说明 |
|---|
| CommonJS | Node.js | 同步加载模块,在服务端,模块文件都存在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,会出现堵塞情况,所以不适用。CommonJS的风格通过对module.exports或exports的属性赋值来达到暴露模块对象 |
| ES6 Module | ES6 | 一个模块就是一个独立的文件,该文件内部的所有变量,外部无法改变。两个命令:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能 |
| AMD | require.js | 采用异步方式加载模块,需要定义回调define方式,require.js实现AMD规范的模块化 |
| CMD | sea.js | CMD与AMD类似,但不同点在于:AMD推崇依赖前置、提前执行,CMD推崇依赖就近、延迟执行。sea.js实现CMD规范的模块化 |
eval的作用
- 它的功能是把对应的字符串解析成JS代码并运行
- 应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)
- 由JSON字符串转换为JSON对象的时候可以用eval,var obj =eval('('+ str +')')
callee和caller的作用
- caller是返回一个对函数的引用,该函数调用了当前函数
- callee是返回正在被执行的function函数,也就是所指定的function对象的正文
内存泄漏的情况(加强巩固)
- 定义
程序中己动态分配的堆内存由于某种原因程序未释放或无法释放引发的各种问题
- 结果
崩溃,延迟大等
- 原因
全局变量
dom清空时,还存在引用
使用闭包
定时器未清除
子元素存在引起的内存泄露
- 避免策略
减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收
注意程序逻辑,避免“死循环”之类的
避免创建过多的对象 原则:不用了的东西要及时归还
减少层级过多的引用