二、js
(一)字符串
1.字符串的切割:String.prototype.split()
split方法按照给定规则分割字符串,返回一个由分割出来的子字符串组成的数组。
'a|b|c'.split('|') // ["a", "b", "c"]
- 如果分割规则为空字符串,则返回数组的成员是原字符串的每一个字符。
'a|b|c'.split('') // ["a", "|", "b", "|", "c"]
- 如果省略参数,则返回数组的唯一成员就是原字符串。
'a|b|c'.split() // ["a|b|c"]
- 如果满足分割规则的两个部分紧邻着(即两个分割符中间没有其他字符),则返回数组之中会有一个空字符串。
'a||c'.split('|') // ['a', '', 'c']
- 如果满足分割规则的部分处于字符串的开头或结尾(即它的前面或后面没有其他字符),则返回数组的第一个或最后一个成员是一个空字符串。
'|b|c'.split('|') // ["", "b", "c"]
'a|b|'.split('|') // ["a", "b", ""]
- split方法还可以接受第二个参数,限定返回数组的最大成员数。
'a|b|c'.split('|', 0) // []
'a|b|c'.split('|', 1) // ["a"]
'a|b|c'.split('|', 2) // ["a", "b"]
'a|b|c'.split('|', 3) // ["a", "b", "c"]
'a|b|c'.split('|', 4) // ["a", "b", "c"]
上面代码中,split方法的第二个参数,决定了返回数组的成员数。
2.字符串的拼接:String.prototype.concat()
- concat方法用于连接两个字符串,返回一个新字符串,不改变原字符串。
var s1 = 'abc';
var s2 = 'def';
s1.concat(s2) // "abcdef"
s1 // "abc"
- 该方法可以接受多个参数。
'a'.concat('b', 'c') // "abc"
- 如果参数不是字符串,concat方法会将其先转为字符串,然后再连接。
var one = 1;
var two = 2;
var three = '3';
''.concat(one, two, three) // "123"
one + two + three // "33"
上面代码中,concat方法将参数先转成字符串再连接,所以返回的是一个三个字符的字符串。作为对比,加号运算符在两个运算数都是数值时,不会转换类型,所以返回的是一个两个字符的字符串。
3.字符串的提取:
(1)String.prototype.slice()
slice方法用于从原字符串取出子字符串并返回,不改变原字符串。它的第一个参数是子字符串的开始位置,第二个参数是子字符串的结束位置(不含该位置)。
'JavaScript'.slice(0, 4) // "Java"
- 如果省略第二个参数,则表示子字符串一直到原字符串结束。
'JavaScript'.slice(4) // "Script"
- 如果参数是负值,表示从结尾开始倒数计算的位置,即该负值加上字符串长度。
'JavaScript'.slice(-6) // "Script"
'JavaScript'.slice(0, -6) // "Java"
'JavaScript'.slice(-2, -1) // "p"
- 如果第一个参数大于第二个参数,slice方法返回一个空字符串。
'JavaScript'.slice(2, 1) // ""
(2)String.prototype.substr()
substr方法用于从原字符串取出子字符串并返回,不改变原字符串,跟slice和substring方法的作用相同。
- substr方法的第一个参数是子字符串的开始位置(从0开始计算),第二个参数是子字符串的长度。
'JavaScript'.substr(4, 6) // "Script"
- 如果省略第二个参数,则表示子字符串一直到原字符串的结束。
'JavaScript'.substr(4) // "Script" - 如果第一个参数是负数,表示倒数计算的字符位置。如果第二个参数是负数,将被自动转为0,因此会返回空字符串。
'JavaScript'.substr(-6) // "Script"
'JavaScript'.substr(4, -1) // ""
上面代码中,第二个例子的参数-1自动转为0,表示子字符串长度为0,所以返回空字符串。
(二)数组
1.添加元素:push(),unshift()
- push方法用于在数组的末端添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
var arr = [];
arr.push(1) // 1
arr.push('a') // 2
arr.push(true, {}) // 4
arr // [1, 'a', true, {}]
上面代码使用push方法,往数组中添加了四个成员。
- unshift()方法用于在数组的第一个位置添加元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
var a = ['a', 'b', 'c'];
a.unshift('x'); // 4
a // ['x', 'a', 'b', 'c']
unshift()方法可以接受多个参数,这些参数都会添加到目标数组头部。
var arr = [ 'c', 'd' ];
arr.unshift('a', 'b') // 4
arr // [ 'a', 'b', 'c', 'd' ]
2.删除元素:pop(),shift()
- pop方法用于删除数组的最后一个元素,并返回该元素。注意,该方法会改变原数组。
var arr = ['a', 'b', 'c'];
arr.pop() // 'c'
arr // ['a', 'b']
对空数组使用pop方法,不会报错,而是返回undefined。
[].pop() // undefined
push和pop结合使用,就构成了“后进先出”的栈结构(stack)。
var arr = [];
arr.push(1, 2);
arr.push(3);
arr.pop();
arr // [1, 2]
上面代码中,3是最后进入数组的,但是最早离开数组。
- shift()方法用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组。
var a = ['a', 'b', 'c'];
a.shift() // 'a'
a // ['b', 'c']
上面代码中,使用shift()方法以后,原数组就变了。
shift()方法可以遍历并清空一个数组。
var list = [1, 2, 3, 4];
var item;
while (item = list.shift()) {
console.log(item);
}
list // [
上面代码通过list.shift()方法每次取出一个元素,从而遍历数组。它的前提是数组元素不能是0或任何布尔值等于false的元素,因此这样的遍历不是很可靠。
push()和shift()结合使用,就构成了“先进先出”的队列结构(queue)。
4.splice()
splice方法用于删除原数组的一部分成员,并可以在删除的位置添加新的数组成员,返回值是被删除的元素。注意,该方法会改变原数组。
arr.splice(start, count, addElement1, addElement2, ...);
splice的第一个参数是删除的起始位置(从0开始),第二个参数是被删除的元素个数。如果后面还有更多的参数,则表示这些就是要被插入数组的新元素。
var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(4, 2) // ["e", "f"]
a // ["a", "b", "c", "d"]
上面代码从原数组4号位置,删除了两个数组成员。
var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(4, 2, 1, 2) // ["e", "f"]
a // ["a", "b", "c", "d", 1, 2]
上面代码除了删除成员,还插入了两个新成员。
- 起始位置如果是负数,就表示从倒数位置开始删除。
var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(-4, 2) // ["c", "d"]
上面代码表示,从倒数第四个位置c开始删除两个成员。
- 如果只是单纯地插入元素,splice方法的第二个参数可以设为0。
var a = [1, 1, 1];
a.splice(1, 0, 2) // []
a // [1, 2, 1, 1]
- 如果只提供第一个参数,等同于将原数组在指定位置拆分成两个数组。
var a = [1, 2, 3, 4];
a.splice(2) // [3, 4]
a // [1, 2]
4.合并数组:concat()
concat方法用于多个数组的合并。它将新数组的成员,添加到原数组成员的后部,然后返回一个新数组,原数组不变。
['hello'].concat(['world'])
// ["hello", "world"]
['hello'].concat(['world'], ['!'])
// ["hello", "world", "!"]
[].concat({a: 1}, {b: 2})
// [{ a: 1 }, { b: 2 }]
[2].concat({a: 1})
// [2, {a: 1}]
除了数组作为参数,concat也接受其他类型的值作为参数,添加到目标数组尾部。
[1, 2, 3].concat(4, 5, 6)
// [1, 2, 3, 4, 5, 6]
如果数组成员包括对象,concat方法返回当前数组的一个浅拷贝。所谓“浅拷贝”,指的是新数组拷贝的是对象的引用。
var obj = { a: 1 };
var oldArray = [obj];
var newArray = oldArray.concat();
obj.a = 2;
newArray[0].a // 2
上面代码中,原数组包含一个对象,concat方法生成的新数组包含这个对象的引用。所以,改变原对象以后,新数组跟着改变。
5.提取数组:slice()
slice方法用于提取目标数组的一部分,返回一个新数组,原数组不变。
arr.slice(start, end);
它的第一个参数为起始位置(从0开始),第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员。
var a = ['a', 'b', 'c'];
a.slice(0) // ["a", "b", "c"]
a.slice(1) // ["b", "c"]
a.slice(1, 2) // ["b"]
a.slice(2, 6) // ["c"]
a.slice() // ["a", "b", "c"]
上面代码中,最后一个例子slice没有参数,实际上等于返回一个原数组的拷贝。
- 如果slice方法的参数是负数,则表示倒数计算的位置。
var a = ['a', 'b', 'c'];
a.slice(-2) // ["b", "c"]
a.slice(-2, -1) // ["b"]
上面代码中,-2表示倒数计算的第二个位置,-1表示倒数计算的第一个位置。
- 如果第一个参数大于等于数组长度,或者第二个参数小于第一个参数,则返回空数组。
var a = ['a', 'b', 'c'];
a.slice(4) // []
a.slice(2, 1) // []
- slice方法的一个重要应用,是将类似数组的对象转为真正的数组。
Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })
// ['a', 'b']
Array.prototype.slice.call(document.querySelectorAll("div"));
Array.prototype.slice.call(arguments);
上面代码的参数都不是数组,但是通过call方法,在它们上面调用slice方法,就可以把它们转为真正的数组。
6.数组转字符串:
join()方法以指定参数作为分隔符,将所有数组成员连接为一个字符串返回。如果不提供参数,默认用逗号分隔。
var a = [1, 2, 3, 4];
a.join(' ') // '1 2 3 4'
a.join(' | ') // "1 | 2 | 3 | 4"
a.join() // "1,2,3,4"
- 如果数组成员是undefined或null或空位,会被转成空字符串。
[undefined, null].join('#')
// '#'
['a',, 'b'].join('-')
// 'a--b'
- 通过call方法,这个方法也可以用于字符串或类似数组的对象。
Array.prototype.join.call('hello', '-')
// "h-e-l-l-o"
var obj = { 0: 'a', 1: 'b', length: 2 };
Array.prototype.join.call(obj, '-')
// 'a-b'
(二)性能优化
1.优化的思路
加载的优化
体验的优化
- 加载的优化
网络越快越好:
使用CDN
东西体积越少越好:
前端所有资源压缩(特别是图片),
东西数量越少越好:
icon,css,js等资源打包合并
服务器处理的越快越好
能重复利用的最好重复利用 - 体验的优化
只给用户暂时需要的东西
别让用户感觉卡顿
动画不要卡:
优先使用css3的动画,
2.页面优化
- 内容方面:
减少 HTTP 请求 (Make Fewer HTTP Requests)
减少 DOM 元素数量 (Reduce the Number of DOM Elements)
使得 Ajax 可缓存 (Make Ajax Cacheable) - 针对CSS:
把 CSS 放到代码页上端 (Put Stylesheets at the Top)
从页面中剥离 JavaScript 与 CSS (Make JavaScript and CSS External)
精简 JavaScript 与 CSS (Minify JavaScript and CSS)
避免 CSS 表达式 (Avoid CSS Expressions) - 针对JavaScript :
脚本放到 HTML 代码页底部 (Put Scripts at the Bottom)
从页面中剥离 JavaScript 与 CSS (Make JavaScript and CSS External)
精简 JavaScript 与 CSS (Minify JavaScript and CSS)
移除重复脚本 (Remove Duplicate Scripts) - 面向图片(Image):
优化图片
不要在 HTML 中使用缩放图片
使用恰当的图片格式
使用 CSS Sprites 技巧对图片优化
3.页面卡的原因
4.浏览器本地存储
- js中包含sessionStorage和localStorage以及cookie三种浏览器端的数据存储方式。
sessionStorage 、localStorage 和 cookie 之间的共同点:都是保存在浏览器端,且同源的。
sessionStorage 、localStorage 和 cookie 之间的区别: - cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。cookie数据还有网址路径(path)的概念,可以限制cookie只属于某个网址路径下。
- 存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
- 数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
- 作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。
2.使用方法
sessionstorage
sessionStorage.setItem("name","luanpeng"); //添加存储key-value
sessionStorage.age = 12; //设置数据
for(var key in sessionStorage) //遍历数据
console.log(sessionStorage.getItem(key)); //getItem读取属性值
delete sessionStorage.name; //删除数据
sessionStorage.removeItem("age"); //删除数据localstorage
-
localstorage同一个对象访问必须域名相同。数据保留至用户删除或清除缓存
localStorage.setItem("name","luanpeng"); //添加设置属性
localStorage.age = 12; //添加设置
console.log(localStorage.getItem("age")); //读取
console.log(localStorage.name); //读取
cookie
export const cookie = {//根据key值获取对应的cookie
get: (key) => {//获取cookie const data = document.cookie; //获取key第一次出现的位置 pwd= let startIndex = data.indexOf(key+'='); // name=123;pwd=abc //如果开始索引值大于0表示有cookie if(startIndex>-1) { //key的起始位置等于出现的位置加key的长度+1 startIndex = startIndex+key.length+1; //结束位置等于从key开始的位置之后第一次;号所出现的位置 let endIndex = data.indexOf(';',startIndex); //如果未找到结尾位置则结尾位置等于cookie长度,之后的内容全部获取 endIndex = endIndex<0 ? data.length:endIndex; return decodeURIComponent(data.substring(startIndex,endIndex)); }else { return ''; }
},
set:(key,value,time) => {
//默认保存时间
var time = time;
//获取当前时间
let cur = new Date();
//设置指定时间
cur.setTime(cur.getTime()+time243600*1000);//创建cookie 并且设置生存周期为GMT时间 document.cookie = key+'='+encodeURIComponent(value)+';expires='+(time===undefined?'':cur.toGMTString());
},
del:function(key){
//获取cookie const data = this.get(key); //如果获取到cookie则重新设置cookie的生存周期为过去时间 if(data!==false){ this.set(key,data,-1); }
}
};
3.注意点
localStorage和sessionStorage只能存储字符串类型的对象;
localStorage是永久存储的,除非用户显示的删除;
sessionStorage生命周期为当前窗口或标签页,一旦窗口或标签页关闭了sessionStorage将清空;
不同浏览器不能共享sessionStorage和localStorage中的信息;
不同浏览器无法共享localStorage或sessionStorage中的信息。相同浏览器的不同页面间可以共享相同的localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标签页仅指顶级窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的。
4.web缓存
- 前端缓存概述
前端缓存主要是分为HTTP缓存和浏览器缓存。其中HTTP缓存是在HTTP请求传输时用到的缓存,主要在服务器代码上设置;而浏览器缓存则主要由前端开发在前端js上进行设置。下面会分别具体描述。 - 前端缓存分类
2.1 HTTP缓存
整体流程:HTTP缓存都是从第二次请求开始的。
第一次请求资源时,服务器返回资源,并在respone header头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,击中强缓存就直接200,否则就把请求参数加到request header头中传给服务器,看是否击中协商缓存,击中则返回304,否则服务器会返回新的资源。
cookie 和 session
cookie
cookie是存储在浏览器上的一小段数据,用来记录某些当页面关闭或者刷新后仍然需要记录的信息。在控制台用 「document.cookie」查看你当前正在浏览的网站的cookie。
cookie可以使用 js 在浏览器直接设置(用于记录不敏感信息,如用户名), 也可以在服务端通使用 HTTP 协议规定的 set-cookie 来让浏览器种下cookie,这是最常见的做法。(打开一个网站,清除全部cookie,然后刷新页面,在network的Response headers试试找一找set-cookie吧)
每次网络请求 Request headers 中都会带上cookie。所以如果 cookie 太多太大对传输效率会有影响。
一般浏览器存储cookie 最大容量为4k,所以大量数据不要存到cookie。
设置cookie时的参数:
path:表示 cookie 影响到的路径,匹配该路径才发送这个 cookie。
expires 和 maxAge:告诉浏览器 cookie 时候过期,maxAge 是 cookie 多久后过期的相对时间。不设置这两个选项时会产生 session cookie,session cookie 是 transient 的,当用户关闭浏览器时,就被清除。一般用来保存 session 的 session_id。
secure:当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效
httpOnly:浏览器不允许脚本操作 document.cookie 去更改 cookie。一般情况下都应该设置这个为 true,这样可以避免被 xss 攻击拿到cookie。
测试: 很多网站的静态资源使用CDN地址而是使用当前网站域名,从cookie的角度说说这对性能有何影响?
session
当一个用户打开淘宝登录后,刷新浏览器仍然展示登录状态。服务器如何分辨这次发起请求的用户是刚才登录过的用户呢?这里就使用了session保存状态。用户在输入用户名密码提交给服务端,服务端验证通过后会创建一个session用于记录用户的相关信息的对象,这个 session 可保存在服务器内存中(容易产生内存泄露),生产环境一般是保存在数据库中。
创建session后,会把关联的session_id 通过setCookie 添加到http响应头部中。
浏览器在加载页面时发现响应头部有 set-cookie字段,就把这个cookie 种到浏览器指定域名下。
当下次刷新页面时,发送的请求会带上这条cookie, 服务端在接收到后根据这个session_id来识别用户。
cookie 是存储在浏览器里的一小段「数据」,而session是一种让服务器能识别某个用户的「机制」,当然也可以特指服务器存储的 session 数据。session 在实现的过程中需要使用cookie。
页面要显示英文或者中文怎么显示相应的文字?
多语言的切换界面大概就分三步走:
1.前端页面多语言
2.数据库多语言
3.用户访问语言统一
第一步:页面多语言
需要考虑的问题是:
A.用户登陆时候,自动识别字符,调用不同的语言包?
B.用户切换不同语言时候,调用不同的语言包?
C.增加多语言后的目录结构?
页面多语言也就是外观的多语言化,这里可以采用静态的语言包的方式。
设计时候就应该包括language的目录,针对不同语言有独立的子目录。
如英文language/en ,简体中文language/gb,繁体中文language/b5 (可以扩展其他语言)
每个目录下就包含了对每个页面的语言版本。选择语言版本时候就可以调用相应版本的语言包。
2.数据库多语言
这个考虑的问题:
A.后台录入数据的多语言化?
B.用户在不同版本下,提交的内容,如何保存?
C.提供三种语言包,还是提供英文和简体,简体通过转化提供繁体?
数据库多语言就是达到多语言在数据库里面的统一。就需要采用utf-8统一编码。
无论什么语言的文字,都统一使用utf-8来存放到数据库里面。采用表字段来表识
属于什么语言版本的文字。
3.简体转化的繁体。
利用php的iconv.此过程对于linux/unix有效,对于windows无效。
iconv("GB2312","BIG5",$text);
4.因为,charset = "utf-8",数据就都是以utf-8编码方式存在,
添加数据时候,要分别用en/gb/big5来标识语言版本.
INSERT INTO zz_importer
VALUES (,'', '', 'en');
INSERT INTO zz_importer
VALUES (,'', '', 'gb');
INSERT INTO zz_importer
VALUES (,'', '', 'big5');
vue.js的优点
Vue.js的特点:MVVM框架、数据驱动、组件化、轻量、简洁、高效、快速、模块友好
其实Vue.js不是一个框架,因为它只聚焦视图层,是一个构建数据驱动的Web界面的库。
Vue.js通过简单的API(应用程序编程接口)提供高效的数据绑定和灵活的组件系统。
Vue.js的特性如下:
1.轻量级的框架
2.双向数据绑定
3.指令
4.插件化
优点: 1. 简单:官方文档很清晰,比 Angular 简单易学。
2. 快速:异步批处理方式更新 DOM。
3. 组合:用解耦的、可复用的组件组合你的应用程序。
4. 紧凑:~18kb min+gzip,且无依赖。
5. 强大:表达式 & 无需声明依赖的可推导属性 (computed properties)。
6. 对模块友好:可以通过 NPM、Bower 或 Duo 安装,不强迫你所有的代码都遵循 Angular 的各种规定,使用场景更加灵活。
缺点: 1. 新生儿:Vue.js是一个新的项目,没有angular那么成熟。
2. 影响度不是很大:google了一下,有关于Vue.js多样性或者说丰富性少于其他一些有名的库。
3. 不支持IE8: