-
document.ready和document.load的区别
document.onload
是在结构和样式,外部js以及图片加载完才执行jsdocument.ready
是dom
树创建完成就执行的方法,原生种没有这个方法,jquery
中有$().ready(function)
-
添加 删除 替换 插入到某个接点的方法
appendChild
removeChild
replaceChild
inserBefore
-
可视区大小
clientHeight
:height+paddingoffsetHeight
:height+padding+borderscrollHeigt
:无滚动条时,为clientHeight;有滚动条时,不可见部分的元素的高度scrollTop
: 当前元素顶部距离最近父元素顶部的距离,和有没有滚动条没有关系
-
null 和 undefined的区别
null
表示没有对象,即该处不该有值,Number
转为0undefined
表示此处应该有个值,但还没有定义,Number
转为NaN
- 函数没有返回值,定义了参数没有赋值,变量声明但没有赋值都是
undefined
-
数据类型判断方法
- 基本数据类型
Undefined
,Null
,Boolean
,Number
,String
; - 引用数据类型
object
,Array
,Date
,RegExp
,Function
typeof
,对于引用数据类型的判断不太好,除了Function
会返回function
,其它引用数据类型返回object
Object.prototype.toString.call(arg)
instanceof
用来判断某个构造函数的prototype
属性是否存在于要检测对象的原型链上,例如[] instanceof Array
就为true
- 基本数据类型
-
原型与原型链
prototype
:每个函数都有一个prototype
属性,它是一个对象,是调用该构造函数而创建实例的原型(可以将属性或方法暴露成共用的)__proto_
:每个对象(除了null)上都带一个属性__proto__
,他指向当前实例所属类的原型(即创建它的构造函数的原型对象)constructor
:每个原型都有一个constructor
属性,他指向当前所属类(即关联的构造函数)- 每个
class
都有一个显示原型prototype
;每个实例都有隐式原型__proto__
,实例的隐式原型__proto__
指向class
的显示原型prototype
-
闭包
闭包
:有权访问另外一个函数作用域中的变量的函数(可以读取其它函数内部变量的函数)作用
:正常函数执行完毕后,里面声明的变量被垃圾回收机制处理掉,但是闭包可以让作用域里的 变量,在函数执行完之后依旧保持没有被垃圾回收处理掉,常驻内存- 函数作为返回值,函数作为参数来执行
- 自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方
-
this
- 在对象中
this
就是对象本身 this
是在函数执行时决定的,不是在定义时决定;(变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方)- 自执行函数中的
this
指向window
- 给元素中的某一个事件绑定方法,当事件触发时,执行绑定的方法,this就指向当前对象
- 箭头函数中的
this
指向上级作用域 call
,apply
,bind
可以改变this执行
- 在对象中
-
call,apply,bind的区别
- 都是改变函数执行的上下文,即改变this的指向
call
方法第一个参数是要绑定给this
的值,后面传入的是一个参数列表。当第一个参数为null
、undefined
的时候,默认指向window
apply
接受两个参数,第一个参数是要绑定给this
的值,第二个参数是一个参数数组。当第一个参数为null
、undefined
的时候,默认指向window
- 和
call
很相似,第一个参数是this
的指向,从第二个参数开始是接收的参数列表。区别在于bind
方法返回值是函数以及bind
接收的参数列表的使用
// 将数组转换为类数组 Array.prototype.slice.call(arguments) // call函数原理,apply与其类似,其本质就是将调用call函数的函数添加到当前所指向的this的属性中 Function.prototype.call = function(thisArg, args) { // this指向调用call的对象 if (typeof this !== 'function') { // 调用call的若不是函数则报错 throw new TypeError('Error') } thisArg = thisArg || window thisArg.fn = this // 将调用call函数的对象添加到thisArg的属性中 const result = thisArg.fn(...[...arguments].slice(1)) // 执行该属性 delete thisArg.fn // 删除该属性 return result }
-
同源策略与跨域
- 只要协议、域名、端口有任何一个不同,就是跨域
- 通过
jsonp
解决跨域,只支持get
,因为其本质还是通过script
对资源的请求 Access-Control-Allow-Origin
后台设置允许跨域nginx
做代理实现跨域document.domain+iframe
实现跨域(需要页面中嵌套iframe
,且iframe
的主域,协议,端口相同),页面通过js强制设置document.domain
为基础域名
-
事件冒泡,事件捕获,事件委托
- 事件冒泡会从当前触发的事件目标一级一级往上传递,依次触发,直到
document
为止。 - 事件捕获会从
document
开始触发,一级一级往下传递,依次触发,直到真正事件目标为止。(即点了最里面的元素,会从最外层的元素开始执行) - 事件委托,通过监听一个父元素,来给不同的子元素绑定事件,减少监听次数,从而提升速度(兼容监听ul的click,来对li添加事件)
- 阻止冒泡:w3c的方法是
e.stopPropagation()
,IE则是使用e.cancelBubble = true
- 阻止默认事件:w3c的方法是
e.preventDefault()
,IE则是使用e.returnValue = false
;
- 事件冒泡会从当前触发的事件目标一级一级往上传递,依次触发,直到
-
ajax原理(异步JavaScript和XML)
- 特点:无需重新加载整个网页的情况下,能够更新部分数据
- 创建
Ajax
核心对象XMLHttpRequest
- 向服务器发送请求
- 服务器响应处理(区分同步跟异步两种情况)
//创建 XMLHttpRequest 对象 var xhr = new XMLHttpRequest(); //发送信息至服务器时内容编码类型 xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //接受服务器响应数据 xhr.onreadystatechange = function () { // readyState用于标示当前XMLHttpRequest对象处于什么状态 if (xhr.readyState == 4 && (xhr.status == 200) { // let data = xhr.responseText; } }; //规定请求的类型、URL 以及是否异步处理请求。 xhr.open('GET',url,true); //发送请求 xhr.send(null);
-
http 常见状态码
2xx
表示成功3xx
完成请求,需要进一步操作,一般这些状态码用来重定向4xx
请求错误,表示请求可能出错,妨碍了服务器的处理5xx
服务器错误,这些状态码表示服务器在尝试处理请求时发生内部错误200
成功401
未授权(Unauthorized),当前请求需要用户验证403
对请求资源的访问被服务器拒绝了404
服务器上无法找到请求的资源500
服务器执行请求发生错误
-
get 与 post 请求的区别
get
传参方式是通过url后加参数进行传递,post
传参是放于请求体内get
请求对传递的参数有长度限制,post
没有get
请求可以被缓存,post
不可以被缓存get
请求的记录会留在历史记录中,post
请求不会留在历史记录- 一般资源查找使用
get
请求,表单提交使用post
请求
-
深拷贝和浅拷贝
浅拷贝
:拷贝的时候只是拷贝了一份引用,修改拷贝以后的数据会影响原来的数据深拷贝
:拷贝的时候会生成一份新的数据,修改拷贝以后的数据不会原数据
// 深拷贝的实现 function deepClone(obj = {}){ if (typeof obj !== 'object' || obj == null){ return obj } let result; if (obj instanceof Array){ result = [] for (let i=0; i<obj.length; i++){ result.push(deepClone[obj[i]]); } }else { result = {} for(let key in obj){ if (obj.hasOwnProperty(key)){ // 不能是原型链上的属性 result[key] = deepClone(obj[key]); } } } return result; }
-
== 防抖节流==
防抖
:用户输入结束或暂停时,才会出发change事件(最后的时候触发)防抖原理
:设置一个timer,每一次触发事件时,清空原来的timer,并新建timer,那么在最后一次触发事件时到了定时器的时间,就会执行timer
function debounce (fn, delay=500){ let timer = null; return function(){ if(timer){ clearTimeout(timer); } timer = setTimeout(() => { fn.apply(this, arguments); // fn() }, delay); } } input1.addEventListener('click', debounce(function(){ console.log(input1.value) }, 500))
节流
:会保持一个频率频繁触发,比如监听onscroll事件,每100ms触发一次事件节流原理
;设置一个timer,当触发事件时,设置timer,下一次触发如果没有到timer设置的时间,那么返回,当定时器到了时间,执行事件函数并清空timer,当下一次再触发时timer没有值,再次设置timer
function throttle(fn, delay){ let timer = null; retrun function(){ if (timer){ return ; } timer = setTimeout(() => { fn.apply(this, arguments); // fn() timer = null; }, delay); } }
-
函数声明和函数表达式的区别
- 函数声明会代码执行前预加载,而函数表达式不会
// 函数声明 function fn(){} // 函数表达式 let fn = function(){}
-
new Object()和Object.create()的区别
- 使用
Object.create()
是将对象继承到__proto__
属性上 new Object()
就是创建一个对象,和js var obj = {age:7}
是一样的
// 以下obj1和obj2指向的是同一个地址 var obj1 = {name: 'zhangjie'} var obj2 = new Object(obj1); Object.create(null); // 没有属性且没有原型 var obj4 = {name: 'zhangjie'}; var obj3 = Object.create(obj4); // 将对象挂在到一个空对象的原型中,即obj3的__proto__和obj4指向同一个内存地址
- 以下是
Object.create
的一个简单实现
// 思路:将传入的对象作为原型 function create(obj) { function F() {} F.prototype = obj return new F() }
- 使用
-
xss安全
- XSS跨站请求攻击
- 比如在博客中注入了一段script代码
- script内容获取cookie
- 将获取到的cookie发送到自己的服务器
- 将<>替换为<和>
- XSRF跨站请求伪造
- XSS跨站请求攻击
-
数据属性和访问器
- 数据属性:包含一个数据值的位置,在这个位置可以读取和写入值。数据属性有4个描述其行为的特性
- 1、
value
:包含该属性的数据值,默认为undefined。 - 2、
writable
:表示能否修改属性的值。 - 3、
enumerable
:表示能否通过for-in循环返回属性。 - 4、
configurable
:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或能否把属性修改为访问器属性,默认为true。
- 1、
- 访问器属性:这个属性不包含数据值,包含一对get和set方法,在读写访问器属性时,就是通过这两个方法来进行操作处理的
configurable
:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或能否把属性修改为访问器属性,默认为false。enumerable
:表示能否通过for-in循环返回属性,默认为false。Get
:在读取属性时调用的函数,默认为undefined。Set
:在写入属性时调用的函数,默认为undefined。
- 数据属性:包含一个数据值的位置,在这个位置可以读取和写入值。数据属性有4个描述其行为的特性
-
DOM的回流和重绘
- 当页面中元素的位置,大小或结构、定位发生改变,会引发浏览器对当前页面的结构进行重新的计算;非常耗性能的
- 当元素的背景、透明度、颜色发生变化,那么浏览器会对元素进行重新描绘;这个过程就是浏览器的重绘
-
前端性能优化
- 减少请求次数
- 减少资源大小
- 优化资源加载
- 减少重绘回流
- webpack优化
-
谈谈对缓存的理解
- 缓存读取就是浏览器在向服务器请求资源之前,先查询一下本地缓存中是否存在需要的资源,如果存在,那便优先从缓存中读取。当缓存不存在或者过期,再向服务器发送请求
- 强缓存:先获取该资源缓存的header信息,判断是否命中缓存(根据
cache-control
和expires
信息判断),若命中直接从缓存中获取资源信息,包括缓存header信息。本次请求不会与服务器进行通信expires
由于是一个绝对时间,所以可能存在用户修改电脑时间而导致页面刷新cache-control
:主要max-age
发挥作用,它是一个相对时间,表示资源的过期时间cache-control
比expires
的优先级别高
- 协商缓存:如果没有命中强缓存,浏览器会发送请求到服务器,请求会携带第一次请求返回的有关缓存的header字段信息(
Last-Modified/If-Modified-Since
和Etag/If-None-Match
),由服务器根据请求中的相关header
信息来比对结果是否缓存命中;若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取;否则返回最新的资源内容。- 发请求–>看资源是否过期–>过期–>请求服务器–>服务器对比资源是否真的过期–>没过期–>返回304状态码–>客户端用缓存的老资源
last-modified
:文件的修改时间,精确到秒ETAG
:每个文件有一个,改动文件了就变了,就是个文件hash
,每个文件唯一- 为什么要有
etag
:1)一些文件也许会周期性改变,不修改内容,只修改改变时间;2)有些文件修改频繁可能在s级以下的时间内修改
-
js延迟加载的方式
defer
和async
,不让页面等待脚本下载和执行,异步加载页面其它内容,在load之前执行- 动态创建
DOM
方式(创建script
,插入到DOM
中,加载完毕后callBack
)
-
浏览器渲染机制
- 处理
HTML
标签建立DOM
树 - 处理
CSS
标签建立CSSOM
树 - 连接
CSSOM
树和DOM
树形成一个render
树 - 在
render
树上运行布局来计算每个节点的形状 - 在屏幕上画每一个节点
- 处理
-
从输入一个url到浏览器页面展示都经历了哪些过程
- 首先,在浏览器地址栏中输入
url
- 浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操作。
- 在发送
http
请求前,需要域名解析(DNS
解析),解析获取相应的IP
地址。 - 浏览器向服务器发起
tcp
连接,与浏览器建立tcp
三次握手。 - 握手成功后,浏览器向服务器发送
http
请求,请求数据包。 - 服务器处理收到的请求,将数据返回至浏览器
- 浏览器收到
HTTP
响应 - 读取页面内容,浏览器渲染,解析
html
源码 - 生成
Dom
树、解析css
样式、js
交互 - 客户端和服务器交互
ajax
查询
- 首先,在浏览器地址栏中输入
-
== xhr,ajax,axios,fetch的区别==
xhr
:与服务器进行交换,最开始是使用的XMLHttpRequest
对象- 优点:
- 1)不重新加载页面的情况下更新网页;
- 2)在页面加载后从服务器请求数据;
- 3)向后台发送数据
- 缺点:1)繁琐,设置项多;2)兼容IE浏览器
- 优点:
ajax
:对XMLHttpRequest对象的封装,可以兼容多种浏览器- 优点:
- 1)对原生XHR封装,简化了使用;
- 2)增加对jsonp的支持
- 缺点:
- 1)多个依赖关系的请求时容易形成回调地狱;
- 2)使用ajax需要引入整个jquery
- 优点:
axios
:可以用于浏览器和NODE端,本质还是对XMLHttpRequest对象的封装,是Promise的实现版本- 优点:
- 1)可以在NODE端进行请求;
- 2)支持promiseAPI;
- 3)拦截请求和相应;
- 4)自动转换json数据
- 缺点:1)只支持高版本浏览器
- 优点:
-
cookie,session,localstorage
-
cookie
:完全存在于客户端;cookie保存了登录的凭证,有了它,只需要在下次请求时带着cookie发送cookie
属性:expires
(过期时间);max-age
(多久之后过期);domain
(域名);path
(路径);cookie
缺点:1)每个域名下的cookie
数量有限;2)cookie
大小有限制;3)每次请求都会携带cookie信息- 解决
cookie
跨域问题(nginx
反向代理/jsonp
)参考链接 - 如何在子域共享
cookie
,设置domain
为.baidu.com
-
session
:根本作用就是在服务端存储用户和服务器会话的一些信息- 存放于服务端
session
不支持跨域,仅只在他所在的域内有效- 一般用于判断用户是否登录,即购物车功能,根据
session_id
查找session
,如果没有session_id
,那么创建session
-
localstorage
(HTML5):本地存储,解决了cookie
内存不足的问题- 仅在本地存储,不与服务器通信,且长期有效
-
cookie,localStorage, sessionStorage三者区别
cookie
始终在同源的http请求中携带,即使不需要,cookie
在浏览器和服务器中来回传递。而localStorage
和sessionStora
仅仅在本地存储,不会好服务器通信,也不会自动把数据发送给服务器。- 存储大小不同,
cookie
为4kb左右;localStorage
,sessionStorage
可以达到5M - 数据有效期不同,
sessionStorage
仅在同源窗口中有效,关闭窗口就消失了,cookie
可以设置过期时间,localStorage
长期有效 localStorage
,sessionStorage
有现成的API,cookie
需要程序员手动封装
-
http的头部有什么字段
-
请求头
Accept
:告知服务端浏览器这边可以接受的数据Cache-control
:告诉服务器是否缓存referer
:当前页面的上一个页面,一般用于服务器判断是否在一个域内
-
响应头
- 返回内容的格式
set-Cookie
:服务端像客户端设置cookielast-modified
:文档的最后修改时间content-length
:内容长度
-
写一个function,清除字符串前后的空格
String.prototype.trim= function(){ return this.replace(/^\s+/,"").replace(/\s+$/,""); }
-
js 实现一个函数 获得url参数的值
function getQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); if (r != null) return unescape(r[2]); return null; }
- 堆:存储引用类型值的空间
- 栈:存储基本类型值和执行代码的环境
//==================================
var a = {};
var b = 0;
var c = 0;
a[b] = '张杰';
a[c] = '同学';
console.log(a[b]); // 输出为同学
// 扩展:对象和数组的区别
//============================================
let a = {};
b = Symbol('1'); // 创建的是唯一值
c = Symbol('1');
a[b] = '张杰';
a[c] = '同学';
console.log(a[b]); // 输出为张杰
// 自己实现一个Symbol
//=========================================
let a = {};
b = {m:1};
c = {n:2};
a[b] = '张杰'; // 这时会存储为a['object object'] = '张杰'
a[c] = '同学'; // 所以再次赋值会将原来的值覆盖
console.log(a[b]); // 输出为同学
// 关于Object.prototype.toString / valueOf
//=====================================
// 闭包;函数执行会形成一个执行上下文
var test = (function(i){
return function(){
alert(i*=2);
}
})(2)
test(5); // "4"(alert弹出为字符串)
//================================
var a = 0;
var b = 0;
function A(a){
A = function(){
alert( a + b++)
};
alert(a++);
}
A(1); //"1",在A(1)执行后形成的上下文不销毁,因为形成的函数A被外面的函数A所占用
A(2); //"4"
//===================================
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(); //2
getName(); //4
Foo().getName(); //1
getName(); //1
new Foo.getName(); //2 先执行Foo.getName,再执行new
new Foo().getName(); //3
new new Foo().getName(); //3 先执行new Foo(),再new xxx.getName(),这个先执行new xxx.getName, 再执行()
//===================================
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');
// script start; async1 start; async2; promise1; script end; async1 end; promise2; setTimeout
// == 转换规则:
// 对象 == 字符串,对象tostring变为字符串
// null==undefined 相等,但是和其它比较值不相等
// Nan == NaN 不相等
// 剩下的都会转换为数字进行比较
// a为多少,下面的条件可以成立
var a = null;
a = {
i:0,
toString(){
return ++this.i
}
}
if (a==1 && a==2 && a==3){
console.log(3)
}
//下面也可以实现
var i = 0;
Object.defineProperty(window, 'a', {
get(){
// get中不能获取当前属性,不然就会形成死循环
return ++i;
}
})
// 方式三
var a = [1, 2, 3];
a.toString = a.shift();