在此分享、整理前端面试题,若有解答错误的地方,烦请各位大佬指正,感谢!!javascript
每一个函数都有一个 prototype 属性,函数的 prototype属性指向了一个对象,这个对象正是调用该构造函数而建立的实例的原型前端
那什么是原型呢?你能够这样理解:每个JavaScript对象(null除外)在建立的时候就会与之关联另外一个对象,这个对象就是咱们所说的原型,每个对象都会从原型"继承"属性。java
这是每个JavaScript对象(除了 null )都具备的一个属性,叫__proto__,这个属性会指向该对象的原型。git
原型链解决的主要是继承问题。github
每一个对象拥有一个原型对象,经过 proto 指针指向其原型对象,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null(Object.proptotype.proto 指向的是null)。这种关系被称为原型链 (prototype chain),经过原型链一个对象能够拥有定义在其余对象中的属性和方法。面试
function Person() {
}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true
复制代码
function Person() {
}
console.log(Person === Person.prototype.constructor); // true
复制代码
function Person() {
}
var person = new Person();
console.log(person.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true
// 顺便学习一个ES5的方法,能够得到对象的原型
console.log(Object.getPrototypeOf(person) === Person.prototype) // true
复制代码
做用域是指程序源代码中定义变量的区域。数组
做用域规定了如何查找变量,也就是肯定当前执行代码对变量的访问权限。promise
变量声明提高:
foo; // undefined
var foo = function () {
console.log('foo1');
}
foo(); // foo1,foo赋值
复制代码
能够想象成:全部的声明(变量和函数)都会被“移动”到各自做用域的最顶端
JS 中分为七种内置类型,七种内置类型又分为两大类型:基本类型和对象(Object)。
基本类型有六种: null,undefined,boolean,number,string,symbol。
栈
内存(不包含闭包中的变量)堆
内存引用类型有:Object、Array、Date、RegExp、Function
var arr = [1,2,3,4,5,6,7,8,9,10];
var newArr = [];
let length=arr.length
for(let i=0;i<length;i++){
let randomIndex = Math.floor(Math.random()*arr.length);
newArr[i]=arr[randomIndex]
arr.splice(randomIndex,1)
}
console.log(newArr)
复制代码
call和apply的区别在于传入参数的不一样; 第一个参数都是,指定函数体内this的指向;
第二个参数开始不一样,apply是传入带下标的集合,数组或者类数组,apply把它传给函数做为参数,call从第二个开始传入的参数是不固定的,都会传给函数做为参数。
call比apply的性能要好,日常能够多用call,
call传入参数的格式正是内部所须要的格式,
闭包:函数 A 返回了一个函数 B,而且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。
做用有:
封装私有变量 模仿块级做用域(ES5中没有块级做用域) 实现JS的模块
function _new(fn, …arg) {
const obj = Object.create(fn.prototype);
const ret = fn.apply(obj, arg);
return ret instanceof Object ? ret : obj;
}
复制代码
ECMAScript6是ES2015标准;
AMD规范:是 RequireJS在推广过程当中对模块定义的规范化产出的,
CMD规范:是SeaJS 在推广过程当中对模块定义的规范化产出的。 区别
CMD 推崇依赖就近;AMD 推崇依赖前置
CMD 是延迟执行;AMD 是提早执行
CMD性能好,由于只有用户须要的时候才执行;AMD用户体验好,由于没有延迟,依赖模块提早执行了
垃圾回收是一种内存管理机制。咱们声明一个变量和函数的时候都会占用内存,可是内存容量有限,当一个变量离开执行环境的时候。考虑到它不会再使用的,就会被回收,释放内存
方法:
内存泄漏是指计算机可用的内存愈来愈少,主要是由于程序不能释放那些再也不使用的内存。
无心的全局变量、循环、定时器、回调
强缓存表示在缓存期间不须要请求,state code 为 200 expires(本地过时时间)和cache-control(单位是秒,多少秒后过时),cache-control优于expires
若是缓存过时了,咱们就可使用协商缓存来解决问题。协商缓存须要请求,若是缓存有效会返回 304。
冒泡排序
重复遍历全部的元素,两个元素比较,若是大小顺序不对,就交换它们的位置。重复遍历直到没有再须要交换,排序完成。
function bubbleSort(arr) {
var len = arr.length;
for (var i = 0; i < len; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) { //相邻元素两两对比
var temp = arr[j+1]; //元素交换
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
复制代码
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) { //寻找最小的数
minIndex = j; //将最小数的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
复制代码
function insertionSort(arr) {
var len = arr.length;
var preIndex, current;
for (var i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i];
while(preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex+1] = arr[preIndex];
preIndex--;
}
arr[preIndex+1] = current;
}
return arr;
}
复制代码
function quickSort(arr, left, right) {
var len = arr.length,
partitionIndex,
left = typeof left != 'number' ? 0 : left,
right = typeof right != 'number' ? len - 1 : right;
if (left < right) {
partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex-1);
quickSort(arr, partitionIndex+1, right);
}
return arr;
}
function partition(arr, left ,right) { //分区操做
var pivot = left, //设定基准值(pivot)
index = pivot + 1;
for (var i = index; i <= right; i++) {
if (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
swap(arr, pivot, index - 1);
return index-1;
}
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
复制代码
实现继承 主要是依靠原型链来实现的.
布尔值 let isDone: boolean = false;
数字
全部数字类型都是浮点数
let decLiteral: number = 6;
字符串
模版字符串也是这个类型
let name: string = "bob";
数组
元组
元组类型容许表示一个已知元素数量和类型的数组,各元素的类型没必要相同。 好比,你能够定义一对值分别为 string和number类型的元组。
let x: [string, number];
枚举enum
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
复制代码
nerver
Object
Null 和 Undefined
Void
Any
var 和 let 用以声明变量,const 用于声明只读的常量;
var 声明的变量,不存在块级做用域,在全局范围内都有效,let 和 const 声明的,只在它所在的代码块内有效;
let 和 const 不存在像 var 那样的 “变量提高” 现象,因此 var 定义变量能够先使用,后声明,而 let 和 const 只可先声明,后使用;
let 声明的变量存在暂时性死区,即只要块级做用域中存在 let,那么它所声明的变量就绑定了这个区域,再也不受外部的影响。
let 不容许在相同做用域内,重复声明同一个变量;
const 在声明时必须初始化赋值,一旦声明,其声明的值就不容许改变,更不容许重复声明;
如 const 声明了一个复合类型的常量,其存储的是一个引用地址,不容许改变的是这个地址,而对象自己是可变的。
变量与内存之间的关系,主要由三个部分组成:
变量名
内存地址
内存空间
JS 引擎在读取变量时,先找到变量绑定的内存地址,而后找到地址所指向的内存空间,最后读取其中的内容。当变量改变时,JS 引擎不会用新值覆盖以前旧值的内存空间(虽然从写代码的角度来看,确实像是被覆盖掉了),而是从新分配一个新的内存空间来存储新值,并将新的内存地址与变量进行绑定,JS 引擎会在合适的时机进行 GC,回收旧的内存空间。
const 定义变量(常量)后,变量名与内存地址之间创建了一种不可变的绑定关系,阻隔变量地址被改变,当 const 定义的变量进行从新赋值时,根据前面的论述,JS 引擎会尝试从新分配新的内存空间,因此会被拒绝,便会抛出异常。
处理中文输入,在input框绑定compositionsend,就能够监听中文输入结束
简化版
var request = new XMLHttpRequest();
request.open('GET', '/xxx');
request.onload = () => {console.log('请求成功'};
request.send();
复制代码
详细版
var request = new XMLHttpRequest();
request.open('GET', 'xxx');
request.onreadystatechange = function() {
if(request.readyState === 4 ) {
console.log('请求完成');
if(request.respondse.status >=200 && request.respondse.status) {
console.log('请求成功')
}else{
}
}
}
request.send();
复制代码
经常使用:使用JSON.parse(JSON.stringify(obj))
原理是把一个对象序列化成为一个JSON字符串,将对象的内容转换成字符串的形式再保存在磁盘上,再用JSON.parse()反序列化将JSON字符串变成一个新的对象
缺点是: 会忽略undefined、symbol、funciton
实现:递归+判断类型
一个简单的代码
// 数字 字符串 function是不须要拷贝的
function deepClone(value) {
if (value == null) return value;
if (typeof value !== 'object') return value;
if (value instanceof RegExp) return new RegExp(value);
if (value instanceof Date) return new Date(value);
// 我要判断 value 是对象仍是数组 若是是对象 就产生对象 是数组就产生数组
let obj = new value.constructor;
for(let key in value){
obj[key] = deepClone(value[key]); // 看一看当前的值是否是一个对象
}
return obj;
}
复制代码
function Promise(executor) {
let self = this;
self.status = 'pending'; //等待态
self.value = undefined; //成功的返回值
self.reason = undefined; //失败的缘由
function resolve(value){
if(self.status === 'pending'){
self.status = 'resolved';
self.value = value;
}
}
function reject(reason) {
if(self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
}
}
try{
executor(resolve, reject);
}catch(e){
reject(e);// 捕获时发生异常,就直接失败
}
}
//onFufiled 成功的回调
//onRejected 失败的回调
Promise.prototype.then = function (onFufiled, onRejected) {
let self = this;
if(self.status === 'resolved'){
onFufiled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
}
module.exports = Promise;
复制代码
window.onload--页面上全部的DOM,样式表,脚本,图片都已经加载完成
document.onload/document.body.onload--仅当DOM加载完成,--也就是DOMContentLoaded的时间(打开devtools-network-DOMContentLoaded)
splice做用于数组,会修改原数组,有删除或替换、添加的功能,返回被删除的元素,若是没有元素被删除,返回空数组
var months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// inserts at index 1
console.log(months);
// expected output: Array ['Jan', 'Feb', 'March', 'April', 'June']
months.splice(4, 1, 'May');
// replaces 1 element at index 4
console.log(months);
// expected output: Array ['Jan', 'Feb', 'March', 'April', 'May']
复制代码
slice能够做用于数组和字符串,不修改选数组,返回一个新数组
var animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
console.log(animals.slice(2));
// expected output: Array ["camel", "duck", "elephant"]
console.log(animals.slice(2, 4));
// expected output: Array ["camel", "duck"]
复制代码