前端面试知识点总结——JS篇

1、创建对象的3种方式

//字面量创建对象
var obj1 = { name = "zhang"};
var obj2 = new Object({ name: "li" });

//构造函数创建对象
var O = function () {
	this.name = "wang";
}
var obj3 = new O();

//Object.create创建对象
var p = { name: "zhao"};
var obj4 = Object.create(p);

2、JS的数据类型

数据类型分类:
1、基本数据类型:Undefined、Boolean、String、Number、Null、Symbol(ES6新定义)
基本类型存储在栈内存种,数据大小确定,内存空间大小可以分配,按值存放,所以可直接访问。

2、引用类型(Object对象):对象、数组、函数、日期、正则
引用类型存放在堆中,引用类型存放在堆内存中,变量实际上是一个存放在栈内存中的指针,这个指针指向堆内存中的地址,每个空间的大小不一样,要根据情况进行特定的分配。

数据类型的判断:
1、typeof:返回的是一个数据类型的字符串,返回结果包括:number、boolean、string、symbol、object、undefined、function等7种数据类型,但不能判断null、array等。

2、instanceof:用来判断A是否为B的实例,A instanceof B,返回Boolean值。instanceof用来测试一个对象在其原型链种是否存在一个构造函数prototype属性,但它不能够检测null和undefined。

3、Object.prototype.toString.call():最准确最常用,所有数据类型都能够判断。

3、原型链

1、JavaScript种的继承是通过原型链来体现的。
2、每一个对象都有一个__proto__属性,指向构造函数的prototype。
3、访问一个对象的属性时,现在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链。
在这里插入图片描述

4、DOM事件

1、DOM事件级别:

//DOM0
element.onclick = function(){}

//DOM2
element.addEventListener('click',function(){
	//false为冒泡阶段,true为捕获阶段
},false);

//DOM3
element.addEventListener('keyup',function(){

},false);

2、事件流:用户与浏览器当前页面的交互过程,可以分为三个阶段(捕获阶段、目标阶段、冒泡阶段)

3、事件模型:事件捕获、事件冒泡

5、事件循环(Event Loop)

JavaScript是一门单线程的执行语言,处理任务的时候是一件一件往下处理。

浏览器在执行js代码过程中维护了一个执行栈,每个方法都会进入执行栈执行之后出栈。于此同时,浏览器又维护了一个消息队列,所有的异步方法,在执行结束后都将回调方法塞入消息队列中,当所有执行栈中的任务全部都执行完毕后,浏览器开始往消息队列中寻找任务,先进消息队列的先执行。

宏任务和微任务
宏任务:js同步执行的代码块:setTimeout、setInterval、XMLHttprequest等
微任务:promise、process.nextTick(node环境)等
执行栈中执行的任务都是宏任务,当宏任务遇到Promise的时候会创建微任务,当Promise状态fulfill的时候塞入微任务队列。在一次宏任务完成之后,会检查微任务队列有没有需要执行的任务,有的话按照顺序执行微任务中的所有任务。之后再开始执行下一次宏任务。具体步骤如下:
1、执行主代码块
2、若遇到Promise,把then之后的内容放进微任务队列
3、一次宏任务执行完成,检查微任务队列有无任务
4、有的话执行所有微任务
5、执行完毕后,开始下一次宏任务。

6、闭包

闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。通俗来说,闭包就是能够读取其他函数内部变量的函数。

变量的作用域:全局变量和局部变量(函数内部可以直接读取全局变量,函数外部自然无法读取函数内的局部变量)

闭包的用途:一个是可以读取函数内部的变量,另一个是可以让这些变量的值始终保持在内存中。

7、Promise

promise就是将异步任务队列化,将多个异步任务按照顺序输出,同时用链式调用解决回调地狱(函数作为参数层层嵌套)的问题。

用法:

var p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('我是异步返回的数据')
  }, 1000);
});

p.then(data => {
  console.log(data);
});

promise规范:

  • 存在三个状态:等待态(pending),执行态(fulfilled),失败态(rejected)
  • 初始态为等待态,可以转化为执行态和失败态
  • 执行态不可转化为其他状态,且必须有一个不可变的终值(value)
  • 失败态不可转化为其他状态,且必须有一个不可变的原因(reason)
  • 必须提供一个then方法,以供访问其当前值,终值及原因
  • then方法提供两个参数:onFulfilled和onRejected
  • onFulfilled和onRejected如果不是函数类型,必须忽略
  • 如果executor执行报错,直接执行reject
  • 不同的promise可以相互套用

8、this指向问题

this的指向不是在函数定义时确定的,而是在函数调用时确定
this默认情况下指向window,严格模式下为undefined

隐式绑定:即this指向距离其最近的调用者

// this的隐式绑定
function fn() {
  console.log(this);
}

var obj = {
  name: 'zhang',
  fn: function () {
    console.log(this);
  }
}

fn(); // window
obj.fn(); // {name: "zhang", fn: ƒ}

显式绑定(强制修改): 在JavaScript中,有一些函数可以强制修改this的指向,如call, apply, bind等。

  1. call, apply, bind 中的this会指向传入的第一个参数
  2. 如果这些函数调用时没有传入参数,则指向默认对象(window或undefined)

构造函数中的this指向: 构造函数中的this指向该函数创建的实例对象

箭头函数中的this指向: 因为箭头函数本身并不存在this,是由其父级作用域继承而来。箭头函数中的this无法通过bind、call、apply进行修改。

立即执行函数中的this指向: 立即执行函数中的this永远指向window

9、ES6的新特性

1、let和const命令的出现

  • let和const区别:const定义一个只读常量,一旦声明变量,就必须立即初始化,不能留到以后赋值且不可改变。
  • 不存在变量提升,声明的变量一定要在声明后使用,否则报错
  • 不允许重复声明变量,不允许在相同作用域内,重复声明同一个变量
  • 块级作用域,ES6之前只有函数作用域与全局作用域,一个大括号即一个块级作用域
  • 声明的变量不在属于window

2、解构赋值
解构赋值是对赋值运算符的扩展。
他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。

3、函数的扩展
箭头函数、REST参数

4、数组的扩展
扩展运算符:
用途:(1)复制数组、(2)合并数组、(3)函数的rest参数

5、对象上的扩展
1、可遍历性:for...inObject.key(obj)
2、super关键字的增加
3、新增方法Object.is()(对象的比较)、Object.assign()(对象的拷贝克隆合并)

6、set和map结构

Set(集合)[类数组]: 它类似于数组,但是成员的值都是唯一的,没有重复的值

const s = new Set();

[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

for (let i of s) {
  console.log(i);   // 2 3 5 4
}

// 去除数组的重复成员
let array = [1,2,1,4,5,3];
[...new Set(array)]     // [1, 2, 4, 5, 3]

属性
size:返回字典所包含的元素个数

操作方法

  • add(value):添加某个值,返回 Set 结构本身。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是否为 Set 的成员。
  • clear():清除所有成员,无返回值。
  • size: 返回set数据结构的数据长度

Map (字典)[类对象]: 它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键,是一种更完善的 Hash 结构实现。

集合和字典的区别:
共同点:集合、字典可以存储不重复的值
不同点:集合是以[值,值]的形式存储元素,字典是以[键,值]的形式存储

const m = new Map();
const o = {p: 'Hello World'};
m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false

属性
size:返回字典所包含的元素个数

操作方法

  • set(key, val): 向字典中添加新元素
  • get(key):通过键值查找特定的数值并返回
  • has(key):如果键存在字典中返回true,否则false
  • delete(key): 通过键值从字典中移除对应的数据
  • clear():将这个字典中的所有元素删除

10、JS数组操作

  • toString(): toString() 方法能够将数组转换为以逗号分隔的字符串。
  • join(): join() 方法将所有数组元素组合成一个字符串。返回一个以参数为分隔符的字符串。
  • concat: 将两个数组组合在一起,或者向数组中添加更多的元素项,然后返回一个新数组。
  • push(): 将元素项添加到数组的末尾,并修改原始数组。
  • pop(): 此方法删除数组的最后一项并返回。
  • shift(): 此方法删除数组的第一项,并将它返回。
  • unshift(): 此方法将一个项添加到数组的开头,并修改原始数组。
  • splice(): 此方法通过添加、删除和插入元素来修改数组。
    array.splice(index[, deleteCount, element1, ..., elementN])
    • Index 这里是删除数组中元素的起点
    • deleteCount 是要从该索引中删除的元素数
    • element1, , elementN 是要添加的元素

注意: deleteCount 不包括范围内的最后一个索引
如果没有声明第二个参数,则将会从数组中删除从给定索引开始的所有元素
要添加项目,我们需要将 deleteCount 设置为零

  • slice(): 此方法复制数组的给定部分,并将复制的部分作为新数组返回。 它不会改变原始数组。
array.slice(start, end)
let numbers = [1, 2, 3, 4]
numbers.slice(0, 3)
// returns [1, 2, 3]
  • split(): 此方法用于字符串。它将一个字符串分成子串并将它们作为数组返回。
  • indexOf(): 此方法在数组中查找项目,如果它被找到就返回索引,否则返回 -1
  • lastIndexOf(): 这种方法的工作方式与 indexOf() 相同,只是它从右到左工作。它返回找到的最后一个索引
  • filter(): 如果数组的项目符合某个条件,则此方法将会创建一个新数组。
  • map(): 此方法通过操作数组中的值来创建新数组。
  • reduce(): 此方法适用于计算总计的值。
let sum = [1, 2, 3, 5].reduce((acc, current) => {
 return acc + current 
}, 0)

11、深拷贝&浅拷贝

对于基本数据类型的拷贝,并没有深浅拷贝的区别,我们所说的深浅拷贝都是对于引用数据类型而言的。
浅拷贝的意思就是只复制引用,而未复制真正的值。
深拷贝就是对目标的完全拷贝,不像浅拷贝那样只是复制了一层引用,就连值也都复制了

目前实现深拷贝的方法不多,主要是两种:

  • 利用 JSON 对象中的 parse 和 stringify

undefined、function、symbol 会在转换过程中被忽略

  • 利用 递归 来实现每一层都重新创建对象并赋值
function deepClone(source){
  const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
  for(let keys in source){ // 遍历目标
    if(source.hasOwnProperty(keys)){
      if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
        targetObj[keys] = source[keys].constructor === Array ? [] : {};
        targetObj[keys] = deepClone(source[keys]);
      }else{ // 如果不是,就直接赋值
        targetObj[keys] = source[keys];
      }
    } 
  }
  return targetObj;
}

12、前端跨域的集中方式

  1. CORS跨域 (全拼 cross-origin resource sharing,意思是跨域资源共享)

注意: 所以要使用 CORS 进行跨域的话,必须注意客户端和服务器必须同时支持。

请求方法为三种方法之一:HEAD、GET、POST
HTTP的头信息不超出这几种字段:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type
简单请求:浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。
非简单请求:非简单请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为 预检请求(preflight)。

  1. jsonp跨域

jonsp跨域的原理是通过动态创建script的标签的形式来实现跨域的,因为script不受同源策略的影响。但是jsonp只能接受get方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值