一、ajax
1.1 什么是ajax?
ajax是快速搭建动态网页的技术,通过与后台进行数据的传输,可以使网页进行异步刷新
1.2 ajax优势 && 为什么要用ajax
1.3 ajax的特点
局部刷新
1.4 介绍一下Xhr对象
1.5 手写ajax请求
const xhr = new XMLHttpRequest()
xhr.open('get', 'url', true)
xhr.send()
xhr.onreadystatechange = function() {
if(xhr.readystate === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}
1.6 json字符串转换集json对象、json对象转换json字符串
1.7 ajax传递方式有哪些?有什么区别?
常用的post、get、put、delete post和get的区别:
- get比post快
- post比get安全
- get的参数是放在url上,post则是放在请求的实体体中
1.8 什么情况下会造成跨域
https: // www .baidu.com
协议 域名 端口
浏览器有同源策略,只要以上三个不一致,就会造成跨域
1.9 跨域的解决方案
- 利用script标签,src属性和href属性不受同源策略限制
- CORS跨域
- jsonp
- window.iframe
- document.domain
- 代理(proxy目前没有系统学习,需要完善)
1.9.1 什么是CORS
1. 两种请求
1.1 简单请求:
(1) 请求方法是以下三种方法之一:
- HEAD
- GET
- POST (2)HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三个值
application/x-www-form-urlencoded、multipart/form-data、text/plain
2. 简单请求的解决方式
- 请求头中会origin: "https://..." 字段
- 在服务器添加请求头
- Access-Control-Allow-Origin: "*"
- Access-Coltrol-Allow-Credentials: true 表示是否发送cookie,只可以设置为true
- Access-Control-Expose-Header: 表示服务器可以获取哪个字段信息
- 浏览器:
- WithCrendentials: true 表示传送cookie
3. 非简单请求
非简单请求会在正式发送请求之前发送一次,称为预检请求
3.1 预检请求
预检请求目的
询问服务器,该网页所在域名是否在服务器的许可名单之中,以及使用哪些http动词和信息字段
预检请求方式
只能为options
浏览器发送字段
- Access-Control-Request-Header: 表示服务器返回的头信息中包含哪些字段
- Access-Control-Request-Method: 表示cors请求会用到哪些方法(put、post...)
服务器返回字段
- 必须要有的:
- Access-Control-Allow-Origin: "*"
- 其他的:
- Access-Control-Allow-Methods: GET, POST, PUT
- Access-Control-Allow-Headers: X-Custom-Header
- Access-Control-Allow-Credentials: true
- Access-Control-Max-Age: 1728000 //说明多长时间之内不用发送预检请求
正式回应
发送请求中含有origin: * 回应请求中含有: Access-Control-Allow-Origin: "*"
二、原型与原型链
2.1 明确对象定义
在JS中万物皆对象,分为普通对象和函数对象
2.1.1 何为函数对象?
通过function() / new function建立的, 其prototype都为Object
2.2 prototype属性
所有的函数对象都有prototype,指向的是他的一个实例即普通对象
- Array.prototype === array
- Object.prototype === object
- Function.prototype = function (比较特殊)
2.3__proto__属性
所有对象都有__proto__属性,指向的是其构造函数的prototype
2.3.1 构造函数
简单来说就是上一级, array的constructor函数为Array
特例: Object.prototype.__ proto __ === null##
(详细都在这里 转载自:www.jianshu.com/p/dee9f8b14…
2.4 构造器
所有构造器的__ proto__值为Function.prototype
- Array.__ proto__ = Function.prototype
- Function.__ proto__ = Function.prototype
- Object.__ proto__ = Function.prototype
2.4 面试案例
2.4.1 如何准确判断一个变量是数组类型
const arr = [1,2,3]
console.log(arr instanceof Array)
2.4.2 写一个原型链继承的例子 实现DOM封装(还包括其他继承)
/**
* 注意点:
* 1.使用new来创建div实例
* 2.使用document自带的函数,比如addEventListener
*/
function getElement(idName) {
this.element = document.getElementById(idName)
}
getElement.prototype.html = function(content) {
if(content) {
this.element.innerHTML = content
return this
} else {
return this.element.innerHTML
}
}
getElement.prototype.on = function(type,callback) {
this.element.addEventListener(type,callback)
}
const div = new getElement('div')
// console.log(div.html())
div.html('11111')
div.on('click',() => {
alert(div.html())
})
2.4.3 描述 new 一个对象的过程
/**
* 手写new
* 1.创建一个新的对象
* 2.继承父级原型上的方法
* 3.让该对象this指向父级,同时赋予参数
* 4.如果返回值类型为object返回该值,否则返回空对象
* */
function _new(obj, ...args) {
let o = {}
o.__proto__ = obj.prototype
const res = obj.call(o, ...args)
return typeof res == 'object' ? res : o
}
function Person(name) {
this.name = name
return 'aaa'
}
Person.prototype.getName = function() {
return this.name
}
const p = _new(Person, 'lixin')
console.log(p)
2.4.4 观察下面函数,f中包含啊a、b方法吗?
var F = function () {}
Object.prototype.a = function () {}
Function.prototype.b = function () {}
var f = new F()
答:只含有a方法,观察下面的原型链
- f.__ proto__ = F.prototype
- F.prototype = object
- F.prototype.__ proto__ = Object.prototype 所以,只含有a方法
2.4.5 手写instanceof实现原理
instanceof与typeof的区别
- typeof只有undefied、object、string、number、symbol、function、boolean
- instanceof只对引用类型有用
- typeof null = object (遗留的bug);typeof function = object
- Object.prototype.toString.call() 最精准,但是麻烦
// obj的__proto__会指向其构造函数的prototype
function Instanceof(obj, cons) {
let o = obj.__proto__
let c = cons.prototype
while(true) {
if(o === null){
return false
}
if(c === o) {
return true
}
o = o.__proto__
}
}
/**
* 什么是Object.prototype.toString.call()
每个对象都有toString方法,这个方法可以获得对象类型,所有的
*/
const arr = []
const obj = {}
const func = function() {}
const date = new Date()
const str = ''
Object.prototype.toString.call(arr)
Object.prototype.toString.call(obj)
Object.prototype.toString.call(func)
Object.prototype.toString.call(date)
Object.prototype.toString.call(str)
// 输出 后面的便是对象类型
[object Array]
[object Function]
[object Object]
[object Date]
[object String]
2.4.6 this
- this分为普通函数和箭头函数
2.4.6.1 普通函数
- 单独调用,指向window
- 闭包指向window
- 隐式绑定谁执行就指向谁(obj.foo2() 函数作为参数)
- 显式绑定 使用bind call apply 绑定谁指向谁
- new定义 谁是实例就指向谁
2.4.6.2 箭头函数
- 向上找到作用域,谁调用就指向谁
- call、bind、apply不好使
- 匿名函数同样向上找作用域
- new定义同理,但是普通对象定义的是找对象的上层作用域
var obj = {
name: 'obj',
foo1: () => {
console.log(this.name)
},
foo2: function () {
console.log(this.name)
return () => {
console.log(this.name)
}
}
}
var name = 'window'
obj.foo1()
obj.foo2()()
// 答案
window // 普通对象昂向上找作用域
obj
obj
例题在这里面,很牛逼!!佩服大大!讲的很透彻
2.4.6.3 手写bind apply call
2.4.7 判断对象里是否存在某个属性
A.call(B, args) //把A的this指向是B
-
- 使用in
-
- 使用hasOwnProperty() 缺点:获取不到继承属性
-
- 使用undefined 缺点:如果值为undefined时,结果不准确
-
- 使用if判断
const a = {
x: '111',
z: undefined
}
console.log('x' in a) // true
console.log('y' in a) // false
console.log('toString' in a) // true
console.log(a.hasOwnProperty('x')) // true
console.log(a.hasOwnProperty('toString')) // false
console.log(a.x == undefined) // false
console.log(a.z == undefined) // true
三、 数组
3.1 数组去重
let arr = [1,2,3,4,2,3]
console.log(new Set(arr))
3.2 数组扁平化
// ES5:
let arr = [1,2,[3,4,[3,4,5]]]
let a = []
function flatten (arr) {
arr.forEach(element => {
if(typeof element === 'object') {
flatten(element)
} else {
a.push(element)
}
});
}
flatten(arr)
console.log(a)
// ES6:
let arr = [1,2,[3,4,[3,4,5]]]
function flatten(arr) {
while(arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr)
}
return arr
}
console.log(flatten(arr))
3.3 深浅拷贝
深浅拷贝只针对引用对象而言,其他的对象都是浅拷贝,但是不涉及值的变化
- 深拷贝:改变复制值时原始值不变
- 浅拷贝:改变复制值时原始值改变
基础知识
浅拷贝是放在栈中,栈中即是内容。深拷贝栈中则是堆的地址。 使用深拷贝(三种方法):
- const obj2 = JSON.parse(JSON.stringfy(obj1))
- Object.assign(ob1)
- 使用递归 优缺点 JSON.parse()
- 不可以复制正则、undefined、函数等
- Object.assign Object.assign()
- 可以复制正则、函数等
- 如果有数组、对象等,还是浅拷贝 递归
- 复杂一点
3.3.1 js写浅拷贝
3.4 类型引用
在js中分为基本类型和引用类型
- 基本类型包括string、number、boolean、symbol、bigInt、null、undefined
- 引用类型是object,array、date等
3.4.1 存储方式
- 基本类型是栈存储,会把值都放在栈中
- 引用类型栈储存的是值指向的地址,堆里面是值
3.4.2 面试题
let x = [12,23]
function fn(y){
y[0] = 100;
y = [100];
y[1] = 200;
console.log(y);
}
fn(x)
console.log(x);
// 解析
function fn(y){
y[0] = 100; // 此时地址没有变,x是[100,23]
y = [100]; // x的地址改变了,x是[100]
y[1] = 200; // x是[100, 200]
console.log(y); // [100,200]
}
fn(x)
console.log(x) // 记住x的地址
- 0.1 + 0.2 为什么不等于0.3
答: 在js中十进制先转为二进制,但是某些小数转为二进制是无穷的,另外number类型有精度不准确的问题,0.1转为二进制时无穷,由于精度的问题,会有一个小数残留
// 如何让a == 1 && a == 2 && a == 3
/** 知识点:
* 引用类型转换为`Number`类型,先调用`valueOf`,再调用`toString`
* 引用类型转换为`String`类型,先调用`toString`,再调用`valueOf`
*/
const a = {
value: [3,2,1],
toString: function() {
return this.value.pop()
}
}
console.log(a == 1 && a == 2 && a == 3)
3.5 连续赋值
从左到右解析,从右到左赋值
(function() {var a=b=1;})();
console.log(b);
console.log(a);
// 从右到左赋值
// 从左到右解析
//相当于如下
var a
b = 1 // b是全局变量
a = b // a是局部变量
// 输出结果: 1, undefined
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
console.log(a);
console.log(b);
console.log(a.x);
console.log(b.x);
/**
* .运算符的优先级大于= 所以,先执行 a.x={n:2} a=a.x
*/
{n: 2}
{n: 1, x: {n: 1}}
undefined
{n: 1}
3.6 数组自身方法
3.6.1 sclice(start, end) 不改变原数组
- slice对数组进行部分截取,从0开发,到end结束,不算end(无论正负)
- start和end为负值,从后往前数
var fruits = ['a', 'b', 'c', 'd', 'r'];
console.log(fruits.slice(1,3)) // bc
console.log(fruits.slice(1, -1)) // bcd
console.log(fruits.slice(-2)) // dr
3.6.2 splice 改变原数组
四、js声明提升
- 以下的声明提升针对var定义(输出undefined),是指把该变量定义提到该作用域下的最高位置
- 分为变量提升、函数提升
4.1 变量提升(直接上题)
console.log(v1);
var v1 = 100;
function foo() {
console.log(v1);
var v1 = 200;
console.log(v1);
}
foo();
console.log(v1);
// 提升完之后是:
var v1
console.log(v1)
v1 = 100
function foo() {
var v1
console.log(v1)
v1 = 200
console.log(v1)
}
foo()
console.log(v1)
// 结果输出:undefined undefined 200 100
4.2 函数提升
函数定义有两种:
- function foo() {}
- const foo = function() {} 变量提升是对第一种情况而言
五、 promise
5.1 构造函数
const p1 = new Promise((reslove, reject) => {
reslove(4)
})
p1.then(res => {
console.log(res)
})
5.2 宏队列与微队列
在new Promise中都是宏队列的,只有遇到了then才加入到微队列中。setTimeout则是单独的,多个之间(无论里面是有promise还是什么其他的)不干扰
async function async1 () {
console.log('async1 start')
await async2();
console.log('async1 end')
}
async function async2 () {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1();
new Promise (function (resolve) {
console.log('promise1')
resolve();
}).then (function () {
console.log('promise2')
})
console.log('script end')
// 知识点 await后面的方法相当于then方法,遇到await就是阻塞
// 记住,只有then才可以进入微队列中
// 输出结果
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('once')
resolve('success')
}, 1000)
})
promise.then((res) => {
console.log(res)
})
promise.then((res) => {
console.log(res)
})
// 输出 then可以执行多次,但是第二次是直接返回结果,不会有异步等待的时间,
once success success
在浏览器上,下面的程序会一次输出哪些内容?
const p1 = () => (new Promise((resolve, reject) => {
console.log(1);
let p2 = new Promise((resolve, reject) => {
console.log(2);
const timeOut1 = setTimeout(() => {
console.log(3);
resolve(4);
}, 0)
resolve(5);
});
resolve(6);
p2.then((arg) => {
console.log(arg);
});
}));
const timeOut2 = setTimeout(() => {
console.log(8);
const p3 = new Promise(reject => {
reject(9);
}).then(res => {
console.log(res)
})
}, 0)
p1().then((arg) => {
console.log(arg);
});
console.log(10);
// 答案
六、路由
6.1 history和hash
- 在mode中定义使用history还是hash
- hash多了一个锚点(#),hash是改变#后面的数据,来进行路由的变化。特点:#虽然包含在url里面,但是不在http请求里面,同时改变他也不会发生路由变化
- history则是利用h5的特性,需要在特定的浏览器里使用。
五、http与https
5.1 http、https概念
http
5.2 http与https的区别
5.3 http运行方式
5.4 http1.0 http1.1 http2.0
5.5 http的缓存策略。
5.6 说下https,证书是如何校验的?
5.7 说下http2,你觉得阻碍http2发展的问题是什么?(
六、说下输入一个url地址的全过程
- DNS解析找到IP地址
- 根据IP建立TCP请求(三次握手)
- 建立成功发送http请求
- 服务器响应http请求
- 浏览器解析html资源和1请求静态资源js、css
- 关闭TCP连接(四次挥手)
- 浏览器渲染页面
三次握手和四次挥手都是什么?
什么叫静态资源?
- js(.js .jsx .coffee .ts)
- css(.css .less .sass .scss)
- image (.jpg .png .gif .bmp .svg)
- 字体文件 (.svg .ttf .eot .woff .woff2)
- 模板文件 (.ejs .jade .vue)
六、闭包
七、CRSF攻击
八、跨域解决
IPV4、IPV6什么意思