刷新页面,js请求一般会有哪些地方有缓存处理
dns缓存,cdn缓存,浏览器缓存,服务器缓存
浏览器的存储技术有哪些
UserData、GlobalStorage、Google Gear
这三种的使用都有一定的局限性,例如userData是IE浏览器专属,它的容量可以达到640K,这种方案可靠,不需要安装额外插件,只不过它仅在IE下有效~
globalStorage适用于Firefox 2+的浏览器,类似于IE的userData~
google gear是谷歌开发出的一种本地存储技术,需要安装Gear组件。
Flash ShareObject
这种方式能能解决上面提到的cookie存储的两个弊端,而且能够跨浏览器,应该说是目前最好的本地存储方案。不过,需要在页面中插入一个Flash,当浏览器没有安装Flash控件时就不能用了。所幸的是,没有安装Flash的用户极少。
强调一下:cookie,localStorage和sessionStorage的异同:
共同点:都是保存在浏览器端,且同源的。

image.png
作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的;
如何实现页面每次打开时清除本页缓存
www.cnblogs.com/vivaxiaonan...
(1) 用HTML标签设置HTTP头信息
**
ini
<HEAD>
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
</HEAD>
说明:HTTP头信息"Expires"和"Cache-Control"为应用程序服务器提供了一个控制浏览器和代理服务器上缓存的机制。HTTP头信息Expires告诉代理服务器它的缓存页面何时将过期。HTTP1.1规范中新定义的头信息Cache-Control可以通知浏览器不缓存任何页面。当点击后退按钮时,浏览器重新访问服务器已获取页面。如下是使用Cache-Control的基本方法:
**
perl
1) no-cache:强制缓存从服务器上获取新的页面
2) no-store: 在任何环境下缓存不保存任何页面
HTTP1.0规范中的Pragma:no-cache等同于HTTP1.1规范中的Cache-Control:no-cache,同样可以包含在头信息中。
(2) 在需要打开的url后面增加一个随机的参数
增加参数前:url=test/test.jsp
增加参数后:url=test/test.jsp?ranparam=random()
说明:因为每次请求的url后面的参数不一样,相当于请求的是不同的页面,用这样的方法来曲线救国,清除缓存
(3)chrome
现在新版的Chrome在developer Tools(F12调出来)的Settings(右下角有个齿轮标志)中有了个Disable cache选项。勾了便可以
4)ajax方法
**
php
方式一:用ajax请求服务器最新文件,并加上请求头If-Modified-Since和Cache-Control,如下:
$.ajax({
url:'www.haorooms.com',
dataType:'json',
data:{},
beforeSend :function(xmlHttp){
xmlHttp.setRequestHeader("If-Modified-Since","0");
xmlHttp.setRequestHeader("Cache-Control","no-cache");
},
success:function(response){
//操作
}
async:false
});
方法二,直接用cache:false,
$.ajax({
url:'www.haorooms.com',
dataType:'json',
data:{},
cache:false,
ifModified :true ,
success:function(response){
//操作
}
async:false
});
其他方法看链接文档www.cnblogs.com/vivaxiaonan...
实现Storage
**
javascript
function Storage(){}
Storage.getInstance = (function(){
var instance = null
return function(){
if(!instance){
instance = new Storage()
}
return instance
}
})()
Storage.prototype.setItem = function(key, value) {
return localStorage.setItem(key, value)
}
Storage.prototype.getItem = function(key){
return localStorage.getItem(key)
}
// 测试代码:Chrome环境
let a = Storage.getInstance()
let b = Storage.getInstance()
console.log(a === b)
a.setItem("key", 1)
console.log(b.getItem("key"))
前端需要注意哪些SEO
一、什么是SEO?
它是由英文Search Engine Optimization缩写而来,中文意思是"搜索引擎的优化"。
**
markdown
SEO具体是指通过网站结构调整、网站内容建设、网站代码优化、以及站外优化(网站站外推广、网站品牌建设等),使网站满足搜索引擎的收录排名需求,提高网站在搜索引擎中关键字的排名,从而吸引精准用户进入网站,获得免费流量,产生直接销售或品牌推广。
二、需要注意的
1、 合理的title,description,keyswords 搜索引擎对这三项的权重逐个减小,title 值强调重点即可,重要的关键词出现不要超过两次,而且要靠前。
2 、不同页面的tilte要有所不同;description把页面的内容高度概括,长度合适,不可过分堆叠关键词,不同页面
description有所不同。keyswords列举出重要的关键词即可。
3、语义化的HTML代码,符合W3C 规范:语义化代码有利于搜索引擎理解网页。
4 、重要的内容HTML代码放在前面:搜索引擎抓取HTML 的顺序是从上到下,有的搜索引擎对抓取长度有限制,保证重要内容一定会被抓取。
5 、重要的内容不要用js输出,爬虫不会执行js获取内容。
6 、尽量少用iframe ,搜索引擎不会抓取iframe中的内容。
7 、非装饰的图片必须加alt 。
8 、提高网站速度:网站速度是搜索引擎排序的一个重要指标。
网站SEO怎么处理
1、网站URL稳定:不乱更改URL地址,丧失老客户流量
2、死链&外链处理
目前网站中的外链,已经极少能影响到网站的站点评价,但是并不代表,网站可完全对外链置之不理;页面中的外链接如都是死链,对用户体验本身是十分不友好的行为,网站出现大量死链,也会影响站点评价,建议定期清理网站死链、外链等现象.
3、网站在优化过程杜绝作弊手段
像那些网站优化的软件广告漫天到处去吸引客户,倒不如自己有本事做做几个网站优化,用事实去说话,来吸引客户的眼球,客户也就会自动找上门了,也就不用浪费广告费,大家要经得住诱惑,不要对于做到首页就满足了,也不能因为没有做到,就自暴自弃。提醒大家,如果不想被k,就要寻找关于搜索引擎的规则。
4、循序渐进的优化
只要你认真做网站并保持一段长久的时间段后都可以到一定水准的,到一定阶段也会遇到一些新站的优化问题,切莫急于成功,一天就想干好一个月,这样的开展优化不利于网站优化.
网页验证码是干嘛的,是为了解决什么安全问题
**
您好,网页的图片验证码是用于人机识别的,用于区分人的操作行为和机器行为
可以防止恶意破解密码,刷票,论坛灌水
有效防止黑客对某人特定注册用户用特定程序暴力破解方式进行不断的登陆尝试
web开发中会话跟踪的方法有哪些
Web服务器使用Http协议。Http是无状态协议。Http的web服务器不能保持与客户端的关联。会话(session)定义为在一段时间内,单一客户与web服务器之间的一系列的交互。在一个会话中,跟踪请求之间的数据成为会话跟踪。
- 使用隐藏域进行会话跟踪
- SSL会话{Secure Socket Layer)
- Cookies
- URL重写
- IP地址
typescript有什么好处
基本数据类型
六种
- undefined
- null
- string
- boolean
- number
- symbol(ES6)
引用类型:Function,Array,Object
介绍js有哪些内置对象?
内置对象:
Object是Javascript中所有对象的父对象
数据封装对象:Object Array Boolean Number String
其他对象:Function Argument Math Date RegExp Error
原始类型有哪几种?null是对象吗
原始类型也叫基本类型
undefined、null、string、number、boolean、symbol(es6新增)
null并不是对象:
null其实并不是一个对象,尽管typeof null 输出的是object,但是这其实是一个bug。在js最初的版本中使用的是32位系统,为了性能考虑地位存储变量的类型信息,000开头表示为对象类型,然而null为全0,故而null被判断为对象类型。
介绍JS数据类型,基本数据类型和引用数据类型的区别
undefined、null、string、number、boolean、symbol(es6新增) Object 7种
1、基本类型的比较是值的比较
2、基本类型的变量是存放在栈区的,栈区包括了 变量的标识符和变量的值。
3、简单赋值
在从一个变量向另一个变量赋值基本类型时,会在该变量上创建一个新值,然后再把该值复制到为新变量分配的位置上
1、引用类型的值是可变的,基本类型是不可变的
也就是说引用类型可以拥有属性和方法,属性又可以包含基本类型和引用类型。来看看引用类型的一些特性
2、引用类型的值是同时保存在栈内存和堆内存中的对象
3、引用类型的比较是引用的比较
javascript和其他语言不同,其不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,那我们操作啥呢? 实际上,是操作对象的引用,所以引用类型的值是按引用访问的。准确地说,引用类型的存储需要内存的栈区和堆区(堆区是指内存里的堆内存)共同完成,栈区内存保存变量标识符和指向堆内存中该对象的指针,也可以说是该对象在堆内存的地址。
4、对象引用
当从一个变量向另一个变量赋值引用类型的值时,同样也会将存储在变量中的对象的值复制一份放到为新变量分配的空间中。前面讲引用类型的时候提到, 保存在变量中的是对象在堆内存中的地址,所以,与简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象。那么赋值操作后, 两个变量都保存了同一个对象地址,则这两个变量指向了同一个对象。因此,改变其中任何一个变量,都会相互影响
数据类型判断
www.cnblogs.com/hahazexia/p...
typeof 可以判断基本数据类型
Array,Object,null,Date,RegExp,Error这几个类型都被typeof判断为object,所以如果想要判断这几种类型,就不能使用typeof了。Number,String,Boolean,Function,undefined,如果想判断这几种类型,那就可以使用typeof
instanceof
除了使用typeof来判断,还可以使用instanceof。instanceof运算符需要指定一个构造函数,或者说指定一个特定的类型,它用来判断这个构造函数的原型是否在给定对象的原型链上。结果如下:
**
javascript
console.log(
instanceof Number, //false
'dsfsf' instanceof String, //false
false instanceof Boolean, //false
[1,2,3] instanceof Array, //true
{a:1,b:2,c:3} instanceof Object, //true
function(){console.log('aaa');} instanceof Function, //true
undefined instanceof Object, //false
null instanceof Object, //false
new Date() instanceof Date, //true
/^[a-zA-Z]{5,20}$/ instanceof RegExp, //true
new Error() instanceof Error //true
)
可以发现如下规律:Number,String,Boolean没有检测出他们的类型,但是如果使用下面的写法则可以检测出来
**
typescript
var num = new Number(123);
var str = new String('dsfsf');
var boolean = new Boolean(false);
还需要注意null和undefined都返回了false,这是因为它们的类型就是自己本身,并不是Object创建出来它们,所以返回了false。
使用toString()检测对象类型
可以通过toString() 来获取每个对象的类型。为了每个对象都能通过 Object.prototype.toString() 来检测,需要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用,传递要检查的对象作为第一个参数,称为thisArg。
**
ruby
toString.call(123); //"[object Number]"
toString.call('abcdef'); //"[object String]"
toString.call(true); //"[object Boolean]"
toString.call([1, 2, 3, 4]); //"[object Array]"
toString.call({name:'wenzi', age:25}); //"[object Object]"
toString.call(function(){ console.log('this is function'); }); //"[object Function]"
toString.call(undefined); //"[object Undefined]"
toString.call(null); //"[object Null]"
toString.call(new Date()); //"[object Date]"
toString.call(/^[a-zA-Z]{5,20}$/); //"[object RegExp]"
toString.call(new Error()); //"[object Error]"</pre>
这样可以看到使用Object.prototype.toString.call()的方式来判断一个变量的类型是最准确的方法。封装一个获取变量准确类型的函数这样判断一个变量的数据类型就很方便了。
**
typescript
function gettype(obj) {
var type = typeof obj;
if (type !== 'object') {
return type;
}
//如果不是object类型的数据,直接用typeof就能判断出来
//如果是object类型数据,准确判断类型必须使用Object.prototype.toString.call(obj)的方式才能判断
return Object.prototype.toString.call(obj).replace(/^[object (\S+)]$/, '$1');
}
== 和 ===的区别,什么情况下用相等==
== 在表达式两边的数据类型不一致时,会隐式转换为相同数据类型,然后对值进行比较。=== 不会进行类型转换,在比较时除了对值进行比较以外,还比较两边的数据类型。另外,数值是null,"",undefined,Nan的时候,返回的也是false.有时候判断的时候没必要一个个列举出来,一行代码解决的事情,就不要写两行。
值相等 类型不相等的时候用==
怎么判断两个对象是否相等
两个对象如何比较
怎么判断两个对象相等?
javascript
var obj = { name: 'shenghua' }
var obj2 = obj
var obj3 = { name: 'shenghua' }
// 字面量比较
console.log(JSON.stringify(obj) == JSON.stringify(obj2));//true
// 全比
console.log(Object.is(obj, obj2));//true
console.log(JSON.stringify(obj) == JSON.stringify(obj3));//true
console.log(Object.is(obj, obj3));//false
Array是Object类型吗
数据类型分别存在哪里
var a = {name: "前端开发"}; var b = a; a = null那么b输出什么
{name: "前端开发"}
var a = {b: 1}存放在哪里
var a = {b: {c: 1}}存放在哪里
栈和堆的区别
垃圾回收时栈和堆的区别x3
首先JavaScript中的变量分为基本类型和引用类型。基本类型就是保存在栈内存中的简单数据段,而引用类型指的是那些保存在堆内存中的对象。
1、基本类型
基本类型有Undefined、Null、Boolean、Number 和String。这些类型在内存中分别占有固定大小的空间,他们的值保存在栈空间,我们通过按值来访问的。
2、引用类型
引用类型,值大小不固定,栈内存中存放地址指向堆内存中的对象。是按引用访问的。如下图所示:栈内存中存放的只是该对象的访问地址,在堆内存中为这个值分配空间。由于这种值的大小不固定,因此不能把它们保存到栈内存中。但内存地址大小的固定的,因此可以将内存地址保存在栈内存中。 这样,当查询引用类型的变量时, 先从栈中读取内存地址, 然后再通过地址找到堆中的值。对于这种,我们把它叫做按引用访问当我们看到一个变量类型是已知的,就分配在栈里面,比如INT,Double等。其他未知的类型,比如自定义的类型,因为系统不知道需要多大,所以程序自己申请,这样就分配在堆里面。基本类型大小固定,引用类型大小不固定,分开存放使得程序运行占用内存最小。
3、栈内存:存放基本类型。 堆内存:存放引用类型(在栈内存中存一个基本类型值保存对象在堆内存中的地址,用于引用这个对象。)
4、基本类型在当前执行环境结束时销毁,而引用类型不会随执行环境结束而销毁,只有当所有引用它的变量不存在时这个对象才被垃圾回收机制回收。
数组里面有10万个数据,取第一个元素和第10万个元素的时间相差多少
JavaScript 没有真正意义上的数组,所有的数组其实是对象,其"索引"看起来是数字,其实会被转换成字符串,作为属性名(对象的 key)来使用。所以无论是取第 1 个还是取第 10 万个元素,都是用 key 精确查找哈希表的过程,其消耗时间大致相同。
栈和堆具体怎么存储
栈内存:存放基本类型。 堆内存:存放引用类型(在栈内存中存一个基本类型值保存对象在堆内存中的地址,用于引用这个对象。)
js中栈、堆、队列
栈和队列都是动态的集合,在栈中,可以去掉的元素是最近插入的那一个。栈实现了后进先出。在队列中,可以去掉的元素总是在集合中存在的时间最长的那一个。队列实现了先进先出的策略。

image.png

image.png
述说websock实现原理
WebSocket 是html5 出的东西(协议),并且是一个持久化的协议(下面将会讲到什么是持久化协议)
HTTP 是不支持持久连接的(长连接,循环连接的不算)
首先HTTP有 1.1
和 1.0
之说,也就是所谓的 keep-alive
,把多个HTTP请求合并为一个,但是 Websocket
其实是一个新协议,简单的说它是HTTP协议上的一种补充,可以通过这样一张图理解

image
有交集,但是并不是全部。另外Html5是指的一系列新的API,或者说新规范,新技术。Http协议跟Html本身没有直接关系。通俗来说,你可以用HTTP协议传输非Html数据,就是这样=。=再简单来说,层级不一样。
变量作用域链
当一个变量在当前作用域下找不到该变量的定义,js引擎会向外层作用域查找,一直如此知道最外层window对象。
作用域链是js函数在创建的时候定义的,用于寻找到变量的一个索引。作用域链索引的内部规则是将函数自身的本地变量放在最前面,把自身的父级函数变量放在其次,再把高一级的函数的变量放在更后面,以此类推直到window全局对象为止。当需要查找一个变量时,js解释器会从作用域链去查找该变量,先从该函数的本地变量开始查找,如果没有,则在下一级作用域链进行查找,如果查找到相应变量则返回该变量,如果直到最后也没找到相应变量则返回undefined。简单说就是,当一个变量在当前作用域下找不到该变量的定义,js引擎会向外层作用域查找,一直如此知道最外层window对象。
我们知道,如果作用域链越深, [0] => [1] => [2] => [...] => [n],我们调用的是 全局变量,它永远在最后一个(这里是第 n 个),这样的查找到我们需要的变量会引发多大的性能问题?JS 引擎查找变量时会耗费多少时间?
所以,这个故事告诉我们,尽量将 全局变量局部化 ,避免,作用域链的层层嵌套,所带来的性能问题。
谈谈你对JS执行上下文栈和作用域链的理解
www.jianshu.com/p/6ef0e6ee4...
当函数执行时,会创建一个称为执行上下文的内部对象(可理解为作用域)。一个执行上下文定义了一个函数执行时的环境。
对于每个执行上下文(Execution Context)都有三个重要的属性,①变量对象(Variable object,VO),②作用域链(Scope chain)和 ③this。
介绍暂时性死区
www.php.cn/js-tutorial...
blog.csdn.net/nicexibeida...
在ES6的新特性中,最容易看到TDZ作用就是在let/const的使用上,let/const与var的主要不同有两个地方:let/const是使用区块作用域;var是使用函数作用域。在let/const声明之前就访问对应的变量与常量,会抛出ReferenceError错误;但在var声明之前就访问对应的变量,则会得到undefined,ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为"暂时性死区"(temporal dead zone,简称 TDZ)。
**
javascript
//"暂时性死区"也意味着typeof不再是一个百分之百安全的操作。
typeof aVar; // ReferenceError
console.log(aVar) // undefined
console.log(aLet) // causes ReferenceError: aLet is not defined
var aVar = 1
let aLet = 2
js代码最终在哪里执行的
手写数组去重函数
Set
手写数组扁平化函数
www.cnblogs.com/wind-lanyan...
1、拓展运算符
**
css
[].concat(...[1, 2, 3, [4, 5]]); // [1, 2, 3, 4, 5]
2、flatten Api
3、3. join & split toString & split
和上面的toString一样,join也可以将数组转换为字符串
**
javascript
function flatten(arr) {
return arr.join(',').split(',').map(function(item) {
return parseInt(item);
})
}
4、递归
**
ini
function flatten(arr) {
var res = [];
arr.map(item => {
if(Array.isArray(item)) {
res = res.concat(flatten(item));
} else {
res.push(item);
}
});
return res;
}
如何判断一个变量是不是数组
www.jianshu.com/p/208cb24e2...

image.png
typeof()和instanceof()的用法区别
typeof:作用:用于判断一个一个表达式,(对象或者原始值),返回一个字符串。不能鉴别数组 对象
instanceof:instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。使用规则:
**
kotlin
object instanceof constructor
要求前面是个对象,所以number boolean string不能直接检测,要new Number(1)封装成对象,后面是一个构造函数。而且返回的是布尔型的,不是true就是false。常用使用:由于typeof只能判断类型,所以,数组和对象返回的都是object,这时就需要使用instanceof来判断是否是
**
javascript
[] instanceof Array //true
所以,我们可以通过这两种方式封装一个函数专门进行类型判断
为什么console.log(0.2+0.1==0.3) //false
在计算机中数字无论是定点数还是浮点数都是以多位二进制的方式进行存储的。由于0.1转换成二进制时是无限循环的,所以在计算机中0.1只能存储成一个近似值。另外说一句,除了那些能表示成 x/2^n 的数可以被精确表示以外,其余小数都是以近似值得方式存在的。在0.1 + 0.2这个式子中,0.1和0.2都是近似表示的,在他们相加的时候,两个近似值进行了计算,导致最后得到的值是0.30000000000000004,此时对于JS来说,其不够近似于0.3,于是就出现了0.1 + 0.2 != 0.3 这个现象。 当然,也并非所有的近似值相加都得不到正确的结果。
解决办法
想办法规避掉这类小数计算时的精度问题就好了,那么最常用的方法就是将浮点数转化成整数计算。因为整数都是可以精确表示的。
**
ini
0.1+0.2 => (0.1*10+0.2*10)/10
说一下JS中类型转换的规则?
www.jianshu.com/p/e0fb3f37a...
www.jianshu.com/p/e0fb3f37a...
在条件判断运算 == 中的转换规则是这样的:如果比较的两者中有布尔值(Boolean),会把 Boolean 先转换为对应的 Number,即 0 和 1,然后进行比较。
如果比较的双方中有一方为 Number,一方为 String时,会把 String 通过 Number() 方法转换为数字,然后进行比较。
如果比较的双方中有一方为 Boolean,一方为 String时,会将双方转换为数字,然后再进行比较。
如果比较的双方中有一方为 Number,一方为Object时,则会调用 valueOf 方法将Object转换为数字,然后进行比较。对象在转换基本类型时,首先会调用 valueOf 然后调用 toString。并且这两个方法你是可以重写的。
这两个运算符在大部分上面都是与(1)相同的,不同的是:
字符串 op 字符串:不会进行类型转换,直接比较。
对象 op 对象:引用都指向同一个对象才为true。
在条件判断时,除了 undefined, null, false, NaN, '' , 0, -0,其他所有值都转为 true,包括所有对象
建议在所有使用条件判断的时候都使用全等运算符 ===来进行条件判断。全等运算符会先进行数据类型判断,并且不会发生隐式类型转换。
同(一),但是对于两个操作数均是字符串的时候&无法转换时的返回值会有不同。当两个操作数均是字符串的时候,它会执行大家熟悉的字符串比较,即从左到右依次比较每一个字符的ASCII码,若出现符合操作符的情况,则返回true,否则返回false。无法将操作数转换为数字的情况下总是返回false

image.png
变量a和b,如何交换
标签生成的Dom结构是一个类数组
1)拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理);2)不具有数组所具有的方法;javascript中常见的类数组有 arguments对象和 DOM方法的返回结果。比如 document.getElementsByTagName()。
判断是否是类数组
**
javascript
function isLikeArray(o) {
if (typeof o === 'object' && isFinite(o.length) && o.length >= 0 && o.length < 4294967296){
// 4294967296: 2^32
return true
} else {
return false
}
}
类数组和数组的区别
www.cnblogs.com/jiayeyuan/p...

image.png
arguments
www.jianshu.com/p/d7ed5ade6...
其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数都会有一个Arguments对象实例arguments,它引用着函数的实参,可以用数组下标的方式"[]"引用arguments的元素。arguments.length为函数实参个数,arguments.callee引用函数自身
1.arguments对象和Function是分不开的。
2.因为arguments这个对象不能显式创建。
3.arguments对象只有函数开始时才可用。
**
scss
function demo(a,b,c){
console.log(...arguments);// 1 2 3
}
demo(1,2,3)
说一下类数组,数据结构是怎么样的,怎么转换为数组
dom的类数组如何转成数组
Array.from方法转为数组,如果有不支持Array.from方法的浏览器,可以用Array.prototype.slice方法替代,也可以用...扩展运算符
**
ini
const toArray = (() =>
Array.from ? Array.from : obj => [].slice.call(obj)
)();
Array.from使用
**
python
Array.from('一二三四五六七') // ["一", "二", "三", "四", "五", "六", "七"] // 等效的es5是'一二三四五六七'.split('')
Array.from(new Set([1,2,1,2])) // 等效[...new Set([1,2,1,2])] => [1,2] // 用来数组去重
Array.from(new Map([[1, 2], [2, 4], [4, 8]])) // 接受一个map
Array.from(arguments)// 接受一个类数组对象
Array.from(document.querySelectorAll('div')) Array.from({1: 2,length:3}) // [undefined, 2, undefined]
说几条写JavaScript的基本规范?

image.png
js延迟加载的方式有哪些?
一般有六种方式;defer属性、async属性、动态创建dom方式、使用jquery的getScript方法、使用setTimeout延迟方法、让js最后加载。
www.cnblogs.com/songForU/p/...
说说严格模式的限制
严格模式主要有以下限制:
变量必须声明后再使用
函数的参数不能有同名属性,否则报错
不能使用with语句
不能对只读属性赋值,否则报错
不能使用前缀0表示八进制数,否则报错
不能删除不可删除的属性,否则报错
不能删除变量delete prop,会报错,只能删除属性delete global[prop]
eval不会在它的外层作用域引入变量
eval和arguments不能被重新赋值
arguments不会自动反映函数参数的变化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局对象
不能使用fn.caller和fn.arguments获取函数调用的堆栈
增加了保留字(比如protected、static和interface)
设立"严格模式"的目的,主要有以下几个:
消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
消除代码运行的一些不安全之处,保证代码运行的安全;
提高编译器效率,增加运行速度;
为未来新版本的Javascript做好铺垫。
注:经过测试IE6,7,8,9均不支持严格模式。
attribute和property的区别是什么?
www.cnblogs.com/lmjZone/p/8...
attribute是dom元素在文档中作为html标签拥有的属性;property就是dom元素在js中作为对象拥有的属性。对于html的标准属性来说,attribute和property是同步的,是会自动更新的,attributes是属于property的一个子集
- property能够从attribute中得到同步;
- attribute不会同步property上的值;
- attribute和property之间的数据绑定是单向的,attribute->property;
- 更改property和attribute上的任意值,都会将更新反映到HTML页面中;
但是对于自定义的属性来说,他们是不同步的,
函数防抖节流的原理,防抖和节流的区别(两题合并)
函数节流 是指一定时间内js方法只跑一次。比如人的眨眼睛,就是一定时间内眨一次。这是函数节流最形象的解释。
函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次。比如生活中的坐公交,就是一定时间内,如果有人陆续刷卡上车,司机就不会开车。只有别人没刷卡了,司机才开车。
词法作用域和this的区别
词法作用域是在写代码或者说定义时确定的,而动态作用域是在运行时确定的。
词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用。
动态作用域不关心函数和作用域是如何声明以及在何处声明的,只关心它们从何处调用。作用域链式基于调用栈的,而不是代码中的作用域嵌套。需要明确的是,JavaScript并不具有动态作用域,。它只有词法作用域,简单明了。但是this机制某种程度上很像动态作用域。
下列代码中,使用词法作用域将输出 2,动态作用域将输出 3:
**
scss
function foo() {
console.log( a ); // 2
}
function bar() {
var a = 3;
foo();
}
var a = 2;
bar();
介绍this各种情况,箭头函数的this是什么
call apply bind指的this是谁就是谁(bind不会调用,只会将当前的函数返回)
fun.call(obj,a,b)
fun.apply(obj,[ ])
fun.bind(obj,a,b)()
- this的情况:
1.以函数形式调用时,this永远都是window
2.以方法的形式调用时,this是调用方法的对象
3.以构造函数的形式调用时,this是新创建的那个对象
4.使用call和apply调用时,this是指定的那个对象
5.箭头函数:箭头函数的this看外层是否有函数
如果有,外层函数的this就是内部箭头函数的this
如果没有,就是window
6.特殊情况:通常意义上this指针指向为最后调用它的对象。这里需要注意的一点就是如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例
闭包和this一起谈谈
箭头函数中的this是通过继承得到的,可以理解成其本身并没有this,是通过谁调用(其父对象来判断的,谁调用它谁就是this)并不像普通函数中的this一样,箭头函数中的this是看其定义时,test2();这种写法等同于window.text2();所以this就指向window对象,而new text2();这种写法意思是实例化一个text2对象,是构造函数,所以this指向的是text2对象
什么是变量提升
在js中只有两种作用域,全局作用域和函数作用域,在ES6之前,js是没有块级作用域。
JavaScript 代码的执行分为两个阶段。第一个阶段在当前词法环境中注册所有的变量和函数声明,简单说就是,解析,解析完成之后,第二个阶段的 JavaScript 执行就开始了!
JS中创建函数有两种方式:函数声明式和函数字面量式。只有函数声明才存在函数提升。
JavaScript 仅提升声明,而不提升初始化。如果你先使用的变量,再声明并初始化它,变量的值将是 undefined。
1:所有的声明都会提升到作用域的最顶上去。
2:同一个变量只会声明一次,其他的会被忽略掉。
3:函数声明的优先级高于变量申明的优先级,并且函数声明和函数定义的部分一起被提升
只有声明本身会被提升,而赋值操作不会被提升。
变量会提升到其所在函数的最上面,而不是整个程序的最上面。
函数声明会被提升,但函数表达式不会被提升。
深拷贝和浅拷贝的区别?如何实现
深拷贝和浅拷贝最根本的区别在于是否是真正获取了一个对象的复制实体,而不是引用,
浅拷贝---浅拷贝是指复制对象的时候,只对第一层键值对进行独立的复制,如果对象内还有对象,则只能复制嵌套对象的地址深拷贝---深拷贝是指复制对象的时候完全的拷贝一份对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。其实只要递归下去,把那些属性的值仍然是对象的再次进入对象内部一 一进行复制即可。
深拷贝
1、最简单的方法就是JSON.parse(JSON.stringify()),这种拷贝方法不可以拷贝一些特殊的属性(例如正则表达式,undefined,function)
2、用递归去复制所有层级属性
浅拷贝
1、object.assign(target,source) 对象
Object.assign 方法只复制源对象中可枚举的属性和对象自身的属性
如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖。后来的源的属性将类似地覆盖早先的属性
Object.assign
会跳过那些值为 [null
] null 是一个 JavaScript 字面量,表示空值(null or an "empty" value),即没有对象被呈现(no object value is present)。它是 JavaScript 原始值 之一。") 或 undefined
的源对象。
2、 数组 slice、concat方法
**
lua
let arr = ['one', 'two', 'three'];
let newArr = arr.concat();
newArr.push('four')
console.log(arr) // ["one", "two", "three"]
console.log(newArr) // ["one", "two", "three", "four"]
**
bash
let arr = ['one', 'two', 'three'];
let newArr = arr.slice();
newArr.push('four')
console.log(arr) // ["one", "two", "three"]
console.log(newArr) // ["one", "two", "three", "four"]
3.es6三个点
深拷贝和浅拷贝
深拷贝就是在拷贝数据的时候,将数据的所有引用结构都拷贝一份。简单的说就是,在内存中存在两个数据结构完全相同又相互独立的数据,将引用型类型进行复制,而不是只复制其引用关系。
分析下怎么做 深拷贝 :
首先假设深拷贝这个方法已经完成,为 deepClone
要拷贝一个数据,我们肯定要去遍历它的属性,如果这个对象的属性仍是对象,继续使用这个方法,如此往复
**
ini
function deepClone(o1, o2) {
for (let k in o2) {
if (typeof o2[k] === 'object') {
o1[k] = {};
deepClone(o1[k], o2[k]);
} else {
o1[k] = o2[k];
}
}
}
// 测试用例
let obj = {
a: 1,
b: [1, 2, 3],
c: {}
};
let emptyObj = Object.create(null);
deepClone(emptyObj, obj);
console.log(emptyObj.a == obj.a);
console.log(emptyObj.b == obj.b);
复制代码递归容易造成爆栈,尾部调用可以解决递归的这个问题,Chrome 的 V8 引擎做了尾部调用优化,我们在写代码的时候也要注意尾部调用写法。递归的爆栈问题可以通过将递归改写成枚举的方式来解决,就是通过for或者while来代替递归
深拷贝x2
loadsh深拷贝实现原理
怎么实现this对象的深拷贝
使用setTimeout代替setInterval进行间歇调用
原因:区别在于,setInterval间歇调用,是在前一个方法执行前,就开始计时,比如间歇时间是500ms,那么不管那时候前一个方法是否已经执行完毕,都会把后一个方法放入执行的序列中。这时候就会发生一个问题,假如前一个方法的执行时间超过500ms,加入是1000ms,那么就意味着,前一个方法执行结束后,后一个方法马上就会执行,因为此时间歇时间已经超过500ms了。
**
javascript
setTimeout(arguments.callee,intervalTime);
为什么会出现setTimeout倒计时误差?如何减少
阻塞
**
javascript
setTimeout(function () {
console.log('biubiu');
}, 1000);
某个执行时间很长的函数();
JS帧动画,定时器,requestAnimateFrame
随着技术与设备的发展,用户的终端对动画的表现能力越来越强,更多的场景开始大量使用动画。在 Web 应用中,实现动画效果的方法比较多,JavaScript 中可以通过定时器 setTimeout 来实现,css3 可以使用 transition 和animation 来实现,html5 中的 canvas 也可以实现。除此之外,html5 还提供一个专门用于请求动画的 API,即 requestAnimationFrame

image.png
应用:简单的进度条动画
函数式编程
函数式编程是一种 编程范式,你可以理解为一种软件架构的思维模式。它有着独立一套理论基础与边界法则,追求的是 更简洁、可预测、高复用、易测试。其实在现有的众多知名库中,都蕴含着丰富的函数式编程思想,如 React / Redux 等。
立即执行函数和使用场景
www.jianshu.com/p/b10b6e93d...
声明一个函数,并马上调用这个匿名函数就叫做立即执行函数;也可以说立即执行函数是一种语法,让你的函数在定义以后立即执行
有时,我们定义函数之后,立即调用该函数,这时不能在函数的定义后面直接加圆括号,这会产生语法错误。产生语法错误的原因是,function 这个关键字,既可以当做语句,也可以当做表达式,比如下边:
**
csharp
//语句
function fn() {};
**
javascript
//表达式
var fn = function (){};
为了避免解析上的歧义,JS引擎规定,如果function出现在行首,一律解析成语句。因此JS引擎看到行首是function关键字以后,认为这一段都是函数定义,不应该以原括号结尾,所以就报错了。解决方法就是不要让function出现在行首,让JS引擎将其理解为一个表达式,最简单的处理就是将其放在一个圆括号里,比如下边:
**
javascript
(function(){
//code
}())
(function (){
//code
})()
上边的两种写法,都是以圆括号开头,引擎会意味后面跟的是表达式,而不是一个函数定义语句,所以就避免了错误,这就叫做"立即调用的函数表达式"。
立即执行函数,还有一些其他的写法(加一些小东西,不让解析成语句就可以),比如下边:
**
scss
(function () {alert("我是匿名函数")}()) //用括号把整个表达式包起来
(function () {alert("我是匿名函数")})() //用括号把函数包起来
!function () {alert("我是匿名函数")}() //求反,我们不在意值是多少,只想通过语法检查
+function () {alert("我是匿名函数")}()
-function () {alert("我是匿名函数")}()
~function () {alert("我是匿名函数")}()
void function () {alert("我是匿名函数")}()
new function () {alert("我是匿名函数")}()
立即执行函数的作用
- 不必为函数命名,避免了污染全局变量
- 立即执行函数内部形成了一个单独的作用域,
- 可以封装一些外部无法读取的私有变量封装变量总而言之:立即执行函数会形成一个单独的作用域,我们可以封装一些临时变量或者局部变量,避免污染全局变量
立即执行函数使用的场景
1、你的代码在页面加载完成之后,不得不执行一些设置工作,比如时间处理器,创建对象等等。
2、所有的这些工作只需要执行一次,比如只需要显示一个时间。
3、但是这些代码也需要一些临时的变量,但是初始化过程结束之后,就再也不会被用到,如果将这些变量作为全局变量,不是一个好的注意,我们可以用立即执行函数------去将我们所有的代码包裹在它的局部作用域中,不会让任何变量泄露成全局变量,看如下代码:
立即执行函数的参数
(function(j){
//代码中可以使用j
})(i)
如果立即执行函数中需要全局变量,全局变量会被作为一个参数传递给立即执行函数(上例中的i就是一个全局变量,i代表的是实参,j是i在立即执行函数中的形参)。
说一下如何实现闭包
创建闭包最常见方式,就是在一个函数内部创建另一个函数。下面例子中的 closure 就是一个闭包:
**
csharp
function func(){
var a = 1,b = 2;
function closure(){
return a+b;
}
return closure;
}
闭包的作用域链包含着它自己的作用域,以及包含它的函数的作用域和全局作用域。通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。最后可以通过 null 释放
**
ini
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
// 释放对闭包的引用
add5 = null;
add10 = null;
在javascript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收;如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。闭包只能取得包含函数中任何变量的最后一个值,这是因为闭包所保存的是整个变量对象,而不是某个特殊的变量。
对闭包的理解,闭包的核心是什么
核心 变量私有化

image.png
工程中闭包使用场景x2
应用闭包的主要场合是:设计私有的方法和变量。
任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数外部访问这些变量。私有变量包括函数的参数、局部变量和函数内定义的其他函数。把有权访问私有变量的公有方法称为特权方法(privileged method)。
www.jianshu.com/p/fc645eb62...
1、匿名自执行函数(也叫即时函数)模拟块级作用域
2、循环注册dom事件中的index
3、setTimeOut中的闭包应用
介绍闭包以及闭包为什么没清除
闭包的缺点就是常驻内存会增大内存使用量,并且使用不当很容易造成内存泄露。如果不是因为某些特殊任务而需要闭包,在没有必要的情况下,在其它函数中创建函数是不明智的,因为闭包对脚本性能具有负面影响,包括处理速度和内存消耗。
在javascript中,如果一个对象不再被引用,那么这个对象就会被垃圾回收机制回收;如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。将用完的函数或者变量置为null,不过现在V8引擎做了很多优化,根本不需要考虑了。
添加原生事件不移除为什么会内存泄露
因为都DOM 被删除了 事件没有被取消
介绍闭包,使用场景
闭包: 会导致父级中的变量无法被释放
使用闭包特权函数的使用场景
说说你理解的闭包
还有哪些地方会内存泄露x2
1)意外的全局变量引起的内存泄露
**
csharp
function leak(){
leak="xxx";//leak成为一个全局变量,不会被回收
}
2)闭包引起的内存泄露
3)没有清理的DOM元素引用
4)被遗忘的定时器或者回调
5)子元素存在引起的内存泄露 连个对象相互引用

image.png
介绍垃圾回收
JavaScript垃圾回收的机制很简单:找出不再使用的变量,然后释放掉其占用的内存,
但是这个过程不是实时的,因为其开销比较大
,所以垃圾回收系统(GC)会按照固定的时间间隔
,周期性的执行。
到底哪个变量是没有用的?所以垃圾收集器必须跟踪到底哪个变量没用,对于不再有用的变量打上标记,以备将来收回其内存。用于标记的无用变量的策略可能因实现而有所区别,通常情况下有两种实现方式:标记清除和引用计数。引用计数不太常用,标记清除较为常用。
JS里垃圾回收机制是什么,常用的是哪种,怎么处理的
js中最常用的垃圾回收方式就是标记清除
垃圾回收,引用计数和标记清除
标记清除
js中最常用的垃圾回收方式就是标记清除。当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为"进入环境"。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为"离开环境"。
**
csharp
function test(){
var a=10;//被标记,进入环境
var b=20;//被标记,进入环境
}
test();//执行完毕之后a、b又被标记离开环境,被回收
引用计数
引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值(function object array)赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。
**
css
function test(){
var a={};//a的引用次数为0
var b=a;//a的引用次数加1,为1
var c=a;//a的引用次数加1,为2
var b={};//a的引用次数减1,为1
}
V8垃圾回收机制
**
vbnet
垃圾回收: 将内存中不再使用的数据进行清理,释放出内存空间。
V8 将内存分成 新生代空间 和 老生代空间。新生代空间: 用于存活较短的对象。又分成两个空间: from 空间 与 to 空间
Scavenge GC算法: 当 from 空间被占满时,启动 GC 算法存活的对象从 from space 转移到 to space。清空 from space,from space 与 to space 互换,完成一次新生代GC
老生代空间: 用于存活时间较长的对象,从 新生代空间 转移到 老生代空间 的条件,经历过一次以上 Scavenge GC 的对象当 to space 体积超过25%。
压缩算法: 将内存中清除后导致的碎片化对象往内存堆的一端移动,解决 内存的碎片化
babel编译原理
www.jianshu.com/p/e9b94b2d5...
**
babylon 将 ES6/ES7 代码解析成 AST
babel-traverse 对 AST 进行遍历转译,得到新的 AST
新 AST 通过 babel-generator 转换成 ES5
实现函数的柯里化
柯里化,可以理解为提前接收部分参数,延迟执行,不立即输出结果,而是返回一个接受剩余参数的函数。因为这样的特性,也被称为部分计算函数。柯里化,是一个逐步接收参数的过程。在接下来的剖析中,你会深刻体会到这一点。
总结
柯里化,在这个例子中可以看出很明显的行为规范:
- 逐步接收参数,并缓存供后期计算使用
- 不立即计算,延后执行
- 符合计算的条件,将缓存的参数,统一传递给执行方法
柯里化的应用
- 利用柯里化制定约束条件,管控触发机制
- 处理浏览器兼容(参数复用实现一次性判断)
- 函数节流防抖(延迟执行)
- ES5前bind方法的实现
秒懂反柯里化
先上公式,从来没有这么喜欢写公式,简明易懂。
**
scss
// 反柯里化公式:
curryFn(a)(b)(c)(d) = fn(a, b, c, d);
curryFn(a) = fn(a);
看完公式,是不是似曾相识,这不就是我们日常敲码的普通函数么?没错的,函数柯里化就是把普通函数变成成一个复杂的函数,而反柯里化其就是柯里化的逆反,把复杂变得简单。
函数柯里化是把支持多个参数的函数变成接收单一参数的函数,并返回一个函数能接收处理剩余参数:fn(a,b,c,d) => fn(a)(b)(c)(d),而反柯里化就是把参数全部释放出来:fn(a)(b)(c)(d) => fn(a,b,c,d)。
**
css
// 反柯里化:最简单的反柯里化(普通函数)
function add(a, b, c, d) {
return a + b + c + d;
}
柯里化函数两端的参数具体是什么东西
www.jianshu.com/p/ad102d658...
函数柯里化x2
在一个函数中,首先填充几个参数,然后再返回一个新的函数的技术,称为函数的柯里化。通常可用于在不侵入函数的前提下,为函数 预置通用参数,供多次重复调用。
**
scss
const add = function add(x) {
return function (y) {
return x + y
}
}
const add1 = add(1)
add1(2) === 3
add1(20) === 21
函数柯里化是函数编程中的一个重要的基础
,它为我们提供了一种编程的思维方式
。显然,它让我们的函数处理变得复杂,代码调用方式并不直观,还加入了闭包
,多层作用域嵌套
,会有一些性能上的影响。
但在一些复杂的业务逻辑封装中,函数柯里化能够为我们提供更好的应对方案,让我们的函数更具自由度和灵活性。实际开发中,如果你的逻辑处理相对复杂,不妨换个思维,用函数柯里化来实现,技能包不嫌多。说到底,程序员就是解决问题的那群人
如何去除url中的#号
正则匹配
sleep函数
sleep函数作用是让线程休眠,等到指定时间在重新唤起。
方法一:这种实现方式是利用一个伪死循环阻塞主线程。因为JS是单线程的。所以通过这种方式可以实现真正意义上的sleep()。
**
javascript
function sleep(delay) {
var start = (new Date()).getTime();
while ((new Date()).getTime() - start < delay) {
continue;
}
}
function test() {
console.log('111');
sleep(2000);
console.log('222');
}
test()
方法二:定时器
**
scss
function sleep1(ms, callback) {
setTimeout(callback, ms)
}
//sleep 1s
sleep1(1000, () => {
console.log(1000)
})
方法三:es6异步处理
**
javascript
const sleep = time => {
return new Promise(resolve => setTimeout(resolve,time)
) }
sleep(1000).then(()=>{ console.log(1) })
[实现一个sleep函数 实现一个sleep函数 promise.retry 将一个同步callback包装成promise形式 写一个函数,可以控制最大并发数](https://juejin.im/post/5dad327951882508652e525e)
写一个数,可以控制最大并发数
服务端渲染
www.jianshu.com/p/10b6074d7...
简单理解是将组件或页面通过服务器生成html字符串,再发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序
** 更利于SEO**
更利于首屏渲染
首屏的渲染是node发送过来的html字符串,并不依赖于js文件了,这就会使用户更快的看到页面的内容。尤其是针对大型单页应用,打包后文件体积比较大,普通客户端渲染加载所有所需文件时间较长,首页就会有一个很长的白屏等待时间。
SSR的局限
1、服务端压力较大
本来是通过客户端完成渲染,现在统一到服务端node服务去做。尤其是高并发访问的情况,会大量占用服务端CPU资源;
2、开发条件受限
在服务端渲染中,只会执行到componentDidMount之前的生命周期钩子,因此项目引用的第三方的库也不可用其它生命周期钩子,这对引用库的选择产生了很大的限制;
3、学习成本相对较高
除了对webpack、React要熟悉,还需要掌握node、Koa2等相关技术。相对于客户端渲染,项目构建、部署过程更加复杂。
浏览器如何预览图片,假设我要上传图片,未上传前我想在浏览器看到我待上传的图片
file协议 选中图片后,获取到图片的本地路径,然后显示在浏览中。
或者用终端命令查看图片本地路径加上一个file协议
**
bash
file:///Users/aniugel/Desktop/timg.jpeg
如何优化图像,图像格式的区别
1、不用图片,尽量用css3代替。 比如说要实现修饰效果,如半透明、边框、圆角、阴影、渐变等,在当前主流浏览器中都可以用CSS达成。
2、 使用矢量图SVG替代位图。对于绝大多数图案、图标等,矢量图更小,且可缩放而无需生成多套图。现在主流浏览器都支持SVG了,所以可放心使用!
3.、使用恰当的图片格式。我们常见的图片格式有JPEG、GIF、PNG。基本上,内容图片多为照片之类的,适用于JPEG。而修饰图片通常更适合用无损压缩的PNG。GIF基本上除了GIF动画外不要使用。且动画的话,也更建议用video元素和视频格式,或用SVG动画取代。
4、按照HTTP协议设置合理的缓存。
5、使用字体图标webfont、CSS Sprites等。
6、用CSS或JavaScript实现预加载。
7、WebP图片格式能给前端带来的优化。WebP支持无损、有损压缩,动态、静态图片,压缩比率优于GIF、JPEG、JPEG2000、PG等格式,非常适合用于网络等图片传输。
图像格式的区别:
矢量图:图标字体,如 font-awesome;svg
位图:gif,jpg(jpeg),png
区别:
1、gif:是是一种无损,8位图片格式。具有支持动画,索引透明,压缩等特性。适用于做色彩简单(色调少)的图片,如logo,各种小图标icons等。
2、JPEG格式是一种大小与质量相平衡的压缩图片格式。适用于允许轻微失真的色彩丰富的照片,不适合做色彩简单(色调少)的图片,如logo,各种小图标icons等。
3、png:PNG可以细分为三种格式:PNG8,PNG24,PNG32。后面的数字代表这种PNG格式最多可以索引和存储的颜色值。
关于透明:PNG8支持索引透明和alpha透明;PNG24不支持透明;而PNG32在24位的PNG基础上增加了8位(256阶)的alpha通道透明;
优缺点:
1、能在保证最不失真的情况下尽可能压缩图像文件的大小。
2、对于需要高保真的较复杂的图像,PNG虽然能无损压缩,但图片文件较大,不适合应用在Web页面上。
介绍webp这个图片文件格式
WebP是google开发的一种旨在加快图片加载速度的图片格式
。图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器带宽资源和数据空间。是现代图像格式,提供了优越的无损和有损压缩的图片在网络上。使用WebP,网站管理员和web开发人员可以创建更小、更丰富的图像,使网页更快。
WebP无损的png图像小26%。WebP有损图像是25 - 34%小于等效SSIM质量指数可比JPEG图像
无损WebP支持透明(也称为alpha通道)的成本只有22%额外的字节。对有损压缩RGB压缩情况下是可以接受的,有损WebP还支持透明度,通常提供3×PNG相比较小的文件大小。
WebP 的优势体现在它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量;同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性,在 JPEG 和 PNG 上的转化效果都相当优秀、稳定和统一。
优势强劲所以推动起来也很快,因为压缩效率高,体积小,对节省磁盘空间、网络带宽,加快页面加载速度
Google、Youtube、Facebook、Ebay 以及很多国内较大的公司(TAB,360,美图等)的许多产品都开始使用 WebP 格式的图片,但现在仍有很多地方不支持这种格式,这时就需要用转换工具将图片转变为我们常用的 PNG 或 JPG 格式,在这里介绍一下转换的方法。
1、在线转换网站 cloudconvert
2、转换工具 isparta(Windows & Mac)
3、谷歌转换【翻墙查看】
base64 前端如何转化
场景一:将用户本地上传的资源转化,即用户通过浏览器点击文件上传时,将图片资源转化成base64
BOM属性对象方法
Window对象:open close confirm
Navigator对象: appName online userAgent
Screen对象
History对象方法: back()和forward() go()
Location对象: host hostname protocol hash
for in和for of的区别
for...in循环有几个缺点
①数组的键名是数字,但是for...in循环是以字符串作为键名"0"、"1"、"2"等等。
②for...in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
③某些情况下,for...in循环会以任意顺序遍历键名。
④for...in循环主要是为遍历对象而设计的,不适用于遍历数组。
⑤for...in 循环会自动跳过那些没被赋值的元素,而 for 循环则不会,它会显示出 undefined。
for...of循环 es6方法
①有着同for...in一样的简洁语法,但是没有for...in那些缺点。
②不同于forEach方法,它可以与break、continue和return配合使用。
③for in 会遍历自定义属性,for of不会推荐数组的时候用for of
一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbol.iterator方法。提供了遍历所有数据结构的统一操作接口.or...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串

image.png
数组中的forEach和map的区别
相同点
1、都是循环遍历数组中的每一项
2、forEach和map方法里每次执行匿名函数都支持3个参数,参数分别是item(当前每一项),index(索引值),arr(原数组)
3、匿名函数中的this都是指向window
4、只能遍历数组
5、都不会改变原数组
区别
map方法
1.map方法返回一个新的数组,数组中的元素为原始数组调用函数处理后的值。
2.map方法不会对空数组进行检测,map方法不会改变原始数组。
3.浏览器支持:chrome、Safari1.5+、opera都支持,IE9+,
**
javascript
array.map(function(item,index,arr){},thisValue)
var arr = [0,2,4,6,8];
var str = arr.map(function(item,index,arr){
console.log(this); //window
console.log("原数组arr:",arr); //注意这里执行5次
return item/2;
},this);
console.log(str);//[0,1,2,3,4]
若arr为空数组,则map方法返回的也是一个空数组。
forEach方法
foreEach()方法:
针对每一个元素执行提供的函数。
map()方法:
创建一个新的数组,其中每一个元素由调用数组中的每一个元素执行提供的函数得来。
1.forEach方法用来调用数组的每个元素,将元素传给回调函数
2.forEach对于空数组是不会调用回调函数的。
**
javascript
Array.forEach(function(item,index,arr){},this)
var arr = [0,2,4,6,8];
var sum = 0;
var str = arr.forEach(function(item,index,arr){
sum += item;
console.log("sum的值为:",sum); //0 2 6 12 20
console.log(this); //window
},this)
console.log(sum);//20
console.log(str); //undefined
无论arr是不是空数组,forEach返回的都是undefined。这个方法只是将数组中的每一项作为callback的参数执行一次。
forEach()可以做到的东西,map()也同样可以。反过来也是如此。
map()会分配内存空间存储新数组并返回,forEach()不会返回数据。
forEach()允许callback更改原始数组的元素。map()返回新的数组。
forEach()的执行速度 < map()的执行速度
.forEach(),.map()和.reduce()的区别,分别用来干什么
www.jianshu.com/p/541b84c9d...
一、语法
reduce() 是数组的归并方法,与forEach()、map()、filter()等迭代方法一样都会对数组每一项进行遍历,但是reduce() 可同时将前面数组项遍历产生的结果与当前遍历项进行运算,这一点是其他迭代方法无法企及的
arr.reduce(function(prev,cur,index,arr){
...
}, init);
其中,
arr 表示原数组;
prev 表示上一次调用回调时的返回值,或者初始值 init;
cur 表示当前正在处理的数组元素;
index 表示当前正在处理的数组元素的索引,若提供 init 值,则索引为0,否则索引为1;
init 表示初始值。
先提供一个原始数组:
**
ini
var arr = [3,9,4,3,6,0,9];
实现以下需求的方式有很多,其中就包含使用reduce()的求解方式,也算是实现起来比较简洁的一种吧。
- 求数组项之和
**
ini
var sum = arr.reduce(function (prev, cur) {
return prev + cur;
},0);
由于传入了初始值0,所以开始时prev的值为0,cur的值为数组第一项3,相加之后返回值为3作为下一轮回调的prev值,然后再继续与下一个数组项相加,以此类推,直至完成所有数组项的和并返回。
- 求数组项最大值
**
javascript
var max = arr.reduce(function (prev, cur) {
return Math.max(prev,cur);
});
由于未传入初始值,所以开始时prev的值为数组第一项3,cur的值为数组第二项9,取两值最大值后继续进入下一轮回调。
- 数组去重
**
ini
var newArr = arr.reduce(function (prev, cur) {
prev.indexOf(cur) === -1 && prev.push(cur);
return prev;
},[]);
数组去重
www.jianshu.com/p/3a5db29fb...
随机打乱一个数组
**
思路:从数组的最后一项开始,随机选择前面的一个元素进行交换,然后一步步往前交换
快速扰乱数组排序
**
javascript
var arr = [1,2,3,4,5,6,7,8,9,10];
arr.sort(function(){
return Math.random() - 0.5;
})
console.log(arr);
数组常用方法
www.jianshu.com/p/5e37efb06...
www.jianshu.com/p/d2f653c48...
查找数组重复项
**
ini
var newArr = arr.reduce(function (prev, cur) {
prev.indexOf(cur) === -1 && prev.push(cur);
return prev;
},[]);
扁平化数组
**
scss
arr.flat(Infinity)
arr.join().split(',').map(Number)
arr.toString().split(',').map(Number)
**
javascript
const arr = [1, [2, [3], 4], 5]
function flatten(arr) {
for (let i in arr) {
if (Array.isArray(arr[i])) {
arr.splice(i, 1, ...flatten(arr[i]))
}
}
return arr
}
手动实现parseInt
ES6中的map和原生的对象有什么区别
object和Map存储的都是键值对组合。但是:
object的键的类型是 字符串;
map的键的类型是 可以是任意类型;
另外注意,object获取键值使用Object.keys(返回数组);
Map获取键值使用 map变量.keys() (返回迭代器)。
什么是组件,他是怎么封装的
组件(Component)是对数据和方法的简单封装
js前端组件的封装方法
定义一个类
类中增加一个方法
body中定义一个dom节点
脚本中把dom节点和类定义结合起来 , 实现特定的组件功能
vue组件封装
建立组件的模板,先把架子搭起来,写写样式,考虑你的组件的基本逻辑
然后在引用得组件中 用import引入组件
通过component定义组件名称
在把组件以标签的形式写出来。
介绍纯函数
一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数叫做纯函数。
为什么要煞费苦心地构建纯函数?因为纯函数非常"靠谱",执行一个纯函数你不用担心它会干什么坏事,它不会产生不可预料的行为,也不会对外部产生影响。不管何时何地,你给它什么它就会乖乖地吐出什么。如果你的应用程序大多数函数都是由纯函数组成,那么你的程序测试、调试起来会非常方便。
函数的返回结果只依赖于它的参数。
函数执行过程里面没有副作用。
sum(2, 3)实现sum(2)(3)的效果
柯里化 和 反柯里化
**
scss
function add(x) {
var sum = x;
tmp = function (y) {
sum = sum + y;
return tmp;
};
tmp.toString = function () {
return sum;
};
return tmp;
}
console.log(add(1)); //6
console.log(add(1)(2)(3)(4)); //10
console.log(add(1)(2)(3)(4)(5));//15
console.log(add(1)(2)(3)(4)(5)(6));//21
实现一个类,可以on,emit,off,once,注册、调用、取消、注册仅能使用一次的事件
eventEmitter(emit,on,off,once)
实现instanceof
**
javascript
function instanceofFunc(obj, cons) {
// 错误判断 构造函数必须是一个function 其他的均报错
if (typeof cons !== 'function') throw new Error('instance error')
if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) return false
// 获取到原型对象
let proto = cons.prototype
// 如果obj的原型对象不是null
while (obj.__proto__) {
if (obj.__proto__ === proto) return true
obj = obj.__proto__
}
return false
}
console.log(instanceofFunc(() => {}, Function)) // true
[1, 2, 3, 4, 5]变成[1, 2, 3, a, b, 5]
**
css
var q = [1, 2, 3, 4, 5]
q.splice(3, 0, 'a')
q.splice(4, 0, 'b')
console.log(q);
取数组的最大值(ES5、ES6)
**
javascript
var q = [1, 2, 3, 4, 5]
console.log(Math.max(...q));//es6
console.log(Math.max.apply(this, q));//es5
ES5和ES6有什么区别
图片上传中...(image.png-682065-1584080584770-0)
some、every、find、filter、map、forEach有什么区别
如何找0-5的随机数,95-99呢
**
javascript
let num = Math.floor(Math.random() * 10)
console.log(num > 5 ? num - 5 : num);
页面上有1万个button如何绑定事件
使用事件委托, 利用了事件的冒泡机制.
针对btn绑定事件就一定要判断点击的target是不是btn, 如果做这一步, 点击被委托的父容器其他地方也会触发事件.
不要阻止冒泡事件!
如何判断是button
页面上生成一万个button,并且绑定事件,如何做(JS原生操作DOM)
遍历循环绑定 闭包 let作用域
循环绑定时的index是多少,为什么,怎么解决
闭包 let块级作用域
页面上有一个input,还有一个p标签,改变input后p标签就跟着变化,如何处理,监听input的哪个事件,在什么时候触发
如何用原生js给一个按钮绑定两个onclick事件?
**
javascript
// 事件监听 绑定多个事件
var btn = document.getElementById("btn");
btn.addEventListener('click', hello1)
btn.addEventListener("click", hello2);
function hello1() {
console.log(1);
}
function hello2() {
console.log(2);
}
拖拽会用到哪些事件
drag、dragstart、dragend、dragenter、dragover、dragleave、drop
介绍defineProperty方法,什么时候需要用到
www.jianshu.com/p/570a84ca7...
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。参见Object.defineProperty语法。在vue.js是通过它实现双向绑定的。俗称属性拦截器。
Object.defineProperty是es5上的方法,这也就是为什么vue.js不兼容ie8及其以下浏览器的原因。
**
javascript
Object.defineProperty(obj, prop, descriptor)
参数说明:
// obj:必需。目标对象
// prop:必需。需定义或修改的属性的名字
// descriptor:必需。目标属性所拥有的特性
for..in 和 object.keys的区别
for in遍历对象所有可枚举属性 包括原型链上的属性
Object.keys遍历对象所有可枚举属性 不包括原型链上的属性
hasOwnProperty检查对象是否包含属性名,无法检查原型链上是否具有此属性名
**
javascript
var aa = [12, 34, 5];
Array.prototype.add = function() {}
for(let i in aa) {
console.log(i);
//输出0 1 2 add
}
console.log('--------------')
console.log(Object.keys(aa));
//输出0 1 2
console.log(aa.hasOwnProperty('add'))
//输出false
console.log(aa.hasOwnProperty('0'))
//输出true
总的来说,操作中引入继承的属性会让问题复杂化,大多数时候,我们只关心对象自身的属性。所以,尽量不要用for...in循环,而用Object.keys()代替。
ES2017 引入了跟Object.keys
配套的Object.values
和Object.entries
,作为遍历一个对象的补充手段,供for...of
循环使用。
**
css
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
如何判断img加载完成
www.cnblogs.com/zhusf/p/106...
一、load事件
**
ini
<body>
<img id="img1"src="http://pic1.win4000.com/wallpaper/f/51c3bb99a21ea.jpg">
<p id="p1">loading...</p>
<script type="text/javascript">
img1.onload =function() {
p1.innerHTML ='loaded'
}
</script>
</body>
二、javascipt原生方法
选取指定ID的图片,通过onload指定回调方法,在图片加载完成后弹出"图片加载已完成"字样提示。
**
xml
<img id="pic1" src="..." />
<script language="JavaScript">
document.getElementById("pic1").onload = function () {
alert("图片加载已完成");
}
</script>
优点:简单易用,不影响HTML代码。
缺点:只能指定一个元素,javascipt代码必须置于图片元素的下方
三、onload方法
通过向img标签添加onload属性,并填入相应的函数来执行后续的javascipt代码。如下代码例子中img元素默认是不显示的,通过onload判断加载完成后再将图片显示出来。
**
ini
<img class="pic1" onload="get(this)" src="..." style='display:none' />
<script type="text/javascript">
function get(ts){
ts.style.display = 'block'; //显示图片
}
</script>
优点:可以将javascript代码部分放置于页面的任何部分加载,并且可以用于多数任意图片上。使用比较简单,易理解。
缺点:必须在每个标签上都贴上onlaod属性,在某些无法直接操作HTML代码,或者需要代码精简的情况下不适用
ajax请求时,如何解释json数据
JSON.parse()eval 方法
总结:"eval();"方法解析的时候不会去判断字符串是否合法,而且json对象中的js方法也会被执行,这是非常危险的; 而"JSON.parse();"方法的优点就不用多说了,推荐此方法。
对前端路由的理解?前后端路由的区别?
1.什么是路由
路由是根据不同的 url 地址展示不同的内容或页面;
2、什么是前端路由
很重要的一点是页面不刷新,前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,每跳转到不同的URL都是使用前端的锚点路由. 随着(SPA)单页应用的不断普及,前后端开发分离,目前项目基本都使用前端路由,在项目使用期间页面不会重新加载。
3、什么是后端路由?
浏览器在地址栏中切换不同的url时,每次都向后台服务器发出请求,服务器响应请求,在后台拼接html文件传给前端显示, 返回不同的页面, 意味着浏览器会刷新页面,网速慢的话说不定屏幕全白再有新内容。后端路由的另外一个极大的问题就是 前后端不分离。
优点:分担了前端的压力,html和数据的拼接都是由服务器完成。
缺点:当项目十分庞大时,加大了服务器端的压力,同时在浏览器端不能输入制定的url路径进行指定模块的访问。另外一个就是如果当前网速过慢,那将会延迟页面的加载,对用户体验不是很友好。
4,什么时候使用前端路由?
在单页面应用,大部分页面结构不变,只改变部分内容的使用
5,前端路由有什么优点和缺点?
**
makefile
优点:
1.用户体验好,和后台网速没有关系,不需要每次都从服务器全部获取,快速展现给用户
2.可以再浏览器中输入指定想要访问的url路径地址。
3.实现了前后端的分离,方便开发。有很多框架都带有路由功能模块。
缺点:
1.使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存
2.单页面无法记住之前滚动的位置,无法在前进,后退的时候记住滚动的位置
如何实现同一个浏览器多个标签页之间的通信
第一种------调用localStorage
在一个标签页里面使用 localStorage.setItem(key,value)添加(修改、删除)内容;在另一个标签页里面监听 storage 事件。
即可得到 localstorge 存储的值,实现不同标签页之间的通信。
标签页1:
**
xml
<input id="name">
<input type="button" id="btn" value="提交">
<script type="text/javascript">
$(function () {
$("#btn").click(function () {
var name = $("#name").val();
localStorage.setItem("name", name);
});
});
</script>
标签页2:
**
javascript
$(function () {
window.addEventListener("storage", function (event) {
console.log(event.key + "=" + event.newValue);
});
});
第二种------调用cookie+setInterval()
将要传递的信息存储在cookie中,每隔一定时间读取cookie信息,即可随时获取要传递的信息。
页面1:
**
ini
<input id="name">
<input type="button" id="btn" value="提交">
<script type="text/javascript">
$(function () {
$("#btn").click(function () {
var name = $("#name").val();
document.cookie = "name=" + name;
});
});
</script>
页面2:
**
xml
<script type="text/javascript">
$(function () {
function getCookie(key) {
return JSON.parse("{"" + document.cookie.replace(/;\s+/gim, "","").replace(/=/gim, "":"") + ""}")[key];
}
setInterval(function () {
console.log("name=" + getCookie("name"));
}, 10000);
});
</script>
require和import有什么不同
www.cnblogs.com/xiaolucky/p...
所有import的都能用 require,但用require的不能用import;import支持编译时静态分析,便于JS引入宏和类型检验。动态绑定。node编程中最重要的思想就是模块化,import和require都是被模块化所使用。
遵循规范
- require 是 AMD规范引入方式
- import是es6的一个语法标准,如果要兼容浏览器的话必须转化成es5的语法
调用时间
- require是运行时调用,所以require理论上可以运用在代码的任何地方
- import是编译时调用,所以必须放在文件开头
本质
- require是赋值过程,其实require的结果就是对象、数字、字符串、函数等,再把require的结果赋值给某个变量
- import是解构过程,但是目前所有的引擎都还没有实现import,我们在node中使用babel支持ES6,也仅仅是将ES6转码为ES5再执行,import语法会被转码为require
import用于引入外部模块。
require不仅可以引用文件和模块,而且使用位置不受限制,可以在代码中使用
js模块化(commonjs/AMD/CMD/ES6)
www.jianshu.com/p/1fde4eb32...
实现数组flat、filter等方法
图片懒加载、预加载
juejin.im/post/5b0c3b...
www.jianshu.com/p/4876a4fe7...
所谓懒加载就是通过某些特定的条件,然后再给图片的src赋值,常见的懒加载方式有点击加载和滚动加载。如果是点击加载,那么一般是通过点击事件
如果是加载,那么就有些复杂,首先你要先明白触发加载的条件,一般都是文档的高度-浏览器窗高度-浏览器距离顶部的高度<规定的尺寸。达到一定条件的后,向for循环的图片数组(笔者使用的是vue)添加元素。最困难是获取文档的高度,浏览器窗高度,浏览器距离顶部的高度。
当然你要注意滚动的上下方向,如果向上的话就不需要添加元素。
图片预加载:很简单通过创建img元素,并将要预加载的src赋值给img元素,通过src的onload达到预加载的目的,但是此时图片只是存在了浏览器,但是并没有显示在页面上,通过观察network的可以发现图片已经加载完毕。
**
ini
function loadImage(url,callback) {
var img = new Image();
img.src = url;
if(img.complete) { // 如果图片已经存在于浏览器缓存,直接调用回调函数
callback.call(img);
return; // 直接返回,不用再处理onload事件
}
img.onload = function(){
img.onload = null;
callback.call(img);
}
}
实现页面加载进度条
lazyMan
实现eventEmitter 实现instanceof new的过程 lazyMan 函数currying
函数currying
节流 防抖 生拷贝 数组乱序 flat filter 手写call & apply & bind
文件上传如何做断点续传
www.cnblogs.com/cangqinglan...
前端大文件上传网上的大部分文章已经给出了解决方案,核心是利用 Blob.prototype.slice 方法,和数组的 slice 方法相似,调用的 slice 方法可以返回原文件的某个切片
这样我们就可以根据预先设置好的切片最大数量将文件切分为一个个切片,然后借助 http 的可并发性,同时上传多个切片,这样从原本传一个大文件,变成了同时传多个小的文件切片,可以大大减少上传时间
另外由于是并发,传输到服务端的顺序可能会发生变化,所以我们还需要给每个切片记录顺序

image.png
iframe的缺点有哪些

image.png
getBoundingClientRect 方法的弊端;

image.png
静态资源加载和更新的策略;
大公司的静态资源优化方案,基本上要实现这么几个东西:
1.配置超长时间的本地缓存 ------ 节省带宽,提高性能
2.采用内容摘要
作为缓存更新依据 ------ 精确的缓存控制
3.静态资源CDN部署 ------ 优化网络请求
4.更资源发布路径实现非覆盖式发布
------ 平滑升级
5.合并打包,压缩,各种其他优化
缓存静态资源的注意事项
CDN 服务器的了解和使用;
CDN的全称是Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。CDN可以理解为一个普通缓存,如代理缓存或者说边缘缓存,即便不关心用户的具体地理位置,也应该考虑使用cdn的代理缓存来提高用户体验。
CDN的优势
很明显:
(1)CDN节点解决了跨运营商和跨地域访问的问题
,访问延时大大降低;
(2)大部分请求在CDN边缘节点完成,CDN起到了分流作用,减轻了源站的负载。
CDN的缺点
当网站更新时,如果CDN节点上数据没有及时更新,即便用户再浏览器使用Ctrl +F5的方式使浏览器端的缓存失效,也会因为CDN边缘节点没有同步最新数据而导致用户访问异常。
CDN缓存策略
CDN边缘节点缓存策略因服务商不同而不同,但一般都会遵循http标准协议,通过http响应头中的Cache-control: max-age的字段来设置CDN边缘节点数据缓存时间。
当客户端向CDN节点请求数据时,CDN节点会判断缓存数据是否过期,若缓存数据并没有过期,则直接将缓存数据返回给客户端;否则,CDN节点就会向源站发出回源请求,从源站拉取最新数据,更新本地缓存,并将最新数据返回给客户端。
CDN服务商一般会提供基于文件后缀、目录多个维度来指定CDN缓存时间,为用户提供更精细化的缓存管理。
CDN缓存时间会对"回源率"产生直接的影响。若CDN缓存时间较短,CDN边缘节点上的数据会经常失效,导致频繁回源,增加了源站的负载,同时也增大的访问延时;若CDN缓存时间太长,会带来数据更新时间慢的问题。开发者需要增对特定的业务,来做特定的数据缓存时间管理。
CDN缓存刷新
CDN边缘节点对开发者是透明的,相比于浏览器Ctrl+F5的强制刷新来使浏览器本地缓存失效,开发者可以通过CDN服务商提供的"刷新缓存"接口来达到清理CDN边缘节点缓存的目的。这样开发者在更新数据后,可以使用"刷新缓存"功能来强制CDN节点上的数据缓存过期,保证客户端在访问时,拉取到最新的数据。
webkit基础知识
请简单实现双向数据绑定mvvm
vuejs是利用Object.defineProperty来实现的MVVM,采用的是订阅发布模式。 每个data中都有set和get属性,这种点对点的效率,比Angular实现MVVM的方式的效率更高。
**
xml
<body>
<input type="text">
<script>
const input = document.querySelector('input')
const obj = {}
Object.defineProperty(obj, 'data', {
enumerable: false, // 不可枚举
configurable: false, // 不可删除
set(value){
input.value = value
_value = value
// console.log(input.value)
},
get(){
return _value
}
})
obj.data = '123'
input.onchange = e => {
obj.data = e.target.value
}
</script>
</body>
Dom操作
**
javascript
增删改查, 如:
document.elementById
document.querySelectAll
document.appendChild
docuemnt.removeChild
实现一个函数,判断是不是回文字符串
原文的思路是将字符串转化成数组=>反转数组=>拼接成字符串。这种做法充分利用了js的BIF(内置函数),但性能有所损耗:
**
javascript
function run(input) {
if (typeof input !== 'string') return false;
return input.split('').reverse().join('') === input;
}
复制代码其实正常思路也很简单就能实现,性能更高,但是没有利用js的特性:
// 回文字符串
const palindrome = (str) => {
// 类型判断
if(typeof str !== 'string') {
return false;
}
let len = str.length;
for(let i = 0; i < len / 2; ++i){
if(str[i] !== str[len - i - 1]){
return false;
}
}
return true;
}
场景题:一个气球从右上角移动到中间,然后抖动,如何实现
文件上传如何实现?,除了input还有什么别的方法?
用flash,如uploadify
h5 file API:HTML5拖拽多文件上传asp.net示例
还可以在浏览器把图片转成base64字符串,然后把字符串发到服务器端存起来
使用js实现一个持续的动画效果
安排直接看连接
解析url后的参数
实现一个简单的模版引擎:
如何快速让字符串变成已千为精度的数字
**
javascript
function exchange(num) {
num += ''; //转成字符串
if (num.length <= 3) {
return num;
}
num = num.replace(/\d{1,3}(?=(\d{3})+$)/g, (v) => {
console.log(v)
return v + ',';
});
return num;
}
console.log(exchange(1234567));
逻辑分辨率和物理分辨率有什么区别,如何利用js互相转化

image.png
utf-8和unicode的区别

image.png
Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。
类似的,日文和韩文等其他语言也有这个问题。为了统一所有文字的编码,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。
世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。
可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Unicode,就像它的名字都表示的,这是一种所有符号的编码。
Unicode 当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字严。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表。
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件:
JS判断设备来源
**
javascript
function deviceType(){
var ua = navigator.userAgent;
var agent = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
for(var i=0; i<len,len = agent.length; i++){
if(ua.indexOf(agent[i])>0){
break;
}
}
}
deviceType();
window.addEventListener('resize', function(){
deviceType();
})
微信的 有些不太一样
function isWeixin(){
var ua = navigator.userAgent.toLowerCase();
if(ua.match(/MicroMessenger/i)=='micromessenger'){
return true;
}else{
return false;
}
}
让文本不可复制
**
sql
-webkit-user-select: none;
-ms-user-select: none;
-moz-user-select: none;
-khtml-user-select: none;
user-select: none;
1、答案区域监听copy事件,并阻止这个事件的默认行为。
2、获取选中的内容(window.getSelection())加上版权信息,然后设置到剪切板(clipboarddata.setData())。
js的 for 跟for in 循环它们之间的区别?
**
typescript
遍历数组时的异同: for循环 数组下标的typeof类型:number,
for in 循环数组下标的typeof类型:stringvar southSu = ['苏南','深圳','18','男'];
for(var i=0;i<southSu.length;i++){
console.log(typeof i); //number
console.log(southSu[i]);// 苏南 , 深圳 , 18 , 男
}
var arr = ['苏南','深圳','18','男','帅气'];
for(var k in arr){
console.log(typeof k);//string
console.log(arr[k]);// 苏南 , 深圳 , 18 , 男 , 帅气
}
复制代码遍历对象时的异同:for循环 无法用于循环对象,获取不到obj.length;
for in 循环遍历对象的属性时,原型链上的所有属性都将被访问,解决方案:
使用hasOwnProperty方法过滤或Object.keys会返回自身可枚举属性组
成的数组 Object.prototype.test = '原型链上的属性';//首席填坑官∙苏南的专栏,梅斌的专栏
var southSu = {name:'苏南',address:'深圳',age:18,sex:'男',height:176};
for(var i=0;i<southSu.length;i++){
console.log(typeof i); //空
console.log(southSu[i]);//空
}
for(var k in southSu){
console.log(typeof k);//string
console.log(southSu[k]);// 苏南 , 深圳 , 18 , 男 , 176 , 原型链上的属性
}
说说 cookies,sessionStorage 、 localStorage 你对它们的理解?**
- cookie是网站为了标示用户身份而储存在用户本地终端上的数据(通常经过加密),cookie数据始终在同源的http请求中携带,记会在浏览器和服务器间来回传递。
- sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
- cookie数据大小不能超过4k。 sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
- localStorage 存储持久数据,浏览器关闭后数据不丢失除非用户主动删除数据或清除浏览器/应用缓存; sessionStorage 数据在当前浏览器窗口关闭后自动删除。 cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
- 部分面试官可能还会再深入一些:
1)、如何让
cookie
浏览器关闭就失效?------不对cookie设置任何正、负或0时间的即可;
2)、sessionStorage在浏览器多窗口之间 (同域)数据是否互通共享?
------不会,都是独立的,localStorage会共享;
3)、能让localStorage也跟cookie一样设置过期时间?
答案是可以的,在存储数据时,也存储一个时间戳,get数据之前,先拿当前时间跟你之前存储的时间戳做比较 详细可看我之前写的另一篇分享([小程序项目总结]
请简述js中的this指针绑定
这个几乎是常问到的知识点,我在看《你不知道的javascript》书中有过很详细的描述。js中的this指针绑定总结下包含四种形式:默认绑定,隐式绑定,显式绑定,new绑定,优先级从小到大,有分别阐述了四种形式的代码。
**
javascript
// 默认绑定
function foo(){
console.info(this.a)
}
var a = 'hello'
foo()
// 隐式绑定
// 调用位置是否有上下文对象
function foo() {
console.info(this.a)
}
var obj = {
a: 1,
foo: foo
}
obj.foo()
// 显式绑定
// 对应apply call bind
// 其中bind又叫硬绑定
// bind(..) 会返回一个硬编码的新函数,它会把参数设置为this 的上下文并调用原始函数。
垃圾回收机制
// [防爬虫标识-沙海听雨]
// new绑定
// 使用new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
// 1. 创建(或者说构造)一个全新的对象。
// 2. 这个新对象会被执行[[ 原型]] 连接。
// 3. 这个新对象会绑定到函数调用的this。
// 4. 如果函数没有返回其他对象,那么new 表达式中的函数调用会自动返回这个新对象。