变量声明

声明变量

let

赋值

变量赋值

ago
1
2
3
let a = 1;
let b = 2;
let c = 3;
now

1-从数组中提取值,按照对应位置,对变量赋值

1
2
3
let [a, b, c] = [1, 2, 3];
console.log(a); //1
console.log(b); //2

2-“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值,解构不成功,变量的值就等于undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let [foo, [[bar], baz]] = [1, [[2], 3 ]];
foo // 1
bar // 2
baz // 3
--------------------------------------------------
let [x, , y] = [1, 2, 3];
x // 1
y // 3
--------------------------------------------------
let [, , third] = ["foo", "bar", "baz"];
third // "baz"
--------------------------------------------------
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
--------------------------------------------------
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

3-等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。

1
2
3
4
5
6
7
8
let [x, y] = [1, 2, 3];
x // 1
y // 2
--------------------------------------------------
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4

对象赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var {foo: baz} = {foo: 'aaa',bar: 'bbb'};
baz // "aaa"
--------------------------------------------------
let obj = {
first: 'hello',
last: 'world'
};
--------------------------------------------------
let {
first: f,
last: l
} = obj;
f // 'hello'
l // 'world'

作用域

申明变量 所声明的变量,只在let命令所在的代码块内有效。

1-局部声明

1
2
3
4
5
6
{
let a = 10;
var b = 20;
}
console.log(b); //20
console.log(a) // 报错

2-不存在变量提升

1
2
3
4
console.log(b);
var b = 10; //undefined
console.log(a);
let a = 10; //报错

3-暂时性死区

ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var tmp = 123;
if (true) {
tmp = 'abc'; // 报错
let tmp;
}
--------------------------------------------------
if (true) {
// TDZ开始
tmp = 'abc';
console.log(tmp); // 报错
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}

4-不允许重复声明

let不允许在相同作用域内,重复声明同一个变量。

1
2
3
4
5
6
7
8
9
10
11
12
function fn() {
let a = 10;
var a = 1;
}
fn();
--------------------------------------------------
// 报错
function fn1() {
let a = 10;
let a = 1;
}
fn1();

5-不能在函数内部重新声明参数

1
2
3
4
5
6
7
8
9
function func(arg) {
let arg; // 报错
}
--------------------------------------------------
function func(arg) {
{
let arg; // 不报错
}
}

const

块级作用域,也不会自动提升全局对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const num = 3; //同一个块中不允许声明同名变量
--------------------------------------------------
const num = 1;
if(true){
const num = 2;
console.log(num); //2
}
console.log(num);//1
const num; //必须一次性完成初始化 = 声明 + 赋值
num = 1;
--------------------------------------------------
const PI = 3.14; //常量大写,单词间以_分割
console.log('足球的PI:',PI);
//篮球的开发
//PI = 3.1415926; //不允许二次赋值
console.log('篮球的PI',PI);

解决回调地狱(promise)

解决回调地狱

多重ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
--------------------
<button>发送一堆ajax</button>
function sendMsg(url, callback) {
//ajax
var xhr = new XMLHttpRequest();
xhr.open('get', url);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
//响应回来,请求1.json
alert(xhr.responseText);
//请求2.json
//后续操作,2||3||4.json,该事宜会发生改变
callback(); //你传递的后续要做的事情
}
}
xhr.send();
}
document.querySelector('button').onclick = function() {
// sendMsg('./1.json');
// sendMsg('./2.json');
// sendMsg('./3.json');
// sendMsg('./4.json');
// sendMsg('./1.json');
// sendMsg('./2.json');
// sendMsg('./3.json');
// sendMsg('./4.json');
// 理论上请求挨个出去,但是,响应回来的速度,不一定,此时就会出现响应顺序不一致的情况
//万恶的回调函数地狱,可维护性差
sendMsg('./1.json', function() {
sendMsg('./2.json', function() {
sendMsg('./3.json', function() {
sendMsg('./1.json', function() {
sendMsg('./2.json', function() {
sendMsg('./3.json', function() {
console.log('完成了');
});
});
})
});
});
});
}

promise

  • promise是一个容器,用来管理异步流程,执行的过程中,
  • 通过函数调用,记录住执行成功与否的状态,成功->then,失败->catch
  • 保证顺序执行的then回调函数中,记得return 一个promise对象
  • promise三种状态: pendding(待发) 没有调用reject或者resolve的时候
  • resolved(fulilled) 已解决已满足 调用了resolve后的状态
  • rejected 已拒绝 调用reject函数后的状态
  • 一经改变,无法回退、也不可以暂停

每一个new Promise中包含着要么成功,要么失败的后续标识
每一个promise对象都可以.then函数来获取成功后的操作
每一个promise对象也可以.catch函数来获取失败后的操作

new Promise接受的参数是一个函数
该函数的参数中,1:成功 2:失败
成功(resolve)和失败(reject)也是函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<button>发送一堆ajax</button>
-------------------------------------------------------------------------
function sendMsg(url, callback) {
var p = new Promise(function(resolve,reject){
//包含整件事的执行
var xhr = new XMLHttpRequest();
xhr.open('get', url);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
//成功后的操作
alert(xhr.responseText);
//调用成功函数,其实就是做一个标记,存储起来,未来该对象.then就能执行
resolve('牛逼了');
}
}
xhr.send();
});
return p;//返回p对象外部then||catch
}
document.querySelector('button').onclick = function() {
sendMsg('./1.json')
.then(function(data){
//成功后的回调函数
// console.log('1.json请求完成,成功!!!',data);
return sendMsg('./2.json');
})
.then(function(data){
return sendMsg('./3.json');
})
.then(function(data){
return sendMsg('./4.json');
})
.then(function(data){
return sendMsg('./1.json');
})
.then(function(data){
return sendMsg('./2.json');
})
.then(function(data){
return sendMsg('./3.json');
})
.then(function(data){
return sendMsg('./4.json');
})
.then(function(data){
console.log('结束了');
})
.catch(function(){ //一组promise对象,一个catch多个then
//失败的回调函数
});
}

检测数据的四种方案

检测数据的四种方案

在 ECMAScript 规范中,共定义了 7 种数据类型,分为 基本类型 和 引用类型 两大类,如下所示:

基本类型:String、Number、Boolean、Symbol、Undefined、Null

引用类型:Object

基本类型也称为简单类型,由于其占据空间固定,是简单的数据段,为了便于提升变量查询速度,将其存储在栈中,即按值访问。

引用类型也称为复杂类型,由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此,其值存储在堆(heap)中,而存储在变量处的值,是一个指针,指向存储对象的内存处,即按址访问。引用类型除 Object 外,还包括 Function 、Array、RegExp、Date 等等。

1、typeof

返回的结果用该类型的字符串(全小写字母)形式表示,包括以下 7 种:number、boolean、symbol、string、object、undefined、function 等。

1
2
3
4
5
6
7
8
9
10
typeof ''; // string 有效
typeof 1; // number 有效
typeof Symbol(); // symbol 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Function(); // function 有效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效
  • 对于基本类型,除 null 以外,均可以返回正确的结果。
  • 对于引用类型,除 function 以外,一律返回 object 类型。
  • 对于 null ,返回 object 类型。
  • 对于 function 返回 function 类型。

2、instanceof

instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false

instanceof 检测的是原型

1
2
3
4
5
6
7
8
9
10
// 当 A 的 __proto__ 指向 B 的 prototype 时,就认为 A 就是 B 的实例
instanceof (A,B) = {
var L = A.__proto__;
var R = B.prototype;
if(L === R) {
//A的内部属性__proto__指向B的原型对象
return true;
}
return false;
}
1
2
3
4
5
6
7
8
9
10
[] instanceof Array; //true
{} instanceof Object;//true
new Date() instanceof Date;//true
function Person(){};
new Person() instanceof Person;
[] instanceof Object; //true
new Date() instanceof Object;//true
new Person instanceof Object;//true

3、Array.isArray()

ECMAScript 5 新增方法 IE9+、 Firefox 4+、 Safari 5+、 Opera 10.5+和 Chrome

1
2
3
if (Array.isArray(value)){
//对数组执行某些操作
}

4、constructor

当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用

当执行 var f = new F() 时,F 被当成了构造函数,f 是F的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor == F

null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。

5、toString

toString 是 Object 原型对象上的方法,使用 call 来调用该方法会返回调用者的类型字符串,格式为 [object,xxx],xxx 是调用者的数据类型,包括:String、Number、Boolean、Undefined、Null、Function、Date、Array、RegExp、Error、HTMLDocument 等, 基本上,所有的数据类型都可以通过这个方法获

必须通过 call 或 apply 来调用

1
2
3
4
5
6
7
8
9
10
11
12
13
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window是全局对象 global 的引用

数组常用方法

数组常用方法

1、sort( [compareFunction] )

对数组做原地排序,并返回这个数组,默认按照字符串 UNICODE 的码位点排序

1
2
3
4
5
var fruit = ['cherries', 'apples', 'bananas'];
fruit.sort(); // ['apples', 'bananas', 'cherries']
var scores = [1, 10, 2, 21];
scores.sort(); // [1, 10, 2, 21]

以给 sort 传递一个回调函数 compareFunction, 其接收两个参数 a 和 b,分别代表数组中待比较的两个元素,a 元素 排在 b 的前面 。

回调函数需要返回一个表达式,用以标明 升序 或 降序 操作:

  • return a - b :如果表达式 a - b 为真,触发交换操作。也就是说, 当 a > b 时,进行元素交换,让较小的元素 b 排在较大的元素 a 前面,即 升序操作。
  • return b - a :如果表达式 b - a 为真,触发交换操作。也就是说, 当 a < b 时,进行元素交换,让较大的元素 b 排在较小的元素 a 前面,即 降序操作。  
1
2
3
4
5
6
7
8
9
10
11
12
var numbers = [2,4,1,10,3];
// 回调参数 a,b 是数组要比较的两个元素,a 排在 b 的前面。
numbers.sort(function(a,b){
// 当 a > b 时触发交换操作,把较小的排在前面,即升序。
return a - b;
}); //[1,2,3,4,10]
numbers.sort(function(a,b){
// 当 a < b 时触发交换操作,把较大的排在前面,即降序。
return b - a;
}); //[10,4,3,2,1]

2、join( [separator] )

将数组中的所有元素连接成一个字符串。separtor 用于指定连接每个数组元素的分隔符。分隔符会被转成字符串类型;如果省略的话,默认为一个逗号。如果separtor 是一个空字符串,那么数组中的所有元素将被直接连接。

1
2
3
4
5
var data = ['Wind', 'Rain', 'Fire'];
data.join(); //Wind,Rain,Fire
data.join(', '); //Wind, Rain, Fire
data.join(' + '); //Wind + Rain + Fire
data.join(''); //WindRainFire

3、concat( value1,…,valueN )

oncat 方法将创建一个新的数组,然后将调用它的对象(this 指向的对象)中的元素以及所有参数中的数组类型的参数中的元素以及非数组类型的参数本身按照顺序放入这个新数组,并返回该数组, valueN 允许是数组或非数组值。在没有给 concat 传递参数的情况下,它只是复制当前数组并返回副本。

1
2
3
4
5
var alpha = ['a', 'b', 'c'];
alpha.concat(1, [2, 3]); //["a", "b", "c", 1, 2, 3]
alpha.concat(); // ['a', 'b', 'c']

4、push( element1,…,elementN ) 和 pop( )

push 添加一个或多个元素到数组的末尾,并返回数组新的长度;pop删除一个数组中的最后的一个元素,并且返回这个元素

push 和 pop 并不会改变原来的元素位置。

1
2
3
4
5
var data = [1,2,3];
data.push(4,5,6); //6 ->数组的长度 data->[1,2,3,4,5,6]
data.pop(); //6 ->出栈的元素 data->[1,2,3,4,5]

5、unshift( element1,…,elementN ) 和 shift( )

unshift 添加一个或多个元素到数组的开头,并返回数组新的长度;shift 删除一个数组中的第一个元素,并且返回这个元素。

unshift 和 shift 都会改变原来的元素位置。

1
2
3
4
5
var data = [1,2,3];
data.unshift(-1,-2,-3); //6->新数组的长度 data->[-1,-2,-3,1,2,3]
data.shift(); // -1 ->被移除的元素 data->[-2,-3,1,2,3]

如果把数组看成一个栈,push 和 pop 、unshift 和 shift 对数组的操作行为就符合 后进先出 (LIFO) 规律 ;如果把数组看成一个队列,push 和 shift 、unshift 和 pop 对数组的操作行为就符合 先进先出 (FIFO) 规律。

因此,可以使用数组来实现对应的数据结构:队列

6、slice( begin[,end] )

slice 方法从begin 的索引位置开始提取数组元素,到 end 位置结束,但不包括 end 位置的元素,如果 end 被省略,则默认提取到数组的结尾,如果结束位置小于起始位置,则返回空数组。

1
2
3
4
5
var data = [1,2,3];
data.slice(0); //[1,2,3] 提取的元素
data.slice(1,2); //[2] 提取的元素
data.slice(2,1); //[]

如果参数中有一个负数,则用数组长度加上该数来确定相应的位置。例如,在一个包含 5 项的数组上调用 slice(-2,-1) 与调用 slice(3,4) 得到的结果相同。

1
2
3
var t = [1,2,3,4,5];
t.slice(-2,-1); // [4]
t.slice(3,4); // [4]

slice方法会返回一个新的数组,由于数组是引用类型, 通常会通过 arr.slice(0) 来实现数组的 浅拷贝,但这只对 数组元素是基本类型 的情况有效。

1
2
3
4
5
6
//简单数组拷贝
var arr = [1,2,3,4];
var cyarr = arr.slice(0); //浅拷贝
arr.splice(3,1); //对原数组操作
console.log(arr,cyarr); //[1,2,3] , [1,2,3,4] -> 拷贝成功

如果是对象数组,数组元素作为指针指向对象内存,slice(0) 仅仅是拷贝了一份指针作为副本,而副本中的指针,指向的还是原来的对象,因此,对一个数组中的对象做操作,另一个数组中的对象也会同步变化。

1
2
3
4
5
6
//对象数组拷贝
var list = [{name:'zhangsan'}];
var cylist = list.slice(0); //浅拷贝
list[0].name = 'lisi'; //对原数组操作
console.log(list,cylist); // [{name:'lisi'}] , [{name:'lisi'}] -> 拷贝失败

要实现数组的深拷贝,需要通过 JSON 的序列化和反序列化来实现,即: JSON.parse( JSON.stringify(arr) )

1
2
3
4
5
6
//对象数组拷贝
var list = [{name:'zhangsan'}];
var cylist = JSON.parse(JSON.stringify(list)); //深拷贝
list[0].name = 'lisi'; //对原数组操作
console.log(list,cylist); // [{name:'lisi'}] , [{name:'zhangsan'}] -> 拷贝成功

7、splice( start, deleteCount[,value1,…,valueN] )

splice方法从一个数组中移除一个或多个元素,如果必要,在所移除元素的位置上插入新元素,返回所移除的元素。

1
2
3
data.splice(2,1);//[3]->被删除的元素 data->[1,2]
data.splice(2,2,4,5); //[3]->被删除的元素 data->[1,2,4,5]
data.splice(2,2,4,5,6); //[3]->被删除的元素 data->[1,2,4,5,6]

indexOf 和 lastIndexOf

数组的遍历

数组的遍历

1、forEach( callback[,thisArg] )

forEach 需要传递2个参数,第一个参数是回调函数,是必选参数,第二个参数是一个对象,用来改变callback中的this指向,是可选参数

1
2
3
4
5
6
7
8
var arr = ['a','b','c'];
arr.forEach(function(v,i,r){
console.log(v,i,r);
})
->
a 0 ["a", "b", "c"]
b 1 ["a", "b", "c"]
c 2 ["a", "b", "c"]

callback 中传入了3个参数 v,i,r 分别表示当前元素、当前位置、数组对象。再看看使用 thisArg 的例子:

1
2
3
4
5
6
7
8
9
var obj = {
print:function(a,b){
console.log(a,b);
}
};
var arr = ['a','b','c'];
arr.forEach(function(v,i,a){
this.print(v,i);
},obj);

不传 thisArgs 时,callback中的 this 默认指向 window 对象,当传递 thisArg 时,callback 中的 this 就指向了thisArg,因此这个参数的目的就是为了改变回调函数中的this指向。

对于不支持 ES5 的浏览器,我们可以对 forEach 进行简单的扩展来兼容老的浏览器:

1
2
3
4
5
6
7
8
if(!Array.prototype.forEach){
Array.prototype.forEach = function(callback,thisArg){
for (var i=0;i<this.length;i++){
//当thisArg为undefined时,JS引擎会将window作为其调用者
callback.call(thisArg,this[i],i,this.toString());
}
}
}

2、filter( callback[,thisArg] )

filter 是过滤的意思,所以这个方法的作用就是返回一个匹配过滤条件的新数组,其接收两个参数 callback 和 thisArg, callback 也是回调函数,主要用于对元素进行条件匹配,thisArg 和 forEach 中的 thisArg 作用一样,在这里就不重复了,看下面示例:

1
2
3
4
5
6
var arr = ["a","b","a","c"];
var newArr = arr.filter(function(item){
return item === "a";
});
newArr -> ["a","a"]

没有filter的时候,要实现这个功能,我们事先要创建一个空的数组,把匹配到的元素再 push 进去,对filter的扩展:

1
2
3
4
5
6
7
8
9
10
11
12
if(!Array.prototype.filter) {
Array.prototype.filter = function (callback, thisArg) {
var temp = [];
for (var i = 0; i < this.length; i++) {
if(callback.call(thisArg,this[i])){
//如果callback返回true,则该元素符合过滤条件,将元素压入temp中
temp.push(this[i]);
}
}
return temp;
}
}

3、map( callback[,thisArg] )

map 的作用是对原数组进行加工处理后并将其作为一个新数组返回,该方法同样接收两个参数,callback 是回调函数用于对数组进行加工处理

1
2
3
4
5
6
7
8
9
10
11
ar arr = [
{w:10,h:10}, //定义长和宽
{w:15,h:20},
{w:12,h:12}
];
var newArr = arr.map(function(item){
//根据长宽计算出面积并赋值给新属性area
item.area = item.w * item.h;
return item;
});
newArr[0] - > {w: 10, h: 10, area: 100}

map 进行兼容性扩展

1
2
3
4
5
6
7
8
9
10
if(!Array.prototype.map) {
Array.prototype.map = function (callback, thisArg) {
var temp = [];
for (var i = 0; i < this.length; i++) {
var newItem = callback.call(thisArg,this[i]);
temp.push(newItem); //将callback返回的新元素压入temp中
}
return temp;
}
}

4、reduce ( callback[,initialValue] )

reduce 在这里有减少的意思,其作用是对数组进行归并操作,换句话说就是对数组每一个元素进行累加,最终返回所有元素之和。 回调函数 callback 接收4个参数:

  • previousValue - 存放的是上一次callback返回的结果,其初始值默认为数组的第一个元素。
  • currentValue - 是当前元素 。默认从数组的第二个元素开始。
  • currentIndex - 是当前元素位置 。
  • array - 是当前数组。
1
2
3
4
5
6
7
8
9
10
11
var arr = [1,2,3,4];
var newArr = arr.reduce(function(previousValue, currentValue, currentIndex, array){
console.log(previousValue, currentValue,currentIndex);
return previousValue + currentValue;
});
1 2 1
3 3 2
6 4 3
newArr -> 10

reduce 除过可以传递 callback 之外,还可以传递一个参数 initialValue ,作为数组累加的基数。当传了这个参数以后,callback 中的 previousValue 初始值就被置为 initialValue,reduce 也改为从数组的第一个元素开始遍历。

1
2
3
4
5
6
7
8
9
10
11
12
var arr = [1,2,3,4];
var newArr = arr.reduce(function(previousValue, currentValue, currentIndex, array){
console.log(previousValue, currentValue,currentIndex);
return previousValue + currentValue;
},100);
100 1 0
101 2 1
103 3 2
106 4 3
newArr -> 110

从结果可以看出,reduce 最终返回的是: previousValue + 数组本身归并计算的结果。对 reduce 的 polyfill 实现如下:

1
2
3
4
5
6
7
8
9
10
11
if(!Array.prototype.reduce) {
Array.prototype.reduce = function (callback, initialValue) {
var previousValue = initialValue || this[0];//如果不指定intialValue,则默认为数组的第一个元素
//如果不指定initialValue,i从1开始遍历,否则就从0开始遍历
for (var i = initialValue?0:1; i < this.length; i++) {
//previousValue 累加每一次返回的结果
previousValue = callback(previousValue, this[i],i,this.toString());
}
return previousValue;
}
}

5、reduceRight ( callback[,initialValue] )

和 reduce 的作用完全相同,唯一的不同是,reduceRight 是从右至左遍历数组的元素。

6、some ( callback[,thisArg] )

some 是某些、一些的意思,其作用是对数组中的每一项执行回调函数,如果该函数对任一项返回 true,则停止遍历,并返回 true 。

1
2
3
4
5
6
7
8
9
10
11
var arr = [ 1, 2, 3, 4];
var result = arr.some( function( item, index, array ){
console.log( item, index, array);
return item > 2;
});
->
1 0 [1, 2, 3, 4]
2 1 [1, 2, 3, 4]
3 2 [1, 2, 3, 4]
restule -> true

some 检测整个数组,只要当arr中有一个元素符合条件 item>2 就停止检测和遍历,并返回 true,以表示检测到目标。这和我们在 for 循环中使用 break 语言的作用有点类似。 对于 some 的兼容性扩展如下:

1
2
3
4
5
6
7
8
9
10
11
if(!Array.prototype.some) {
Array.prototype.some = function (callback, thisArg) {
for (var i = 0; i < this.length; i++) {
if(callback.call(thisArg,this[i],i,this.toString())){
return true; //检测到callback返回true,跳出循环,并返回true
}
}
return false; //一个符合条件的都没有检测到,返回false
}
}

7、every (callback[,thisArg])

every 是每一个的意思,其作用是对数组中的每一项执行回调函数,如果该函数对每一项都返回 true,则返回 true 。

1
2
3
4
5
6
7
8
9
10
11
var arr = [ 1, 2, 3, 4];
var result = arr.every( function( item, index, array ){
console.log( item, index, array );
return item < 3;
});
1 0 [1, 2, 3, 4]
2 1 [1, 2, 3, 4]
3 2 [1, 2, 3, 4]
result -> false

当检测第3个元素时,item<3 为 false,停止检测,并返回 false,这说明every在检测元素时,要求每一个元素都要符合条件 item<3,如果有一个不符合就停止检测,并返回false。(你可以测试 item<5 时的运行结果,返回值一定是 true ) 。

那 every 到底有什么作用呢? 当一个 for 循环使用了 break 语句后,我们想知道 for 循环是否正常的执行完时, 我们一般会通过检测for中的索引 i==arr.length 来判断,因此every 的作用就体现在这里。

下面是对于 every 的兼容性扩展:

1
2
3
4
5
6
7
8
9
10
11
if(!Array.prototype.every) {
Array.prototype.every = function (callback, thisArg) {
for (var i = 0; i < this.length; i++) {
if(!callback.call(thisArg,this[i],i,this.toString())){
return false; //检测到不符合条件的元素,跳出循环,并返回false
}
}
return true; //所有元素都符合条件,返回true
}
}

正则

正则

1、正则表达式结构

1
var expression = / pattern / flags ;

每个正则表达式都可带有一或多个标志(flags),用以标明正则表达式的行为,正则表达式支持下列 3 个标志:

  • g: 表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止;
  • i : 表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写;
  • m:表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。

如果多个标志同时使用时,则写成:gmi 。

正则表达式的创建

new RegExp(expression)

1
var exp2 = new RegExp("(^\\s+)|(\\s+$)","g");

直接字面量

1
var exp1 = /(^\s+)|(\s+$)/g;

模式中使用的所有元字符都必须转义。正则表达式中的元字符包括:

1
2
3
4
5
6
7
8
9
10
11
( [ { \ ^ $ | ) ? * + .] }
//匹配 .docx
var exp = /\.docx/gi ;
// 对 \. 再次转义
var exp = new RegExp("\\.docx","gi");
//匹配 \n
var exp1 = /\\n/g; //对\n中的\转义
var exp2 = new RegExp("\\\\n","g"); // 对 \\n 再次转义

2、() [] {} 的区别

() 的作用是提取匹配的字符串。表达式中有几个()就会得到几个相应的匹配字符串。比如 (\s+) 表示连续空格的字符串。

[] 是定义匹配的字符范围。比如 [a-zA-Z0-9] 表示字符文本要匹配英文字符和数字。

{} 一般用来表示匹配的长度,比如 \d{3} 表示匹配三个数字,\d{1,3} 表示匹配1~3个数字,\d{3,} 表示匹配3个以上数字。

3、^ 和 $

^ 匹配一个字符串的开头,比如 (^a) 就是匹配以字母a开头的字符串

$匹配一个字符串的结尾,比如 (b$) 就是匹配以字母b结尾的字符串

^ 还有另个一个作用就是取反,比如[^xyz] 表示匹配的字符串不包含xyz

注意问题:

  • 如果^出现在[ ]中一般表示取反,而出现在其他地方则是匹配字符串的开头。
  • ^$ 配合可以有效匹配完整字符串: /d+/.test(‘4xpt’) -> true,而 /^\d+$/.test(‘4xpt’)->false

4、\d \s \w .

\d 匹配一个非负整数, 等价于 [0-9]

\s 匹配一个空白字符

\w 匹配一个英文字母或数字,等价于[0-9a-zA-Z]

. 匹配除换行符以外的任意字符,等价于[^\n]

5、\ + ?

* 表示匹配前面元素0次或多次,比如 (\s*) 就是匹配0个或多个空格

  • 表示匹配前面元素1次或多次,比如 (\d+) 就是匹配由至少1个整数组成的字符串

? 表示匹配前面元素0次或1次,相当于{0,1} ,比如(\w?) 就是匹配最多由1个字母或数字组成的字符串

6、$1 和 \1

$1-$9 存放着正则表达式中最近的9个正则表达式的提取的结果,这些结果按照子匹配的出现顺序依次排列。基本语法是:RegExp.$n ,这些属性是静态的,除了replace中的第二个参数可以省略 RegExp 之外,其他地方使用都要加上 RegExp 。

1
2
3
4
5
6
7
8
9
10
//使用RegExp访问
//(\d+)-(\d+)-(\d+)/.test("2016-03-26")
RegExp.$1 // 2016
RegExp.$2 // 03
RegExp.$3 // 26
//在replace中使用
"2016-03-26".replace(/(\d+)-(\d+)-(\d+)/,"$1年$2月$3日")
// 2016年03月26日

\1 表示后向引用,是指在正则表达式中,从左往右数,第1个()中的内容,以此类推,\2表示第2个(),\0表示整个表达式。

1
2
3
4
5
6
//匹配日期格式,表达式中的\1代表重复(\-|\/|.)
var rgx = /\d{4}(\-|\/|.)\d{1,2}\1\d{1,2}"/
rgx.test("2016-03-26") //true
rgx.test("2016-03.26") //false

两者的区别是:\n只能用在表达式中,而$n只能用在表达式之外的地方。

7、test 和 match

test则是用来检测字符串是否匹配某一个正则表达式,如果匹配就会返回true,反之则返回false

1
2
3
/\d+/.test("123") ; //true
/\d+/.test("abc") ; //false

match是获取正则匹配到的结果,以数组的形式返回

1
"186a619b28".match(/\d+/g); // ["186","619","28"]

8、replace

replace 本身是JavaScript字符串对象的一个方法,它允许接收两个参数:

1
replace([RegExp|String],[String|Function])

第1个参数可以是一个普通的字符串或是一个正则表达式

第2个参数可以是一个普通的字符串或是一个回调函数

如果第1个参数是 RegExp,JS会先提取RegExp匹配出的结果,然后用第2个参数逐一替换匹配出的结果

如果第2个参数是回调函数,每匹配到一个结果就回调一次,每次回调都会传递以下参数:

1
2
3
4
5
6
7
result: 本次匹配到的结果
$1,...$9: 正则表达式中有几个(),就会传递几个参数,$1~$9分别代表本次匹配中每个()提取的结果,最多9
offset:记录本次匹配的开始位置
source:接受匹配的原始字符串

正则案例

正则案例

实现字符串的 trim 函数,去除字符串两边的空格

1
2
3
4
5
6
7
8
9
10
String.prototype.trim = function(){
//方式一:将匹配到的每一个结果都用""替换
return this.replace(/(^\s+)|(\s+$)/g,function(){
return "";
});
//方式二:和方式一的原理相同
return this.replace(/(^\s+)|(\s+$)/g,'');
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ^\s+ 表示以空格开头的连续空白字符,\s+$ 表示以空格结尾的连续空白字符,加上() 就是将匹配到的结果提取出来,由于是 | 的关系,因此这个表达式最多会match到两个结果集,然后执行两次替换
String.prototype.trim = function(){
/**
* @param rs:匹配结果
* @param $1:第1个()提取结果
* @param $2:第2个()提取结果
* @param offset:匹配开始位置
* @param source:原始字符串
*/
this.replace(/(^\s+)|(\s+$)/g,function(rs,$1,$2,offset,source){
//arguments中的每个元素对应一个参数
console.log(arguments);
});
};
" abcd ".trim();
输出结果:
[" ", " ", undefined, 0, " abcd "] //第1次匹配结果
[" ", undefined, " ", 5, " abcd "] //第2次匹配结果

提取浏览器 url 中的参数名和参数值,生成一个key/value 的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
/([^&=]+)=([^&=]*)/gi 每次匹配到的都是一个完整key/value,形如 xxxx=xxx, 每当匹配到一个这样的结果时就执行回调,并传递匹配到的key和value,对应到$1和$2 。
function getUrlParamObj(){
var obj = {};
//获取url的参数部分
var params = window.location.search.substr(1);
//[^&=]+ 表示不含&或=的连续字符,加上()就是提取对应字符串
params.replace(/([^&=]+)=([^&=]*)/gi,function(rs,$1,$2){
obj[$1] = decodeURIComponent($2);
});
return obj;
}

在字符串指定位置插入新字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
// 当offset=2时,正则表达式为:(^.{3}) .表示除\n之外的任意字符,{3} 表示匹配前三个连续字符,加()就会将匹配到的结果提取出来,然后通过replace将匹配到的结果替换为新的字符串,形如:结果=结果+str
String.prototype.insetAt = function(str,offset){
offset = offset + 1;
//使用RegExp()构造函数创建正则表达式
var regx = new RegExp("(^.{"+offset+"})");
return this.replace(regx,"$1"+str);
};
"abcd".insetAt('xyz',2); //在c字符后插入xyz
>> "abcxyzd"

将手机号12988886666转化成129**6666

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// (\d{3}\d{4}\d{4}) 可以匹配完整的手机号,并分别提取前3位、4-7位和8-11位,"$1****$3" 是将第2个匹配结果用****代替并组成新的字符串,然后替换完整的手机号。
function telFormat(tel){
tel = String(tel);
//方式一
return tel.replace(/(\d{3})(\d{4})(\d{4})/,function (rs,$1,$2,$3){
return $1+"****"+$3
});
//方式二
return tel.replace(/(\d{3})(\d{4})(\d{4})/,"$1****$3");
}

实现HTML编码,将< / > “ & ` 等字符进行转义,避免XSS攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function htmlEncode(str) {
//匹配< / > " & `
return str.replace(/[<>"&\/`]/g, function(rs) {
switch (rs) {
case "<":
return "<";
case ">":
return ">";
case "&":
return "&";
case "\"":
return """;
case "/":
return "/"
case "`":
return "'"
}
});
}

H5播放器

H5播放器

Media.duration

视频的总时长

Media.pause()

暂停

Media.play()

播放

Media.webkitRequestFullScreen()

全屏

Media.ontimeupdate

视频播放触发事件

oninput

进度条触发事件

flex布局

flex布局

Flex 是 Flexible Box 的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。

任何一个容器都可以指定为 Flex 布局。

1
2
3
.box{
display: flex;
}

Webkit 内核的浏览器,必须加上-webkit前缀。

1
2
3
4
.box{
display: -webkit-flex; /* Safari */
display: flex;
}

注意,设为 Flex 布局以后,子元素的floatclearvertical-align属性将失效。

概念

采用 Flex 布局的元素,称为 Flex 容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称”项目”。

容器的属性

flex-direction属性

flex-direction属性决定主轴的方向(即项目的排列方向)

  • row(默认值):主轴为水平方向,起点在左端。
  • row-reverse:主轴为水平方向,起点在右端。
  • column:主轴为垂直方向,起点在上沿。
  • column-reverse:主轴为垂直方向,起点在下沿。
1
2
3
.box {
flex-direction: row | row-reverse | column | column-reverse;
}

flex-wrap属性

(1)nowrap(默认):不换行

(2)wrap:换行,第一行在上方。

(3)wrap-reverse:换行,第一行在下方。

默认情况下,项目都排在一条线(又称”轴线”)上。flex-wrap属性定义,如果一条轴线排不下,如何换行。

1
2
3
.box{
flex-wrap: nowrap | wrap | wrap-reverse;
}

flex-flow

flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

1
2
3
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}

justify-content属性

justify-content属性定义了项目在主轴上的对齐方式。

  • flex-start(默认值):左对齐
  • flex-end:右对齐
  • center: 居中
  • space-between:两端对齐,项目之间的间隔都相等。
  • space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
1
2
3
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}

align-items属性

align-items属性定义项目在交叉轴上如何对齐。

  • flex-start:交叉轴的起点对齐。
  • flex-end:交叉轴的终点对齐。
  • center:交叉轴的中点对齐。
  • baseline: 项目的第一行文字的基线对齐。
  • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
1
2
3
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}

align-content属性

align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

  • flex-start:与交叉轴的起点对齐。
  • flex-end:与交叉轴的终点对齐。
  • center:与交叉轴的中点对齐。
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch(默认值):轴线占满整个交叉轴。
1
2
3
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

项目的属性

order属性

order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

1
2
3
.item {
order: <integer>;
}

flex-grow属性

flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

1
2
3
.item {
flex-grow: <number>; /* default 0 */
}

flex-shrink属性

flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

负值对该属性无效。

1
2
3
.item {
flex-shrink: <number>; /* default 1 */
}

flex-basis属性

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

它可以设为跟widthheight属性一样的值(比如350px),则项目将占据固定空间。

1
2
3
4
.item {
flex-basis: <length> | auto; /* default auto */
}

flex属性

flex属性是flex-grow, flex-shrinkflex-basis的简写,默认值为0 1 auto。后两个属性可选。

该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。

1
2
3
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

align-self属性

align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch

该属性可能取6个值,除了auto,其他都与align-items属性完全一致。

1
2
3
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}