前端常见面试题汇总

一 、JS基础
1、数据类型
(1)基本数据类型6:(值类型,存在栈内存中,操作系统自动分配释放)
数字(number):正常表示的是2的正负53次方,超出范围仍然可以运算,但精度不准,可以用大数进行处理,超过限制的数字被分割成数组。进制的转换(2、8、10、16):1)其他进制转为10进制:parseInt(值,几进制)会将规定的几进制的值转为对应的10进制的 2)10进制转为其他进制:值.toString(几进制)
特殊值:NaN(表示不是一个数字,它的类型检测是‘number’),Infinity(-Infinity ) 超出范围返回的值
Number()转为数字类型,parseInt()用于将数字转整数,其他类型会为NaN,parseFloot()只保留到一个小数点后的值

// 判断NaN时得注意,NaN===NaN // false,使用isNaN()判断,但是它不准确,是非数字就会返回true,不管是数字或布尔和字符串的+操作,都会转为字符串
// 何时会成为NaN
// 数字与字符串的-、*、%、/ 都会得到NaN,会先转数字,再进行操作
console.log(12 - "apple"); // 12 - "apple" = NaN
console.log("12" - "apple"); // "12" - "apple" = NaN

console.log(12 * "apple"); // 12 * "apple" = NaN
console.log("12" * "apple"); // "12" * "apple" = NaN

console.log(12 / "apple"); // 12 / "apple" = NaN
// "12" 转为 number进行除法运算,但是 "apple" 非数字字符串,最后得出 NaN
console.log("12" / "apple"); //"12" / "apple" = NaN

console.log(12 % "apple"); //NaN
console.log("12" % "apple"); //NaN

字符串(string):字符串单引号 或多引号包,模版字符串``
构造函数为String()
布尔(boolean)
undefined
null
symbol(es6引入):可以解决属性名冲突的问题,只有字符串和symbol才能作为对象的属性名,没有两个symbol的值是相等的,Symbol不是构造函数,使用new会报错。直接用Symbol()创建
⚠️:用Symbol.for()创建带有相同description的两个symbol的值相等,const symbol1 = Symbol.for(‘test’);
const symbol2 = Symbol.for(‘test’);
一般用于解决命名冲突,用symbol命名的属性,不会出现在Object.keys()的结果中,可以用Object.getOwnPropertySymbols() 函数获取,还有JSON.stringify() 会忽略Symbol的属性名和属性值。

(2)复杂数据类型(引用类型,存储的是地址引用):数组Array、对象Object、函数Function、Date类型、RegExp正则函数存放在操作系统的堆内存中,一般由程序员进行分配释放,若不释放则垃圾回收机制会回收。

2、变量及作用域(全局作用域、函数作用域、块级作用域。以{}包的、js是静态作用域也叫词法作用域,由声明所处的位置决定(就是写代码时将变量或块级作用域写在哪里决定的),进行变量查找),即变量访问的有效范围。
var(一般不用,它存在变量提升)
let 不存在变量提升,不能在声明前使用
const(1、声明时赋初始值2、值不能被修改 3、不能重复多次声明)
⚠️ let、const存在暂时性死区:在声明前使用报错

// 静态作用域、动态作用域
var val = 1;
function test() {
    console.log(val);
}
function bar() {
    var val = 2;
    test();
}
 
bar();
// 结果是???1
// 因为静态作用域是只在定义它的时候决定,跟调用它的环境无关。静态作用域首先从定义函数的位置查找,没有就从上一层中查找。而动态作用域的执行过程:首先从函数内部查询,如果没有就从调用它的作用域 链查找。函数定义的位置就决定了函数的作用域,遇到题目时不要被别的代码干扰到。看变量有无执行

3、数据类型判断
(1)typeof(有bug)

// typeof能检测到的数据有function、string,number,boolean, undefined,symbol,其他所有的类型,都会被检测为object。
// 所以会将null和数组都检测为'object'

(2)instanceof(只能用来检测对象或函数) 检测某个对象是不是另一个对象的实例

 arr instanceof Array  检测arr是不是内置类Array的实例

(3)constructor(指向它的构造函数),不稳定,函数的构造函数是可以重写的,当开发者重写 prototype 原型后,原有的 constructor 引用会丢失,constructor 会默认为 Object。

console.log(a.constructor === Array); // 返回布尔值

(4)Object.prototype.toString.call() 推荐使用,简单和复杂类型都可使用,判断某个对象值属于哪种内置类型

 console.log(Object.prototype.toString.call(date));//'[object Array]'

4、this指向问题:指向调用时的对象
(1)普通函数调用:指向全局对象,浏览器中就是window。在严格模式在是undefined
(2)对象中方法调用:this指向调用方法的对象
(3)构造函数调用(new 调用):this指向新创建出来的对象
(4)上下文模式(可以修改this指向 call apply bind 它们是函数原型上添加的方法): 指向第一个参数,若第一个参数是null或undefined则指向全局对象window
⚠️:apply(传的第二参数是数组)、call(传的列表参数)修改this指向后直接执行,bind是返回一个新函数,主体与原来函数相同(适合用于修改定时器的this指向)

(5)箭头函数的this指向:根据当前的词法作用域(静态作用域)来决定this的指向,箭头函数会继承外层函数,没有外层函数则window,是指向它定义时所在的作用域中(没有自己的this,创建时外部函数的this)
改变它的指向不用apply、call、bind可用构造函数做

 let fn = () => {
    console.log(this === window); // true,创建所在的作用域就是全局
  };
  let a = {};
  fn();
  a.print = fn;
  a.print(); // true this始终指向创建时指向的window,跟调用无关

(6)定时器中this指向:this指向window,定时器是定义在window下的。
改变时可用bind方法(使用bind函数绑定过后函数的this将永久被改变,无论调用方式如何,总是指向绑定的对象。已经被bind过的函数不会再bind到其他对象上)
(7)闭包中this指向:匿名函数中this指向window,可用变量的形式保存上层函数this对象(函数包函数的情况)
(8)DOM事件函数:一般指向绑定事件的DOM元素。
(9)类中super中this指向
在es6对象扩展中,对象方法中的super指向当前对象的原型对象
在类的继承中子类使用super

// super作为方法:只能在子类构造函数中使用,指向父类构造方法,this指向子类实例即可以得到父的 属性和方法

// super作为对象:1)在普通方法中指向父原型,this指向子实例
(2)在静态方法中指向父类(访问父的静态 方法 和属性)this指向子类

优先级:箭头函数>new 调用 > call、apply、bind 调用 > 对象上的函数调用 > 普通函数调用

5、闭包:有权访问另一函数作用域的函数(函数内部创建函数),利用作用域访问原则
闭包占用内存多,会引起内存泄漏问题

6、事件循环(超高频)和node中的区别:js之所以是单线程,因为浏览器只分配一个线程来执行js代码,因为js不适合多线程,例如一个在节点删内容,一个添加内容,到底执行哪个,但单线程就造成很多任务需要等待执行,即引入浏览器的事件循环机制
js主线程不断的循环往复的从任务队列中读取任务,这种运行机制称为事件循环
js任务分为同步任务和异步任务,事件循环又有宏任务和微任务
执行 顺序:宏任务/所有微任务/浏览器渲染/下一个宏任务(主栈队列就是一个宏任务)

Node.js是谷歌v8引擎上开发的框架,用于创建服务器端web应用程序
补充 node中的事件循环????

7、手写Promise:异步操作,一般执行耗时不想阻塞的内容(解决了回掉地狱的问题)

// 实现promise
// 状态会多次用于判断,所以建议用常量保存
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled'  // 成功
const REJECTED = 'rejected'  // 失败

class Promise {
    successCallBack = [] // 用来存储状态成功的回调函数
    errorCallBack = []  // 用来存储状态失败的回调函数
    constructor(handler) {
        // 构造函数需要参数,参数必须是一个函数类型 这里面我们叫做handler,这儿会对                handler类型进行验证,如果不是函数类型会抛出类型异常
        if (typeof handler !== 'function') {
            throw new TypeError(`Promise构造函数的参数${handler}不是一个函数`)
        }
        this.state = PENDING // 用来存储promise的状态 初始化状态为pending
        this.reason = undefined // 拒因返回值
        this.value = undefined // 成功返回值终值
        // resolve,reject方法里面会用到实例的this,在调用的时候需要改变this的指向
        handler(this.resolve.bind(this), this.reject.bind(this)) //  执行参数成功或失败函数
    }
    resolve(value) {
        // 该方法只能在promise状态为pending的时候调用,如果promise已经有了状态,则不允许调用
        if (this.state !== PENDING) return
        // 调用方法promise的状态变为fulfilled
        this.state = FULFILLED
        // 调用该方法会得到一个终值value
        this.value = value
        // 异步调用的时候执行存储的onFulfilled函数,传入终值
        this.successCallBack.forEach(fn => fn())
    }
reject(reason) {
        // 该方法只能在promise状态为pending的时候调用,如果promise已经有了状态,则不允许调用
        if (this.state !== PENDING) return
        // 调用方法promise的状态变为rejected 
        this.state = REJECTED
        // 调用该方法会得到一个拒因reason
        this.reason = reason
        // 异步调用的时候执行存储的onRejected函数,传入拒因
        this.errorCallBack.forEach(fn => fn())
    }
    
    then(onFulfilled, onRejected) {
        // 每一次调用返回一个promise
        return new Promise((resolve,reject) => {
            // 参数可选要进行判断 如果传递不是一个函数 默认一个函数
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
            onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
            if (this.state === PENDING) {
                // 当resolve或者reject异步调用,then执行的时候promise状态等待
                // 将onFulfilled和onReject函数存储起来
                this.successCallBack.push(() => {
                    let result = onFulfilled(this.value)
                    this.handlerChainPromise(result, resolve, reject)
                })
                this.errorCallBack.push(() => {
                    let result = onRejected(this.reason)
                    this.handlerChainPromise(result, resolve, reject)
                })
            }
            if (this.state === FULFILLED) {
                // 当promise状态为fulfilled时候调用onFulfilled
                let result = onFulfilled(this.value)
                this.handlerChainPromise(result, resolve, reject)
            }
            if (this.state === REJECTED) {
                // 当promise状态为rejected时候调用onRejected
                let result = onRejected(this.reason)
                this.handlerChainPromise(result, resolve, reject)
            }
        })
    }
    handlerChainPromise(result,resolve,reject){
        // 如果返回的是一个promise就调用它的then方法
        // 如果返回的是一个具体值就直接返回值
        if(result instanceof Promise){
            result.then(resolve, reject)
        }else{
            resolve(result)
        }
    }
}

8、异步同步:异步模式:回调函数、事件监听、观察者模式、promise、定时器、async await
"同步模式"就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

// 回调函数详解。同步优先=>异步=>回掉。 回调地狱(顺序执行异步函数)
// 第一个任务
function task1 (callback) {
  setTimeout(() => {
    console.log('1', '我是第一个任务,必须第一个执行');
    callback && callback(1);
  }, 3000);
}

// 第二个任务
function task2 (callback) {
  setTimeout(() => {
    console.log('2', '我是第二个任务');
    callback && callback(2);
  }, 1000);
}

// 第三个任务
function task3 (callback) {
  setTimeout(() => {
    console.log('3', '我是第三个任务');
    callback && callback(3);
  }, 1000);
}

// 所有任务
function allTasks () {
  task1((cb1) => {
    if (cb1) {
      task2((cb2) => {
        if (cb2) {
          task3((cb3) => {
            if (cb3) {
              // 顺序完成所有任务
            }
          })
        }   
      });
    }
  });
}

allTasks();

/**
 * 3秒后
 * 1 我是第一个任务,必须第一个执行
 * 1秒后
 * 2 第二个任务
 * 1秒后
 * 3 第三个任务
 */

// 优化用Promise实现,解决不易阅读的问题
new Promise(resolve => {
  setTimeout(() => {
    console.log('1', '我是第一个任务,必须第一个执行');
    resolve(1); // 当定时器执行后才进行then中方法
  }, 3000);
}).then((val) => {
  new Promise(resolve => {
    setTimeout(() => {
      console.log('2', '我是第二个任务');
      resolve(2); // 当定时器执行后才进行后一个then中方法
    }, 1000);
  }).then(val => {
    setTimeout(() => {
      console.log('3', '我是第三个任务');
    }, 1000); 
  });
});

// 为了更易书写和阅读来实现顺序执行异步函数,可以使用async await(只能用在async中)
function task1 () {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('1', '我是第一个任务,必须第一个执行');
      resolve('done');
    }, 3000);
  });
}
function task2 () {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('2', '第二个任务');
      resolve('done');
    }, 1000)
  });
}
function task3 () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('3', '第三个任务');
      reject('error');
    }, 1000);
  });
}
function task4 () {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('4', '第四个任务');
      resolve('done');
    }, 2000);
  })
}
async function allTasks () {
  await task1(); // 遇到await让出线程,执行完在进行后面的,保证了执行顺序
  await task2();
  await task3();
  await task4();
}
allTasks(); // 执行任务

/**
 * 3秒后
 * 1 我是第一个任务,必须第一个执行
 * 1秒后
 * 2 第二个任务
 * 1秒后
 * 3 第三个任务
 * Uncaught (in promise) error
 */

// 补充promise.all的使用,接收iterable类型,只返回一个promise实例(所有promisede的resolve回调的结果是一个数组,执行是所有输入的promise的resolve回调都结束。执行reject是只要有一个输入的promise的reject回调执行或输入不合法的就会立即 抛出错误信息)
Promise.all(iterable); // 一个可迭代对象,如 Array 或 String,使用集合多个 promise 的返回结果时很有用,都成功才成功,一个失败则失败
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

9、深浅拷贝:针对引用类型 (复杂数据类型),浅拷贝只复制某对象的指针,不复制对象本身

// 赋值:obj1=obj  改变会使两个中值都改变,无论第一层数据是否为基本数据类型
let obj={
   'name' : 'zhangsan', // 第一层数据类型是基本数据类型字符串
   'age' :  '18',  // 第一层数据类型是基本数据类型数值
   'language' : [1,[2,3],[4,5]], // 第一层不是基本数据类型
}
ar obj2 = obj;
obj2.name = "lisi"; // 此时obj中的也会变
obj2.language[1] = ["二","三"];
console.log('obj1',obj)
console.log('obj2',obj2)

// 浅拷贝:改变时不会改变原数据第一层是基本类型的,但会改变是引用类型的
// 浅拷贝方法1
var obj1 = {
   'name' : 'zhangsan',
   'age' :  '18',
   'language' : [1,[2,3],[4,5]],
};
var obj3 = shallowCopy(obj1); // 已完成浅拷贝
obj3.name = "lisi";
obj3.language[1] = ["二","三"];
 
function shallowCopy(initalObj) {
  if(typeof initalObj !== 'object') return
  let result = initalObj.constructor===Array?[]:{} ;
   for (let prop in initalObj) { // 遍历对象的属性
       if (initalObj.hasOwnProperty(prop)) {
           result[prop] = initalObj[prop];
       }
   }
   return result;
}
console.log('obj1',obj1)
console.log('obj3',obj3)

// 方法2:扩展运算符(也是实现第一层是值类型的深拷贝)
let obj = {
    a: {
        a1: 'a1'
    },
    b: 'b'
}
let ass = {...obj};  // a对象的改变还是相互影响的

// 方法3:使用es6的 Object.assign():此方法用于对象的合并,将源对象的所有可枚举属性复制到目标对象上 Object.assign(target, ...sources)
let obj = {
    a: {
        a1: 'a1'
    },
    b: 'b'
}
let ass = Object.assign({}, obj);
ass.a.a1 = 'aaa';
aconsole.log(obj, ass);

// 深拷贝:两者隔离,不相互影响
// (1)方法1:使用JSON的方法(缺点会丢失值为undefined Symbol() function)
JSON.parse(JSON.stringify(obj)) //  通常将对象或数组转为字符串再转为对象

// (2)方法2:嵌套遍历
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] = deepClone(source[keys]);
      }else{ // 如果不是,就直接赋值
        targetObj[keys] = source[keys];
      }
    } 
  }
  return targetObj;
}

10、es6 新语法
(1)let const
(2)Symbol
(3)Set Map
(4)变量的解构赋值:一般根据结构一致对应匹配(常用到扩展运算符)

// 数组的解构赋值
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // undef
z // []

// 对象的解构赋值:没有顺序之分,需变量与属性同名才能取到
let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

// 字符串的解构赋值(使用字符串给变量解构赋值)
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
// 函数参数的解构赋值(也是结构匹配或 使用rest参数 ...变量名)
// rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中,rest参数后不能再有别的,函数length属性不包含rest参数
function add(...values) { // values=[1,2,3]
  let sum = 0;
  for (var val of values) {
    sum += val;
  }
  return sum;
}
add(1, 2, 3) // 6
// 数值布尔的解构赋值(如果等号右边是数值和布尔值,则会先转为对象)

(5 各个类型的扩展
数值的扩展
字符串的扩展
正则的扩展
对象的扩展
函数的扩展:可以设置默认参数,箭头函数
class 类
模块化 :模块的功能主要由 export 和 import 组成

11、迭代器:Iterator,为不同的数据结构提供统一的访问机制(可以使用for of)
一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以用for…of循环遍历它的成员。也就是说,for…of循环内部调用的是数据结构的Symbol.iterator方法
for…of循环可以使用的范围包括 数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串

12、事件流(冒泡捕获)事件委托
什么是事件:事件是文档或浏览器窗口发生的特定的交互瞬间(js与html间交互是通过事件)
什么是事件流:页面接收事件的顺序(IE中是事件冒泡,Netscape的事件流就是事件捕获)
事件冒泡阶段:从目标到逐级向上,直到document div/body/html/document
事件捕获阶段:从顶层向下至目标元素
事件委托:如果有多个DOM节点需要监听事件的情况下,给每个DOM绑定监听函数,会极大的影响页面的性能,因为我们通过事件委托来进行优化,事件委托利用的就是冒泡的原理(给公共的父级绑定,点子 都会走到父,从而触发)
DOM2:事件捕获、目标阶段、事件冒泡阶段

13、js垃圾回收机制:标记清楚、引用计数 (自动周期性的执行)
js基本数据类型存在栈内存中,由操作系统自动分配释放,复杂类型存在堆内存中,由自己分配与释放,不释放时垃圾回收机制进行处理。
(1)标记清除(常用):周期行的执行垃圾回收步骤(是没有引用或相互形成环但访问不到它们则清除),就是发现不可达对象并给予清除的问题:标记阶段即为所有活动对象做上标记,清除阶段则把没有标记销毁
垃圾收集器在运行时会给内存中的所有变量都加上一个标记,假设内存中所有对象都是垃圾,全标记为0(0,1进行标记)
然后从各个根对象开始遍历,把不是垃圾的节点改成1
清理所有标记为0的垃圾,销毁并回收它们所占用的内存空间
最后,把所有内存中对象标记修改为0,等待下一轮垃圾回收
优先 实现简单只打标记0、1 缺点:清理后内存位置不变,使内存不连续 ,内存碎片,分配慢

(2)引用计数:看对象有没有被引用,追踪每个变量被引用的次数,当声明变量赋值引用类型记1.又赋值另一变量 +1,若变量被其他赋值,减1,引用为0则清除内存。
缺点:循环引用不行

14、箭头函数
this指向定义时所在的作用域中(也就是箭头函数没有this)
不能多箭头函数进行 new操作
箭头函数没有参数伪数组 arguments,可以使用rest参数,将多余的参数放在一个数组中
(伪数组具有length属性不可变,但没有数组 所具有的方法。函数参数、dom节点列表、jQuery)
箭头函数的name属性是一个空字符串 ( number => number + 1 ).name; // => ‘’
返回对象时用()包起来

15、数组的操作方法(哪些改变原数组)
改变原数组的方法:以下9个
.push(1,2,3) 数组的尾添加,返回的是新数组的长度,改变原数组
.pop() 数组尾部删除,返回删除项,改变原数组
.unshift() 数组的开头添加一个或多个,返回新数组长度,改变原 数组
.shift() 删除数组的第一个元素,返回删除项,改变原数组
.reverse() 数组的翻转,返回翻转后的 数组,改变原数组
.sort() 数组排序,返回排序后的数组,改变 原数组
.splice(start,length,item) 返回被删除的数组,没删除不返回,改变原数组
.fill(value, start,end) 包start不包end 用元素填充原来的数组,返回改变后的新数组 ,原数组变
.copyWithin(targetIndex,start,end) 包左不包右 浅复制数组的一部分到数组的另一位置

不改变原数组方法:
.concat()数组的连接,返回新数组
.join() 数组转字符串
.slice(start, end) 数组的截取,包左不包右 返回截取的数组
.indexOf(value)、lastIndexOf(value)、every\some\map\filter\forEach\reduce等
.find() 返回满足条件的第一个数组 元素
.findIndex() 返回 满足条件的第一个元素的下标
Array.from() 将类似数组的对象或可遍历的对象转为真正的数组
Array.of() 将一组值转为 数组
includes() 返回数组是否包含某值
.keys() 返回键值对的key,数组就是索引数组
.values() 返回键值对value,数组就是 原数组值
.entries(). 返回 键值对 [[0,‘a’]]

16、for循环(为什么Object不能用for of)
因为对象中原型中都有一个Symbol.iterator方法,无遍历器

17、DOM BOM
18、原声js遍历时获取下标的3中方式
forEach、设置内置属性
19、js执行过程:编译阶段、执行阶段
编译阶段:
词法分析:引擎将我们写的代码当成字符串分解成词法单元token
语法分析: 将词法阶段的token转换成抽象结构的 抽象语法树
语义检查
代码优化及字节码生成

执行阶段:执行需要环境即执行上下文,浏览器环境,全局执行、函数执行、eval执行
后面就是js单线程的执行

20、词法分析、语法分析:先词法分析再语法分析得到抽象语法树

21、meta SEO
首先说 SEO:搜索引擎优化,通过网站的结构布局设计和网页代码优化让用户能看懂
(1)title标签:直接展示在浏览器标签页,让用户快速了解搜索结果的内容至关重要

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <title>标题</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

(2)meta 标签 :元数据,不会展示在页面上但对机器是可读的

<meta name=”Description” Content=”你网页的简述”>

(3)标题标签 h1-h6
(4)语义话的标签:head nav. article aside section footer等
(5)图片的 alt属性,当图片加载不成功时会展示alt属性的内容
(6)响应式设计:可以使用媒体查询实现
https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Responsive_Design

// 视口元标签,将 视口宽度设为设备的宽度
<meta name="viewport" content="width=device-width, initial-scale=1"/>

@media screen and (min-width: 800px) { //最小是800时才
  .container {
    margin: 1em 2em;
  }
} 

在做前端页面时可以使用多栏布局、伸缩盒display:flex、网格display:grid等做响应式布局

22、js类型转换:Number、String、Boolean、parseInt、parseFloat、toString
(1)、转为字符串
1)String(参) 此方法可将其他所有类型转为字符串类型
2)参.toString() 注意不可转null与undefined类型
3)隐式转换:在进行+运算时,若一个是字符串类型,一个为其他类型则会将其他类型转为字符串类型在进行拼接,不管字符串在+前还是后
(2)、转为数值类型
1) Number()
纯数字的字符串转换后为数字,非纯数字的字符串为NaN,""空字符串转后为0
布尔类型true转后为1 ,布尔类型false转后为0
undefined转换后为NaN
null转换后为0
[]空数组转换后为0,其他NaN
Object转后为NaN
Function转后为NaN
2) parseInt() 不识别小数,此方法还可以用于进制的转换
若字符串首字符为数字则遇非数字结束。若首字符非数字则为NaN
布尔类型true转后为NaN ,布尔类型false转后为NaN
undefined转换后为NaN
null转换后为NaN
[]空数组转换后为NaN,非空数组遇逗号结束,若第一个数组值就不是数字则NaN
Object转后为NaN
Function转后为NaN
3)parseFloat() 同parseInt()但识别第一个小数点

(3)转为布尔类型
Boolean() 数字0、"“”空字符串、null、undefined、NaN转换后为false,其他true

23、js进制的转换
(1)十进制转其他进制:num.toString(2) // 十进制转为2进制
(2)其他进制转十进制:parseInt(‘10010’,2) // 将2进制转为10进制

24、

二、CSS
1、盒模型:所有的元素都被一个个盒子包着(margin, border, padding, and content)
css块级盒子包含
Content box: 这个区域是用来显示内容,大小可以通过设置 width 和 height.
Padding box: 包围在内容区域外部的空白区域; padding设置。
Border box: 边框盒包裹内容和内边距。 border 设置。
Margin box: 这是最外面的区域,是盒子和其他元素之间的空白区域 margin
(1)先说盒模型
标准盒模型:设置的width、height是content box (即外加模式)
整个盒子大小=width+padding+border
整个盒子所占区域=width+padding+border+margin(margin影响是盒子页面占的空间)

     IE盒模型:设置的width、height是 content+padding+border(设置就是盒子占的空间,内减模式)
     
     浏览器默认使用标准模型,可以设置box-sizing属性进行更改box-sizing: border-box即内减模式

(2)再说有哪些盒子:块级盒子、行内块盒子、内联盒子
盒子间相互转换:display:block/inline-block/inline
块级盒子:总是在新行开始,高度、边距能可控
行内块盒子:同行展示可设置宽高等属性
内联盒子:和别的内联一行展示,宽度、高度、上下内边距、上下外边距不可控,
由内容撑开

2、选择器及其等级:css通常通过选择器获取html元素,进而设置所需样式,否则只能行内
ID选择器:id定义,#id名获取 ,id值不能重复

  类选择器:class定义,.类名获取
  属性选择器:[title]   [title=runoob]  或input[type="text"]
  伪类选择器:以:开头 配合基本选择器
       子元素获取
       :only-child
       :first-child
       :last-child
       :nth-child(n) 、: nth-last-child(n)
       :first-of-type、:last-of-type
       :nth-of-type(n)、:nth-last-of-type(n)
       元素状态相关
       :hover
       :active
       :focus
 
  标签选择器(元素选择器):p   span
  伪元素选择器:以::开头,配合基本选择器
      ::after
      ::before
      ::first-letter
      ::first-line
      ::selection
 后代用空格、子代>、相邻+、~、多 选择器,
 
  !important > 内联样式 > ID 选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 标签选择器 = 伪元素选择器 > 通配符选择器 > 继承 > 浏览器默认属性

3、伪元素 伪类
伪类:以:,常用于子元素获取或链接状态(别的标签也可以)
伪元素:以::

/* 每一个 <p> 元素的第一行。 */
p::first-line {
  color: blue;
  text-transform: uppercase;
}

4、常见的布局问题
正常的布局流(浏览器默认的,根据块 盒子 、行内块、行内元素的特性进行填写)
display属性改变盒子特性或布局(弹性盒子 、网格、表格grid)
浮动
定位
多列布局

	display:
	(1) block
	(2) inline-block
	(3) inline
	(4) flex/inline-flex
	(5) grid

5、完成扇形 三角形
(1)用纯css实现三角形原理

// 通过设置大的border实现
.box{
  width:0px;
  height:0px;
  border: 50px solid transparent;
  border-left:50px solid #ef4848;  // 要哪个方向的三角形设置哪个
}

6、层叠的理解与解决、继承
层叠:
同层级后设置的相同属性不同值会覆盖前设置的(权重相同时 后面的会 覆盖前面的)
优先级:内联 1000 > ID选择器 100 > 类选择器 10(class类、属性、伪类) > 标签选择器 1(!important 比行内元素优先级还高)

     第一优先级:!important会覆盖页面内任何位置的元素样式
     内联样式,如style="color: green",权值为1000
     ID选择器,如#app,权值为0100
     类、伪类、属性选择器,如.foo, :first-child, div[class="foo"],权值为0010
     标签、伪元素选择器,如div::first-line,权值为0001
     通配符、子类选择器、兄弟选择器,如*, >, +,权值为0000(但优先于继承,继承最低)
     继承的样式没有权值

继承(具有嵌套关系才存在):有些设置在父上的css属性是可以被子继承的,有些不能
如何知道属性是否可继承:inherited:yes/no
常见的可继承属性:文本属性、字体属性(部分不可以)、列表相关、元素可见性(visibility)、表格布局属性、
常见的不可继承属性:背景属性、盒模型(width、height、margin、border、padding)、布局定位属性(display position)等不可继承
7、flex布局:是一种布局模型,子元素有强大的空间分布和对齐能力
容器:任何元素容器都可以指定称为flex容器,通过给盒子设样式:display:flex,即成为flex容器
项目:容器的直接子元素称为 Flex项目,此时子元素的float(浮动)、clear(清除浮动)和vertical-align(垂直展示方式)无效

容器属性(都是规定项目的排列等方式):就是给设置display:flex/inline-flex的盒子设置
(1)主轴方向flex-direction:row/row-reverse/column/column-reverse(交叉与之 垂直)
(2)如何换行flex-wrap:nowrap(不换行,会挤在一行,会自动缩减项目的宽度)、wrap(换行,第一行在上)、wrap-reverse(换行,第一行在最下方)
(3)是前两个缩写 flex-flow:(flex-direction,flex-wrap主轴方向和是否换行的缩写)
(4)主轴对齐方式justify-content:flex-start (左对齐)|flex-end(右对齐)|center (居中)|space-between (两端对齐,项目之间的间隔相等,但距左右边框不一定)|space-around (每个项目两侧的间距相等)
(5)交叉轴对齐方式align-item:flex-start (交叉轴起点对齐)|flex-end (交叉轴终点对齐)|center |baseline (项目第一行文字的基线对齐|stretch (占满容器的高度,默认)(交叉轴的对齐方式,只针对单行)
(6)多轴线的对齐方式align-content:flex-start/flex-end/space-between/space-around/stretch(默认),如何分布容器的侧轴空间
如果flex-wrap为nowrap即只有一行不存在多轴线对齐方式,实质就是多行时如何排
⚠️:主要记住4个属性:主轴方向(规定子项目怎么排列),是否拆行, 主轴对齐方式,交叉轴对齐方式

item项目属性:
(1) html排列顺序order:number(默认0数值越小越靠前 ,改变样式修改html结构)不怎么用
(2) flex-basis:number/auto (默认auto,可设置固定的值50px/50%)项目自身大小,auto就是原项目自己的宽度
⚠️放大、缩小、自身控制的都是主轴上的比例
(3) 项目放大比例flex-grow:number(默认0,如果有剩余空间也不放大,值为1放大,2是1的双倍大小)当项目的总宽小于容器宽时是否放大撑满容器,还有一个使用形式就是通过设置该属性规定各项目按什么比例占满容器主轴空间
当按flex-basis排列后还有 剩余 空间 ,这时候会根据flex-grow看如何(分剩余空间的比例 )
(4) 项目缩小比例flex-shrink:number (默认为1,如果空间不足则会缩小(当宽度不够时项目会缩小),值为0不能缩小),数值越大缩放比例越大

(5) 缩写flex:flex-grow flex-shrink flex-basis (它是这三个属性的缩写默认0 1 auto) auto (即1 1 auto会放大会缩小自身宽) 和 none (即0 0 auto不放大不缩小自身宽) flex:1 flex属性只有一个值的时候,省略的两个并不是默认值(看后面讲解)
(6) 项目对齐方式align-self:auto | flex-start | flex-end | center | baseline | stretch 项目自身对齐(只影响自身项目的交叉轴的排列)
自动换行的场景
flex: 0 flex: 0 1 0% 适用场景少(最终尺寸表现为最小内容宽度)
flex: none flex: 0 0 auto 推荐(固定尺寸由内容决定,元素不具有弹性,通常为最大内容宽度,flex容器不够时直接溢出),适用当flex子项的宽度就是内容的宽度,且内容永远不会换行
flex: 1 flex: 1 1 0% 推荐 当尺寸不足时会优先最小化尺寸,即优先牺牲自己。场景:希望充分利用剩余空间,但不会侵占其他元素尺寸,合等分布局;
flex: auto flex: 1 1 auto 适用场景少,当尺寸不足时会优先最大化自己的内容,即优先霸占住自己的位置,让其他进行换行缩放。元素充分利用剩余空间,但是各自的尺寸按照各自内容进行分配的时候,例如导航按钮的宽度是根据按钮文字的多少分配宽度的。
⚠️:记住放大、缩小(默认不放大会缩小)

8、浮动、定位
定位:position:static静态定位/

position:static  静态定位,它是默认值,是浏览器自主决定元素的位置(文档流),即按正常的页面流布局,此时设属性值top、bottom、left、right无效(是浏览器自主决定的,不用专门设置)

position:relative 相对定位,它相对于自己默认的位置进行偏移(即文档流位置),可以设偏移方向和距离 top、bottom、left、right
div {
  position: relative;
  top: 20px;
}// div位置向下偏移20px

position:absolute 绝对定位 它是相对父级定位的元素进行定位的(不能是静态定位static,否则就是文档html),文档流中不占据位置,脱离文档流,不影响周边元素,具有父子关系,占空间0


position:fixed 固定定位,相对浏览器窗口进行定位,不会随网页的滚动而变化好像固定死一样.一般用于做网页的顶部导航

position:sticky 是relative和fixed定位的结合,会产生动态固定效果。例如实现网页的搜索工具栏,初始时relative定位,文档流中位置,当滚动页面时就变成fixed定位。页面滚动时根据设置的偏移值生效时切换定位。需搭配left/right/top/bottom,否则就是相对定位 
原理:当页面滚动时当距离没有达到生效门槛时(部分不可见)此是时固定定位,当父完全脱离视口时(完全不可见)此时相对定位.例如百度搜索栏的实现,刚开始是相对定位,文档指定的位置,当滚动时达到生效门槛就是固定定位,这两个定位根据设置的生效门槛left/right/top/bottom切换

浮动:float:left/right (浮动元素会脱离 文档流,位于它下方的非浮动元素 会占据浮动剩余位置,即它不占据实际位置)

1、块级元素会认为浮动元素不存在,但可能会被 浮动元素覆盖 (即正常文档流跟浮动元素的位置有重叠 此时浮动元素会覆盖)
2、浮动元素会影响 行内元素,例如文字,会围绕空出浮动元素位置展示 
3、会间接影响包含它的布局
尽量靠上
尽量靠左
尽量一个挨着一个
不能超出包含块,除非元素比包含块更宽
不能超过所在行的最高点
不能超过它前面浮动元素的最高点
行内元素绕着浮动元素摆放:左浮动元素的右边和右浮动元素的左边会出浮动元素
浮动元素碰到包含它的边框或者浮动元素的边框停留。

问题:
1、浮动元素并不能撑起包含块(父元素的高度无法被撑开,外层的背景、边框、margin不生效等):可用clear清除浮动也可以用BFC解决,块级格式化上下文(它规定自己内部元素的布局规则)
2、浮动元素前同级非浮动元素:
  行内元素:当行内元素的宽+浮动元素宽>父宽时,浮动下移,直到可放下(例如四行文字,最后一行昨浮+少许文字情况)
  块级元素:不影响,会在块级元素下进行浮动

3、浮动元素后同级非浮动元素:无论行内还是块都会在紧随浮动元素,行内会空出浮动元素围绕例如实在文字围绕,块级盒子会 忽略浮动,出现覆盖问题

4、浮动元素对浮动元素的影响: 同一个方向的浮动元素,当一个浮动元素在浮动过程中碰到同一个方向的浮动元素时,它会紧跟在它们后面,当空间不够时会被挤下。反方向的浮动元素:互不影响,位于同一条水平线上,当空间不够时会被挤下

解决办法:目的是还原文档流,让浮动元素 占据 该占据的 位置
办法1:清除浮动clear

// 方法1、添加新的元素,利用clear:both(给父的结束标签前插入块级标签)
<div class="outer">
    <div class="div1">1</div>
    <div class="div2">2</div>
    <div class="div3">3</div>
    <div class="clear"></div>
</div>
.clear{clear:both; height: 0; line-height: 0; font-size: 0}
在最后一个浮动元素后添加盒子,设置  clear:both(这样父盒子就不受影响了)

// 方法2、父级div使用使用overflow:auto/hidden,不能visible(即使用BFC特性)

// 方法3、::after,给父加设置 
.outer {zoom:1;}    /*==for IE6/7 Maxthon2==*/
.outer :after {
  clear:both;
  content:'.';
  display:block;
  width: 0;
  height: 0;
  visibility:hidden;}/*==for FF/chrome/opera/IE8==*/

办法2:BFC块级格式化上下文(后面单独模块讲)

9、外边距塌陷:在同一个BFC中,两挨着的块级元素的 上下margin会折叠取较大者(可以两个BFC解决)
10、盒子如何居中或几栏布局

1、两栏布局(左固定右自适应)
   // 方案1 float实现:左固定宽左浮动,右BFC宽度自适应或margin-left为左盒宽度
   // 方案2 定位 父包含两盒子,父相对定位,子决定定位。左盒子设置宽,右盒子设置定位左宽为左盒子宽,右上为0  
   // 方案3 flex布局:父设弹性盒子,左flex:0,0:100px(左设置宽),右flex:1(1,1,0%)

2、三栏布局(左右固定,中间自适应)
   // 方法1 浮动float实现,左右 各自浮动设置宽,中间舍左右margin
   // 方法2 BFC因为BFC不会与浮动元素重叠,紧贴  左左浮设宽,右右浮设宽 ,中间BFC overflow:hidden
   // 方法3 flex布局:父加弹性盒子(可设置整体的宽高)、左右flex 0 0 100px 中间flex 1
   // 方法4 绝对定位 父相对定位,左设宽距左距右0  右设宽距右距上0 中间设置margin空出左右宽

3、盒子居中问题
(1)宽度高度已知(浮动元素也适合)
     办法1:定位:父相对定位,子绝对定位,子top:50% left:50% margin-left/top:子宽高一半
      .father{
            width: 800px;
            height: 400px;
            position: relative;
            background: red;
        }
        .son{
            width: 100px;
            height: 50px;
            position: absolute;
            top: 50%;
            left: 50%;
            margin-left: 50px;
            margin-top:25px;
            background: green;
        }
(2)宽度高度未知(有宽高但自己不知道具体值)
    方法1:定位:父相子绝,子的定位值都为0,margin:auto(浏览器自己选择合适边距)
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            margin: auto;
    方法2:flex布局:给父设置,弹性盒子,主轴交叉轴 对齐方式center(不管宽高已知不已知均可)
    .box{
      display:flex;
      justify-content:center;
      align-items:center
    }
    
内容居中问题:
(1) 方法1:line-height,将该值设置同height
(2) 方法2:flex 
.flex{
    display: flex;
    align-items: center;
    justify-content: center;
    
    text-align: justify;(设置行内内容如何相对父级对齐,只控制内容,不控制自己)
    width:200px;
    height:200px;
    background: #000;
    margin:0 auto;
}

11、BFC 块级格式化上下文:指独立的渲染区域 或隔离的独立容器(容器里面的子元素不会影响到外面的元素)
只要符合以下的条件就是BFC:

  1. 根元素
  2. float属性不为none:float:left/right 它内部就是一个独立的渲染区域
  3. position为absolute或fixed(它们 会 脱离文档流,一个相对父定位一个相对浏览器)
  4. display为inline-block, table-cell, table-caption, flex, inline-flex
  5. overflow不为visible:overflow:auto/hidden

特点:BFC中块级元素垂直依次排列(跟标准文档 相同)
两个块级元素间同属一个BFC上下 margin会折叠,不同BFC不受影响
BFC区域不会与浮动元素区域重叠,不会有交集,而是紧贴浮动边缘(解决覆盖 )
计算BFC高度,浮动元素也参与计算
好处:解决外边距折叠问题:让分别 属于不同的 BFC、清除浮动(例如给浮动后的 块级盒子设置 ,这样后面的块级盒子就会紧挨着,而不是被浮动盒子覆盖,没设宽度时会变窄)、多栏布局、防止文字围绕

12、常见的 css兼容性问题,从初始化、浏览器私有属性、css hack(黑客)语法、自动化插件

一、默认样式
1、不同浏览器中标签默认的margin、padding不同
*{margin:0;padding:0;} // 统一 处理,解决不同浏览器不同默认样式导致错乱的问题
body {
    margin: 0;
}
a {
    background-color: transparent; /* Remove the gray background on active links in IE 10. */
}
img {
    border-style: none; /*  Remove the border on images inside links in IE 10. */
}
// 用时可以百度,找到常用的初始化Normalize.css

二、浏览器私有属性:就是在css属性前加前缀,因为新属性在W3C标准要走很复杂的程序,若属性够成熟了会在浏览器中加入支持,为避免W3C后续公布标准时有所变化所以加入私有前缀
1-webkit-,代表谷歌chrome、苹果safari私有属性:eg -webkit-border-radius
2-ms-,代表IE浏览器
3-moz-,代表火狐firefox浏览器
4-o-,代表opera浏览器
书写时将兼容性写法放在前面,标准写法放在后面 
-webkit-transform:rotate(-3deg); /*为Chrome/Safari*/
-moz-transform:rotate(-3deg); /*为Firefox*/
-ms-transform:rotate(-3deg); /*为IE*/
-o-transform:rotate(-3deg); /*为Opera*/
transform:rotate(-3deg); 

三、css hack,一般针对不同的浏览器甚至不同的版本编写特定的css样式
1、条件hack:主要根据IE浏览器进行一些特殊的设置
<!--[if IE]>
    <p>你在非IE中将看不到我</p>
<![endif]-->
<!--[if IE]>
<style>
    .test{color:red;}
</style>
IE浏览器版本如678,但IE10及以上版本已将条件注释特性移除,使用时需注意

2、属性级hack:在CSS样式属性名前加上一些只有特定浏览器才能识别的hack前缀

3、选择符级hack:

四、自动化插件:Autoprefixer是一款自动管理浏览器前缀的插件,它可以解析CSS文件并且添加浏览器前缀到CSS内容里。
//我们编写的代码
div {
  transform: rotate(30deg);
}
//自动补全的代码,具体补全哪些由要兼容的浏览器版本决定,可以自行设置
div {
  -ms-transform: rotate(30deg);       
  -webkit-transform: rotate(30deg);    
  -o-transform: rotate(30deg);    
  -moz-transform: rotate(30deg);      
  transform: rotate(30deg);
}

13、ccc3新增特性

1、边框 border-radius边框圆角 border-image边框图片 box-shadow元素阴影 
2、背景 
   background-clip:border-box/padding-box/content-box(背景从哪开始显示)
   background-origin:border-box/padding-box/content-box(背景图片是以盒子哪对齐)
   background-size:contain(缩小图片包含在盒子中)/cover(放大覆盖盒子)
3、文字
   word-wrap
   text-overflow:clip(裁剪)/ellipsis(省略号)超出容器边界时如何展示
   text-shadow:文本阴影
   text-decoration
4、颜色 rgba hala
5、transition 过渡
6、transform 转换
7、animation 动画
8、渐变
9、弹性盒子、网格布局、多列布局等 

14、页面抖动的原因???

⚠️css 优化方面的考虑:(如何提高性能,css提高性能的方法有 哪些)
(1)加载性能
(2)渲染性能
(4)可维护性、健壮性:命名结构复用等方面 考虑
实现方式:
(1)内联首屏关联css:打开一个网页页面首要内容出现在屏幕的时间影响用户的体验(直接写在标签中,加载完html就能立刻渲染)
内联就是直接写在html中,嵌入就是在style标签中,外链式就是单独css文件,link或@import引入
(2)异步加载css
使其不阻塞浏览器渲染
(3)资源压缩
使用webpack模块化工具将 css代码进行压缩,使文件变小,降低浏览器加载时间
(4)合理使用选择器
css匹配规则是从右往左匹配,#markdown .content h3,匹配花费时间久
例如:不要过多的嵌套、不要使用通配符 、属性选择器等效率低的选择器
(5)减少使用昂贵的属性
box-shadow/border-radius等降低浏览器的渲染性能
(6)不要使用@import(引入外部样式 文件)页面加载完毕后加载 css2.1才有
@import会影响浏览器的并行下载,使得页面在加载时增加额外的延迟,顺序不一定对
(7)减少重排操作,减少不必要的重绘(页面生成时至少会渲染一次,后期触发重排重绘)
重排:重新生成布局,重新排列元素:当元素位置或尺寸变化,可能全局影响,可能局部,元素内容改变等都是重排
重绘:某些元素的外观被改变,例如:元素的填充颜色

三、操作系统(重点了解,不熟悉这块)

四、前后端通讯
1、输入url到页面面的渲染过程
(1)URL解析:浏览器根据历史记录、书签等地方智能匹配
(2)DNS解析(域名解析):查找url域名对应的ip地址
本地hosts文件中找:浏览器首先查看 本地的hosts文件是否有对应的IP地址(缓存中),若存在直接建立TCP连接发送。http请求进行前后端交互渲染内容。若不存在则向本地的域名服务器发送请求进行查询
本地域名服务器解析:浏览器像本地域名服务器发出请求 ,当本地域名服务器收到请求后首先查看本地的域名缓存,若存在返回 查询主机,否则继续向根域名服务器发送域名解析请求
根域名服务器解析:当根 域名服务器接收到本地 域名服务器发送的域名解析请求后,根域名服务器返回顶级域名(例如com)的一个或多个ip地址(根只负责顶级域名的解析)
顶级域名服务器解析:当本地域名服务器收到根域名服务器返回 的顶级域名的ip地址后,进一步com的域名服务器发送一个域名解析请求,最后顶级域名服务器返回可以解析域名域名服务器地址,再次发送请求完成解析
当本地域名服务器接收到顶级域名服务器返回的ip地址后,放到本地缓存中,并将 ip地址给查询主机
主机 得到ip地址后建立TCP连接(客户端与服务器的连接 )
(3)建立TCP连接(3次握手,面向连接的运输层协议)
客户端打开(进入 等待)》
服务器发送确认 报文(等待)《
客户端给出确认 ,建立起了连接》
(4)客户端发送请求:http请求
(5)服务器处理和响应请求
(6)浏览器解析并渲染响应内容
页面生成过程:
(1) HTML 被 HTML 解析器解析成 DOM 树;
(2)CSS 被 CSS 解析器解析成 CSSDOM 树;
(3)结合 DOM 树和 CSSOM 树,生成一棵渲染树(Render Tree),这一过程称为 Attachment;
(4)根据render树生成布局(flow),浏览器在屏幕上“画”出渲染树中的所有节点;
(5)将布局绘制(paint)在屏幕上,显示出整个页面。
渲染过程优化
使用语义化标签
减少标签嵌套(生成dom树快一些)
样式减少层级嵌套 ,css选择器从右到左层级越多编译越慢

(7)TCP四次挥手断开连接 》《《 》
双方都是发送方、接收方

2、跨域:是解决浏览器同源策略限制请求的场景 (是浏览器最核心最基本的安全功能)
如果缺少同源策略浏览器很容易受到XSS、CSRF等的攻击。同源指的是协议+域名+端口都相同,即使两者不同或两个域名指向同一个ip也是非同源
同源 策略限制:
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) AJAX 请求不能发送

常见的跨域解决方案:
(1)通过jsonp跨域(只能实现get一种请求):例如我们经常会把js、css、img等静态资源分离到独立域名的 服务器上
在html页面中再通过相应的标签从不同域名下加载静态资源
动态创建script,再请求一个带参网址实现跨域通信

// 原生实现 
 var script = document.createElement('script');
    script.type = 'text/javascript';
    // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
    script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
    document.head.appendChild(script);
    // 回调执行函数
    function handleCallback(res) {
        alert(JSON.stringify(res));
    }

// Jquery实现
$.ajax({
    url: 'http://www.domain2.com:8080/login',
    type: 'get',
    dataType: 'jsonp',  // 请求方式为jsonp
    jsonpCallback: "handleCallback",    // 自定义回调函数名
    data: {}
});

// vue实现
this.$http.jsonp('http://www.domain2.com:8080/login', {
    params: {},
    jsonp: 'handleCallback'
}).then((res) => {
    console.log(res); 
})

(2)跨域资源共享(CORS)所有浏览器都支持,主流的跨域解决方案
普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。

// 原生ajax
xhr.withCredentials = true; // 设置是否带cookie

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容

// 前端设置是否带cookie
xhr.withCredentials = true;
//整体事例
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};


// vue框架
// a、axios中设置 
axios.defaults.withCredentials = true
// b、vue-resource设置
Vue.http.options.credentials = true

3、http各版本(通常缓存带出来的问题)
http 0.9 仅支持get,仅能访问html格式
http 1.0 新增POST,DELETE,PUT,HEADER等方式,增加请求头 和响应头;扩展支持的传输内容格式(图片、音视频、二进制)
http 1.1 新增Connection ,可设置keep-alive长短连接,状态码增加、一次连接可以多次请求
http 2.0 二进制分桢(数据体和头信息都是二进制)、多路复用和数据流(能同时发送和响应多个请求)、头部压缩(对header进行压缩,避免重复浪费)、服务器推送(服务器可以向客户端主动发送资源)

一个标准的http请求构成 :
请求行:method url http-version
请求头:一般有内容长度、类型、连接状态、域名等信息
请求体

http响应报文
状态行:协议版本、状态码、状态码描述
响应头部(最后有空行):一些附加信息,日期,服务、连接状态、内容类型等
响应数据:用于页面的数据

各个方法:
GET : 请求获取Request-URI所标识的资源(简单请求)
POST :在Request-URI所标识的资源后附加新的数据(简单请求)
HEAD :请求获取由Request-URI所标识的资源的响应消息报头(简单请求)
PUT : 请求服务器存储一个资源,并用Request-URI作为其标识
DELETE :请求服务器删除Request-URI所标识的资源
TRACE :请求服务器回送收到的请求信息,主要用于测试或诊断
CONNECT:保留将来使用
OPTIONS :请求查询服务器的性能,或者查询与资源相关的选项和需求
简单请求的条件
(1)请求方法是get post head
(2)有规定的请求头 字段
(3)Content-Type的值只有以下三种(Content-Type一般是指在post请求中,get请求中设置没有实际意义),指定是什么媒体类型
text/plain默认值(text表示是普通文本人类可读)
multipart/form-data (html表单)
application/x-www-form-urlencoded (json 表明是某种二进制数据 )

4、https原理及与http的区别(加密 和端口考虑)
http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议http和https使用的是完全不同的连接方式用的端口也不一样,前者是80,后者是443。 http的连接很简单,是无状态的,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议

5、http请求响应过程:基于请求与响应、无状态的、应用层协议

6、网络7层模型
物理层:比特流传输 0,1
数据链路层 :控制网络层和物理层之间的通信
网路层:ip、路由(建立主机-主机连接)
传输层:管理端到端连接 TCP||UDP
会话层 :建立、维护、管理会话连接
表示层:数据格式化、加密、解密
应用层:为应用服务提供网络服务(http)

7、TCP和UDP
TCP:面向连接协议,在收发数据前必须3次握手建立连接(更可靠,丢包会 重发)
UDP:不建立连接,尽最大努力交付不保证可靠交付,是面向报文的
(1)连接 (2)资源 (3)可靠及顺序

8、传输层有什么协议 :最常见的TCP、UDP

9、get post

10、状态码及常见的状态码(200,404,405,503,504)
(1)1xx:服务器收到请求,需要执行者继续执行操作(100,101)
(2)2xx:成功,被成功接收并处理(200-206)
(3)3xx:重定向,需要进一步的操作完成请求(300-307)例如资源移动了需要使用新url
(4)4xx:客户端错误,请求包含语法错误或无法完成请求(400-417)
400:Bad Request,客户端请求语法错误,服务器无法理解
401:用户身份确认,无权限
403:Forbidden(被禁止的)服务器理解客户端请求但拒绝执行
404:Not Found,服务器无法根据请求找到资源(可能 前端接口错或 后端没这个接口)
405:Method Not Allowed 客户端请求中的方法被禁止
(5)5xx:服务器错误,服务器在处理请求的过程中发生了错误(500-505)
502:Bad Gateway,作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503:由于超载或系统维护,服务器暂时的无法处理客户端的请求
504:充当网关或代理的服务器,未及时从远端服务器获取请求
505:服务器不支持请求的HTTP协议的版本,无法完成处理

11、websocket:它可以在用户的浏览器和服务器之间打开交互式通信会话(一种连接),可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应。提供了相关的API进行操作连接关闭等(创建连接,通过连接发送接收数据的API,例如连接成功后的回调函数等)

12、缓存:常用场景实现离线缓存(静态资源类、html页面数据等)
SW(service worker) 是 web worker 的一种,也是挂载在浏览器后台运行的线程。主要用于代理网页请求,可缓存请求结果;可实现离线缓存功能。也拥有单独的作用域范围和运行环境
支持性:浏览器及pc都有一定的支持性
可以解决的问题:用户多次访问网站时加快访问速度;离线缓存接口请求 文件、更新、清除缓存内容;可以在客户端通过indexedDB API 保存持久化信息。
使用:注册、安装、激活、运行、销毁

五、工程化

六、Vue
1、vue父子组件生命周期
(1)挂载阶段:父beforeCreate=>父created=>父beforeMount=>子beforeCreate=>子created=>子beforeMount=>子mounted=>父mounted
(2)更新阶段:父beforeUpdate=>子beforeUpdate=>子updated=>父updeted
(3)销毁阶段:父beforeDestory=>子beforeDestory=>子destoryed=>父destoryed
总结:都是父开始父结尾

七、React
(1)React中setState是同步还是异步
(2)生命周期
(3)虚拟dom的作用
(4)性能优化
(5)redux和mobx
(6)受控组件和非受控组件

八、TypeScript

九、手撕代码➕不知如何分类的题目

十、web前端面试汇总(主要vue项目)
链接:https://vue3js.cn/interview/vue/nexttick.html#%E4%B8%80%E3%80%81nexttick%E6%98%AF%E4%BB%80%E4%B9%88

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2021年的Web前端面试题汇总内容广泛,既包含基础知识点,也涉及到最新的前端技术和趋势。以下是一些可能会在2021年的Web前端面试中遇到的问题: 1. HTML、CSS和JavaScript是Web前端的三大基础技术,对于这三个技术的理解和应用灵活性有了更高的要求。 2. ES6和TypeScript是目前前端开发中常用的语言,考察对它们的掌握程度和用法。 3. 关于前端框架,React、Vue和Angular是最常用的三个框架,要求掌握框架的基本原理以及常见的使用场景。 4. CSS预处理器(如Sass、Less)和CSS模块化(如CSS Modules)也是被提及的重要话题。 5. 前端性能优化,包括代码压缩、图片优化、懒加载等,是面试中常见的问题。 6. 移动端开发和响应式设计是近年来前端发展的重点,了解相关技术和适配方案也是必备的知识。 7. 前端工程化方面的知识,如自动化构建工具的使用、模块化开发和代码规范等问题也会涉及。 8. 前端安全性和网络安全的相关问题,如跨站脚本攻击(XSS)和跨站请求伪造(CSRF)等,也是热门考点。 另外,根据个人工作经验和项目经历,还可能会有针对具体技术栈和框架的问题。针对这些问题,应当事先准备好,深入了解和熟悉相关内容,以便在面试时能够清楚、流利地回答和展示自己的能力。同时,也要注重实际项目经验,可以准备一些有关自己在项目中遇到的具体问题及解决方案的案例,以证明自己的经验和能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值