Siker

Pigs might fly!


  • 首页

  • 标签

  • 分类

  • 归档

jQuery中的extend()方法

发表于 2017-11-14 | 分类于 jQuery

通常我们使用jQuery的extend时,大都是为了实现默认字段的覆盖,即若传入某个字段的值,则使用传入值,否则使用默认值。如下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
function getOpt(option){
var _default = {
name : 'wenzi',
age : '25',
sex : 'male'
}
$.extend(_default, option);
return _default;
}
getOpt(); // {name: "wenzi", age: "25", sex: "male"}
getOpt({name:'bing'}); // {name: "bing", age: "25", sex: "male"}
getOpt({name:'bing', age:36, sex:'female'}); // {name: "bing", age: 36, sex: "female"}

那现在我们就得需要知道这个extend具体是怎么实现的了,除了实现上面的功能,还有其他作用么?那肯定是有的啦,否则我也不会问那句话了((⊙﹏⊙)b)。我们先来看看extend主要有哪些功能,然后再看实现这些功能的原理。

1. extend能实现的功能

其实从extend的含义里,我们就能知道extend是做什么的了。extend翻译成汉语后就是:延伸、扩展、推广。

####1.1 将两个或更多对象的内容合并到第一个对象

我们来看看$.extend()提供的参数:jQuery.extend( target [, object1 ] [, objectN ] ),extend方法需要至少传入一个参数,第一个必需,后面的都是可选参数。若传给extend是两个或两个以上的参数都是对象类型,那么就会把后面所有对象的内容合并给target(第一个对象)上。

我们再来看看上面的例子:

1
2
3
4
5
6
7
8
9
function getOpt(option){
var _default = {
name : 'wenzi',
age : '25',
sex : 'male'
}
`$.extend(_default, option);`
return _default;
}

$.extend()中接收了两个参数_default和option,那么extend方法执行时,就会把option对象上字段的值全给了_default。于是_default上设置的默认值就会被option上的值覆盖。当然,若option上没有这个字段,就不会覆盖_default上字段的值。

上面函数中的extend,只是传入了两个参数,那传的参数再更多一些呢:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function getOpt(target, obj1, obj2, obj3){
$.extend(target, obj1, obj2, obj3);
return target;
}
var _default = {
name : 'wenzi',
age : '25',
sex : 'male'
}
var obj1 = {
name : 'obj1'
}
var obj2 = {
name : 'obj2',
age : '36'
}
var obj3 = {
age : '67',
sex : {'error':'sorry, I dont\'t kown'}
}
getOpt(_default, obj1, obj2, obj3); // {name: "obj2", age: "67", sex: {error: "sorry, I dont't kown"}}

这里我们传入了4个参数,然后getOpt()返回第一个参数的值。从运行的得到结果我们可以看到,属性值永远是最后一个属性的值。

还有很重要的一点,$.extend()其实是有返回值的,返回的就是修改后的第一个参数的值。如我们可以把上面的函数修改成这样:

1
2
3
4
function getOpt(target, obj1, obj2, obj3){
var result = $.extend(target, obj1, obj2, obj3);
return result; // // result即修改后的target值
}

若我们传入的参数不想被修改,我们可以用一个空对象来作为第一个参数,然后获取$.extend()的返回值:

1
2
3
4
function getOpt(target, obj1, obj2, obj3){
var result = $.extend({}, target, obj1, obj2, obj3);
return result; // // result即为{}修改后的值
}

1.2 为jQuery扩展方法或属性

刚才我们在1.1中讲的$.extend()的例子都是传了两个或两个以上的参数,但其实只有一个参数是必须的。若只传一个参数会怎样呢。

如果只有一个参数提供给$.extend(),这意味着目标参数被省略。在这种情况下,jQuery对象本身被默认为目标对象。这样,我们可以在jQuery的命名空间下添加新的功能。这对于插件开发者希望向 jQuery 中添加新函数时是很有用的。

1
2
3
4
5
6
7
8
9
$.extend({
_name : 'wenzi',
_getName : function(){
return this._name;
}
})
$._name; // wenzi
$._getName(); // wenzi

这样我们就为jQuery扩展了_name属性和_getName方法。

1.3 深度拷贝和浅度拷贝

针对什么是深度拷贝,什么是浅度拷贝,我们先来看一个简单的例子。

1
2
3
4
var obj = {name:'wenzi', sex:'male'};
var obj1 = obj; // 赋值
obj1.name = 'bing';
console.log(obj.name); // bing

我们修改了obj1中的name值,结果obj中的值也跟着发生了变化,这是为什么呢。其实这就是浅度拷贝:这仅仅是将obj对象的引用地址简单的复制了一份给予变量 obj1,而并不是将真正的对象克隆了一份,因此obj和obj1指向的都是同一个地址。当修改obj1的属性或给obj1添加新属性时,obj都会受到影响。

可是如果变量的值不是对象和数组,修改后面的变量是不会影响到前面的变量:

1
2
3
4
var s = 'hello';
var t = s;
t = 'world';
console.log(s); // hello

那么深度拷贝就不是拷贝引用地址,而是实实在在的复制一份新对象给新的变量。 在上面使用$.extend()中,都是使用的浅度拷贝,因此若后面的参数值是object类型或array类型,修改_default(target)的值,就会影响后面参数的值。

如我们使用getOpt(_default, obj1, obj2, obj3);得到的_default值是{name: “obj2”, age: “67”, sex: {error: “sorry, I dont’t kown”}},可是若:
_default.sex.error = 'hello world';
那么obj3.sex.error也会跟着修改,因为obj3.sex是一个object类型。

不过$.extend()也提供了深度拷贝的方法:jQuery.extend( [deep ], target, object1 [, objectN ] )。若第一个参数是boolean类型,且值是true,那么就会把第二个参数作为目标参数进行合并。

1
2
3
4
5
6
var obj = {name:'wenzi', score:80};
var obj1 = {score:{english:80, math:90}}
$.extend(true, obj, obj1);
obj.score.english = 10;
console.log(obj.score.english); // 10
console.log(obj1.score.english); // 80

执行后我们发现,无论怎么修改obj.score里的值,都不会影响到obj1.score了。

2. jQuery中extend实现原理

其实不看源码,对extend大致的过程应该也是了解的:对后一个参数进行循环,然后把后面参数上所有的字段都给了第一个字段,若第一个参数里有相同的字段,则进行覆盖操作,否则就添加一个新的字段。

下面是jQuery中关于extend的源码,我就在源码上进行注释讲解了,随后再在后面进行总结:

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// 为与源码的下标对应上,我们把第一个参数称为`第0个参数`,依次类推
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {}, // 默认第0个参数为目标参数
i = 1, // i表示从第几个参数凯斯想目标参数进行合并,默认从第1个参数开始向第0个参数进行合并
length = arguments.length,
deep = false; // 默认为浅度拷贝
// 判断第0个参数的类型,若第0个参数是boolean类型,则获取其为true还是false
// 同时将第1个参数作为目标参数,i从当前目标参数的下一个
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// 判断目标参数的类型,若目标参数既不是object类型,也不是function类型,则为目标参数重新赋值
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// 若目标参数后面没有参数了,如$.extend({_name:'wenzi'}), $.extend(true, {_name:'wenzi'})
// 则目标参数即为jQuery本身,而target表示的参数不再为目标参数
// Extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
// 从第i个参数开始
for ( ; i < length; i++ ) {
// 获取第i个参数,且该参数不为null和undefind,在js中null和undefined,如果不区分类型,是相等的,null==undefined为true,
// 因此可以用null来同时过滤掉null和undefind
// 比如$.extend(target, {}, null);中的第2个参数null是不参与合并的
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// 使用for~in获取该参数中所有的字段
// Extend the base object
for ( name in options ) {
src = target[ name ]; // 目标参数中name字段的值
copy = options[ name ]; // 当前参数中name字段的值
// 若参数中字段的值就是目标参数,停止赋值,进行下一个字段的赋值
// 这是为了防止无限的循环嵌套,我们把这个称为,在下面进行比较详细的讲解
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// 若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进行深度赋值
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
// 若当前参数中name字段的值为Array类型
// 判断目标参数中name字段的值是否存在,若存在则使用原来的,否则进行初始化
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
// 若原对象存在,则直接进行使用,而不是创建
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// 递归处理,此处为2.2
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// deep为false,则表示浅度拷贝,直接进行赋值
// 若copy是简单的类型且存在值,则直接进行赋值
// Don't bring in undefined values
} else if ( copy !== undefined ) {
// 若原对象存在name属性,则直接覆盖掉;若不存在,则创建新的属性
target[ name ] = copy;
}
}
}
}
// 返回修改后的目标参数
// Return the modified object
return target;
};

源码分析完了,下面我们来讲解下源码中存在的几个难点和重点。

2.1 若参数中字段的值就是目标参数,停止赋值

在源码中进行了一下这样的判断:

1
2
3
4
// Prevent never-ending loop
if ( target === copy ) {
continue;
}

为什么要有这样的判断,我们来看一个简单的例子,如果没有这个判断会怎么样:

1
2
3
4
var _default = {name : 'wenzi'};
var obj = {name : _default}
$.extend(_default, obj);
console.log(_default);

输出的_default是什么呢:

1
_default = {name : _default};

_default是object类型,里面有个字段name,值是_default,而_default是object类型,里面有个字段name,值是_default……,无限的循环下去。于是jQuery中直接不进行操作,跳过这个字段,进行下一个字段的操作。

2.2 深度拷贝时进行递归处理

我们在前面稍微的讲解了一下,变量值为简单类型(如number, string, boolean)进行赋值时是不会影响上一个变量的值的,因此,如果当前字段的值为Object或Array类型,需要对其进行拆分,直到字段的值为简单类型(如number, string, boolean)时才进行赋值操作

3. $.extend()与$.fn.extend()

上面讲解的全都是$.extend(),根本就没讲$.fn.extend()。可是,你有没有发现一个细节,在这段代码的第一行是怎么写的:

1
jQuery.extend = jQuery.fn.extend = function(){}

也就是说$.extend()与$.fn.extend()共用的是同一个函数体,所有的操作都是一样的,只不过两个extend使用的对象不同罢了:$.extend()是在jQuery上进行操作的;而$.fn.extend()是在jQuery对象上进行操作的,如$(‘div’).extend().

4. 总结

这就是jQuery中extend的实现,以后若我们需要用到上面的功能时,除了使用$.extend(),我们也可以在不引入jQuery框架的情况下,自己写一个简单的extend()来实现上面的功能。

原文链接:https://www.cnblogs.com/MnCu8261/p/6039986.html

js数组对象排序

发表于 2017-11-14

一、普通数组排序  

js中用方法sort()为数组排序。sort()方法有一个可选参数,是用来确定元素顺序的函数。如果这个参数被省略,那么数组中的元素将按照ASCII字符顺序进行排序。如:

1
2
3
var arr = ["a", "b", "A", "B"];
arr.sort();
console.log(arr);//["A", "B", "a", "b"]

因为字母A、B的ASCII值分别为65、66,而a、b的值分别为97、98,所以上面输出的结果是 ["A", "B", "a", "b"] 。

如果数组元素是数字呢,结果会是怎样?

1
2
3
var arr = [15, 8, 25, 3];
arr.sort();
console.log(arr);//[15, 25, 3, 8]

结果是 [15, 25, 3, 8] 。其实,sort方法会调用每个数组项的toString()方法,得到字符串,然后再对得到的字符串进行排序。虽然数值15比3大,但在进行字符串比较时”15”则排在”3”前面。显然,这种结果不是我们想要的,这时,sort()方法的参数就起到了作用,我们把这个参数叫做比较函数。

比较函数接收两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相等则返回0,如果第一个参数应该位于第二个之后则返回一个正数。例子:

1
2
3
4
5
6
7
8
9
10
11
var arr = [23, 9, 4, 78, 3];
var compare = function (x, y) {//比较函数
if (x < y) {
return -1;
} else if (x > y) {
return 1;
} else {
return 0;
}
}
console.log(arr.sort(compare));

结果为 [3, 4, 9, 23, 78] ,返回了我们想要的结果。如果要按降序排序,比较函数写成这样即可:

1
2
3
4
5
6
7
8
9
var compare = function (x, y) {
if (x < y) {
return 1;
} else if (x > y) {
return -1;
} else {
return 0;
}
}

我们并不能用比较函数比较一个不能转化为数字的字符串与数字的顺序:

1
2
var arr = ["b", 5];
console.log(arr.sort(compare))

结果是 ["b", 5] 。因为比较函数在比较时,会把先把字符串转化为数字,然后再比较,字符串b不能转化为数字,所以就不能比较大小。然而,当不用比较函数时,会比较ASCII值,所以结果是 [5, "b"] 。

二、数组对象排序

如果数组项是对象,我们需要根据数组项的某个属性对数组进行排序,要怎么办呢?其实和前面的比较函数也差不多:

1
2
3
4
5
6
7
8
9
10
11
12
13
var arr = [{name: "zlw", age: 24}, {name: "wlz", age: 25}];
var compare = function (obj1, obj2) {
var val1 = obj1.name;
var val2 = obj2.name;
if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}
console.log(arr.sort(compare));

输出结果为 [Object { name="wlz", age=25}, Object { name="zlw", age=24}] ,可以看到数组已经按照 name 属性进行了排序。我们可以对上面的比较函数再改造一下:

1
2
3
4
5
6
7
8
9
10
11
12
var compare = function (prop) {
return function (obj1, obj2) {
var val1 = obj1[prop];
var val2 = obj2[prop];if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}
}

如果想按照 age 进行排序, ``arr.sort(compare(“age”)) 即可。

但是对age属性进行排序时需要注意了,如果age属性的值是数字,那么排序结果会是我们想要的。但很多时候我们从服务器传回来的数据中,属性值通常是字符串。现在我把上面的数组改为:

1
var arr = [{name: "zlw", age: "24"}, {name: "wlz", age: "5"}];

可以看到,我把 age 属性由数字改为了字符串,第二个数组项的 age 值改为了 “5” 。再次调用 arr.sort(compare("age")) 后,结果为:

1
[Object { name="zlw", age="24"}, Object { name="wlz", age="5"}]

我们的期望是5排在25前面,但是结果不是。这是因为当两个数字字符串比较大小时,会比较它们的ASCII值大小,比较规则是:从第一个字符开始,顺次向后直到出现不同的字符为止,然后以第一个不同的字符的ASCII值确定大小。所以”24”与”5”比较大小时,先比较”2“与”5”的ASCII值,显然”2“的ASCII值比”5”小,即确定排序顺序。

现在,我们需要对比较函数再做一些修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var compare = function (prop) {
return function (obj1, obj2) {
var val1 = obj1[prop];
var val2 = obj2[prop];
if (!isNaN(Number(val1)) && !isNaN(Number(val2))) {
val1 = Number(val1);
val2 = Number(val2);
}
if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}
}

在比较函数中,先把比较属性值转化为数字 Number(val1) 再通过 !isNaN(Number(val1)) 判断转化后的值是不是数字(有可能是NaN),转化后的值如果是数字,则比较转换后的值,这样就可以得到我们想要的结果了, 调用 arr.sort(compare("age")) 得到:

1
[Object { name="wlz", age="5"}, Object { name="zlw", age="24"}]

可以看到,确实是按正确的方式排序了。

原文链接:https://www.cnblogs.com/xljzlw/p/3694861.html

js知识碎片-历史管理

发表于 2017-11-10 | 分类于 js

Math

Math 是一个内置对象, 它具有数学常数和函数的属性和方法。不是一个函数对象。(参考)

Math.ceil()执行向上舍入,即它总是将数值向上舍入为最接近的整数;

Math.floor()执行向下舍入,即它总是将数值向下舍入为最接近的整数;

Math.round()执行标准舍入,即它总是将数值四舍五入为最接近的整数(这也是我们在数学课上学到的舍入规则)。

Math.random() 函数返回一个浮点, 伪随机数在范围[0,1),也就是说,从0(包括0)往上,但是不包括1(排除1),然后您可以缩放到所需的范围。
得到一个两数之间的随机数

1
2
3
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}

得到一个两数之间的随机整数

1
2
3
4
5
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive
}

得到一个两数之间的随机整数,包括两个数在内

1
2
3
4
5
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive
}

window.location

window.location 只读属性,返回一个 Location 对象,其中包含有关文档当前位置的信息。(参考)

window.location.reload(true)
强制从服务器重新加载当前页面

window.location.hash
可以用来获取或设置页面的标签值

window.onhashchange

当 一个窗口的哈希改变时就会触发 hashchange 事件
语法:window.onhashchange = funcRef;或者:<body onhashchange="funcRef();">覆盖任何现有的事件处理程序。
为了将一个事件侦听器添加到现有的一个事件处理程序集中,使用函数 “addEventListener”。
window.addEventListener("hashchange", funcRef, false);

history

pushState: 三个参数: 数据 标题(没实现) 地址(可选)
popstate事件: 读取数据event.state
注意:网址是虚假的,需要在服务器指定对应页面,不然刷新找不到页面

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
var obj = {};
$("#btn").click(function () {
var number = randomNumber(35, 7);
var oRD = Math.random(); //随机数作为obj的键值
obj[oRD] = number; // number 存入obj
$("div").text(number);
window.location.hash = oRD;
//history.pushState(number,'');
});
// window.onpopstate = function (ev) {
// var number = ev.state || '';
// $("div").text(number);
// }
/**
* 将hash插入div
*/
function hashNumber() {
var _number = location.hash;
$("div").text(obj[_number.substring(1)] || '');
}
window.addEventListener("hashchange", hashNumber,false);
/**
*
* @param total
* @param now
* @returns {Array}
*/
function randomNumber(total, now) {
var arr = [];
var newArr = [];
for (var i = 1; i<= total; i++) {
arr.push(i);
}
for (var i = 0; i<now; i++) {
newArr.push(arr.splice(Math.floor(Math.random()*arr.length),1))
}
return newArr;
}

PJAX 介绍

jQuery 业务笔记

发表于 2017-10-20 | 分类于 jQuery

jQuery

基础过滤

###$("selector").eq(index)
index: 要匹配元素的索引值(从0开始计数,负值时从最后一个元素开始倒计数)

$("selector").slice(index)

选择匹配集合中所有大于给定index(索引值)的元素。

$("selector").slice(0, index)

选择匹配集合中所有索引值小于给定index参数的元素。

$("selector").not()

选择所有元素去除不匹配给定的选择器的元素。

$("selector").filter(":odd")

选择索引值为奇数元素,从 0 开始计数。

$("selector").filter(":even")

选择所引值为偶数的元素,从 0 开始计数。

查找表格中索引值是偶数的行(即实际表格中的奇数行),即匹配第一行、第三行、第五行等 (索引值是 0, 2 ,4 等 )

$("selector").filter(":first")

选择第一个匹配的元素。

内容过滤

$( ":contains(text)" )

选择所有包含指定文本的元素。

$("selector").has(selector/DOMElement)

选择元素其中至少包含指定选择器匹配的一个种元素。

DOM 操作

class 属性

.addClass( className )

为每个匹配的元素添加指定的样式类名,和.removeClass()一起使用,用来切换元素的样式。

值得注意的是这个方法不会替换一个样式类名。它只是简单的添加一个样式类名到元素上。

.hasClass()

确定任何一个匹配元素是否有被分配给定的(样式)类。

.toggleClass( className, switch )

在匹配的元素集合中的每个元素上添加或删除一个或多个样式类,取决于这个样式类是否存在或值切换属性。即:如果存在(不存在)就删除(添加)一个类。
switch一个布尔值,用于判断样式是否应该被添加或移除。

复制元素

.clone()

创建一个匹配的元素集合的深度拷贝副本。
当和插入方法联合使用时,.clone()对于复制页面上的元素很方便。$('.hello').clone().appendTo('.goodbye');

DOM 移除

.detach()

从DOM中去掉所有匹配的元素。

.detach() 方法和.remove()一样, 除了 .detach()保存所有jQuery数据和被移走的元素相关联。当需要移走一个元素,不久又将该元素插入DOM时,这种方法很有用。

.empty()

从DOM中移除集合中匹配元素的所有子节点。

为了避免内存泄漏,jQuery先移除子元素的数据和事件处理函数,然后移除子元素。如果你想删除元素,不破坏他们的数据或事件处理程序(这些绑定的信息还可以在之后被重新添加回来),请使用.detach()代替 。

.remove()

将匹配元素集合从DOM中删除。(注:同时移除元素上的事件及 jQuery 数据。)

##DOM 替换

.replaceAll()

用集合的匹配元素替换每个目标元素。

.replaceWith()

用提供的内容替换集合中所有匹配的元素并且返回被删除元素的集合。

CSS 属性

.css()

获取匹配元素集合中的第一个元素的样式属性的值 或 设置每个匹配元素的一个或多个CSS属性。

简写速写的CSS属性(例如: margin, background, border) 是不支持的,例如,如果你想重新获取margin,可以使用$(elem).css(‘marginTop’) 和 $(elem).css(‘marginRight’),其他的也是如此。

.width()

为匹配的元素集合中获取第一个元素的当前计算宽度值或给每个匹配的元素设置宽度。

.height()

获取匹配元素集合中的第一个元素的当前计算高度值 或 设置每一个匹配元素的高度值。

.innerHeight()

为匹配的元素集合中获取第一个元素的当前计算高度值,包括padding,但是不包括border。

.innerWidth()

为匹配的元素集合中获取第一个元素的当前计算宽度值,包括padding,但是不包括border。

.css(‘height’) 和 .height()之间的区别是后者返回一个没有单位的数值(例如,400),前者是返回带有完整单位的字符串(例如,400px)。当一个元素的高度需要数学计算的时候推荐使用.height() 方法 。

这个方法同样能计算出window和document的高度。

1
2
$(window).height(); // returns height of browser viewport
$(document).height(); // returns height of HTML document

注意.height()总是返回内容宽度,不管CSS box-sizing属性值。

设置高度时如果没有给定明确的单位(像’em’ 或者 ‘%’),那么默认情况下”px”会被直接添加上去(也理解为”px”是默认单位)。

.offset()

在匹配的元素集合中,获取的第一个元素的当前坐标,或设置每一个元素的坐标,坐标相对于文档。

.offset()方法允许我们检索一个元素相对于文档(document)的当前位置。和.position()的差别在于:.position()是相对于相对于父级元素的位移。当通过全局操作(特别是通过拖拽操作)将一个新的元素放置到另一个已经存在的元素的上面时,若要取得这个新的元素的位置,那么使用 .offset() 更合适。.offset()返回一个包含top 和 left属性的对象 。

注意:jQuery不支持获取隐藏元素的偏移坐标。同样的,也无法取得隐藏元素的 border, margin, 或 padding 信息。
若元素的属性设置的是 visibility:hidden,那么我们依然可以取得它的坐标。但是若设置的属性是 display:none,由于在绘制 DOM 树时根本就不绘制该元素,所以它的位置属性值是 undefined。

.position()

获取匹配元素中第一个元素的当前坐标,相对于offset parent的坐标。( 及指离该元素最近的而且被定位过的祖先元素 )

.outerHeight([includeMargin ])

在.outerHeight()计算中总是包含padding-top ,padding-bottom 和 border-top,border-bottom ;如果includeMargin参数是true,那么margin (top 和 bottom)也会被包含。

.outerWidth([includeMargin ])

获取元素集合中第一个元素的当前计算宽度值,包括padding,border和选择性的margin。(注:返回一个整数(不包含“px”)表示的值,或如果在一个空集合上调用该方法,则会返回 null。)

.scrollLeft()

获取匹配的元素集合中第一个元素的当前水平滚动条的位置或设置每个匹配元素的水平滚动条位置。

.scrollTop()

获取匹配的元素集合中第一个元素的当前垂直滚动条的位置或设置每个匹配元素的垂直滚动条位置。

DOM 插入

.after()

在匹配元素集合中的每个元素后面插入参数所指定的内容,作为其兄弟节点。

.after()和.insertAfter()实现同样的功能。主要的不同是语法——特别是内容和目标的位置。 对于 .after(), 选择表达式在函数的前面,参数是将要插入的内容。 对于.insertAfter(), 刚好相反,内容在方法前面,它将被放在参数里元素的后面。

.before()

根据参数设定,在匹配元素的前面插入内容

.before() 和.insertBefore()实现同样的功能。主要的不同是语法——内容和目标的位置不同。对于.before(), 选择器表达式在方法的前面,参数是将要插入的内容。对于.insertBefore()刚好相反,内容在方法前面,无论是作为一个选择表达式或作为标记上创建动态,它将被放在目标容器的前面。

.append()

.append()函数将特定内容插入到每个匹配元素里面的最后面,作为它的最后一个子元素(last child), (如果要作为第一个子元素 (first child), 用.prepend()).

.append() 和.appendTo()实现同样的功能。主要的不同是语法——内容和目标的位置不同。对于.append(), 选择器表达式在函数的前面,参数是将要插入的内容。对于.appendTo()刚好相反,内容在方法前面,无论是一个选择器表达式 或创建作为标记上的标记,它都将被插入到目标容器的末尾。

通用属性操作

.attr()

获取匹配的元素集合中的第一个元素的属性的值 或 设置每一个匹配元素的一个或多个属性。
当设置多个属性,包裹属性名的引号是可选的。但当设置样式名(“class”)属性时,必须使用引号!

1
2
3
4
5
// for example
$('#greatphoto').attr({
alt: 'Beijing Brush Seller',
title: 'photo by Kelly Clark'
});

注意: jQuery禁止改变一个 input 或 button 元素的type 特性(attribute),并且在所有浏览器下将抛出一个错误。因为Internet Explorer不会允许你改变 input 或者 button 元素的type属性。

.prop()

获取匹配的元素集中第一个元素的属性(property)值或设置每一个匹配元素的一个或多个属性。

.prop()方法只获得第一个匹配元素的属性值 。如果元素上没有该属性,或者如果没有匹配的元素。那么该方法会返回undefined值。若要取得每个匹配元素的属性值(property),请使用循环结构,如jQuery .each()或.map()方法。

.html()

获取集合中第一个匹配元素的HTML内容 或 设置每一个匹配元素的html内容。

.removeAttr()

为匹配的元素集合中的每个元素中移除一个属性(attribute)。

注意: Internet Explorer 6, 7 ,或8中,使用.removeAttr()删除一个内联onclick 事件处理程序没有实现,为了避免潜在的问题,使用 .prop()代替:

.removeProp()

.removeProp()方法用来删除由.prop()方法设置的属性集。

注意: 不要使用此方法来删除原生的属性( property ),比如checked, disabled, 或者 selected。这将完全移除该属性,一旦移除,不能再次被添加到元素上。使用.prop()来设置这些属性设置为false代替。

.text()

得到匹配元素集合中每个元素的文本内容结合,包括他们的后代,或设置匹配元素集合中每个元素的文本内容为指定的文本内容。

.val()

.val()方法主要用于获取表单元素的值,比如 input, select 和 textarea。对于 <select multiple="multiple"> 元素, .val()方法返回一个包含每个选择项的数组,如果没有选择性被选中,它返回null。

.unwrap()

将匹配元素集合的父级元素删除,保留自身(和兄弟元素,如果存在)在原来的位置。

.wrap()

在每个匹配的元素外层包上一个html元素。

事件

浏览器事件

.scroll()

当用户在元素内执行了滚动操作,就会在这个元素上触发scroll事件。它适用于window对象,但也可以是可滚动frames与CSS overflow属性设置为scroll的元素(或auto时,元素的显示高度小于其内容高度)。

绑定事件处理器

.bind()

为一个元素绑定一个事件处理程序。
bind()方法类似于原生javascript的addEventListener()方法,用于绑定事件;

.on()

.on()方法事件处理程序到当前选定的jQuery对象中的元素。在jQuery 1.7中,.on()方法 提供绑定事件处理的所有功能。为了帮助从旧的jQuery事件方法转换过来,查看 .bind(), .delegate(), 和 .live(). 要删除的.on()绑定的事件,请参阅.off()。要绑定一个事件,并且只运行一次,然后删除自己, 请参阅.one()

.off()

移除一个事件处理函数。

.one()

one()方法用于处理只触发一次的事件

.trigger()

trigger()方法类似于原生javascript的dispatchEvent()方法,用于触发事件;

.triggerHandler()

.triggerHandler() 方法的行为与 .trigger() 相似,不同之处有如下几点:

  1. triggerHandler() 方法并不会触发事件的默认行为。(例如,表单提交)。
  2. trigger() 会影响所有与 jQuery 对象相匹配的元素,而 .triggerHandler() 仅影响第一个匹配到的元素。
  3. 使用 .triggerHandler() 创建的事件,并不会在 DOM 树中向上冒泡。如果事件没有被目标元素直接处理,那么它就不会进行任何处理。
  4. 与普通的方法返回 jQuery 对象(这样就能够使用链式用法)相反,.triggerHandler() 返回最后一个处理的事件的返回值。如果没有触发任何事件,会返回 undefined。

事件对象

event.pageX

鼠标相对于文档的左边缘的位置(左边)

event.pageY

鼠标相对于文档的顶部边缘的位置(坐标)

event.preventDefault()

如果调用这个方法,默认事件行为将不再触发

event.stopPropagation()

防止事件冒泡到DOM树上,也就是不触发的任何前辈元素上的事件处理函数

event.target

触发事件的DOM元素

target 属性可以是注册事件时的元素,或者它的子元素。通常用于比较 event.target 和 this 来确定事件是不是由于冒泡而触发的。经常用于事件冒泡时处理事件委托。

event.which

针对键盘和鼠标事件,这个属性能确定你到底按的是哪个键

event.which也将正常化的按钮按下(mousedown 和 mouseupevents),左键报告1,中间键报告2,右键报告3。使用event.which代替event.button

##表单事件

.blur()

一个元素失去焦点将触发blur事件。起初,这个事件仅适用于表单元素,如元素<input> 。在最新的浏览器中,这个事件适用范围已经扩大到包括所有元素类型。一个元素可以通过键盘命令失去焦点,比如tab键,或用鼠标点击网页上的其他地方。

.change()

一个元素的值改变的时候将触发change事件。此事件仅限用于<input>元素,<textarea>和<select>元素。对于下拉选择框,复选框和单选按钮,当用户用鼠标作出选择,该事件立即触发,但对于其他类型的input元素,该事件触发将推迟,直到元素失去焦点才会触点。

.focus()

当一个元素获得焦点时,focus事件被触发。此事件起初适用于有限的元素,比如表单元素(<input>, <select>等)和链接元素(<a href>)。在最近版本的浏览器中,该事件可以扩展到所有包括通过显式设置tabindex属性的元素类型。一个元素可以通过键盘命令获得焦点,如Tab键,或按鼠标点击的元素。

.focusout()

focusout 事件会在元素(或者其内部的任何元素)失去焦点时触发。这跟 blur 事件的显著区别在于,它可以在父元素上检测子元素失去焦点的情况(换而言之,它支持事件冒泡)

.select()

当用户在一个元素中进行文本选择时,这个元素上的select事件就会被触发。此事件只能用在<input type="text"> 和<textarea>

.submit()

当用户试图提交表单时,就会在这个表单元素上触发submit事件。它只能绑定在

元素上。以下几种情况会导致表单被提交:用户点击了<input type="submit">, <input type="image">, 或者 <button type="submit">,或者当某些表单元素获取焦点时,敲击Enter(回车键),都可以提交。

鼠标事件

.click()

一个元素被点击和鼠标按键被按下和释放时候将触发 click 事件。任何HTML元素都可以接收此事件。

.dblclick()

一个元素被双击时将触发 dblclick 事件。任何HTML元素都可以收到此事件。

.hover()

.hover()方法是同时绑定 mouseenter和 mouseleave事件。我们可以用它来简单地应用在 鼠标在元素上行为。
调用 $(selector).hover(handlerIn, handlerOut) 是以下写法的简写:
$(selector).mouseenter(handlerIn).mouseleave(handlerOut)

.mousedown()

当鼠标指针在元素上和按下鼠标键,mousedown事件被发送到这个元素。任何HTML元素都可以收到此事件。

.mouseenter()

该事件在鼠标移入到元素上时被触发。任何HTML元素都可以接受此事件。

.mouseleave()

该事件在鼠标离开元素上时被触发。任何HTML元素都可以接受此事件。

.mousemove()

当鼠标指针在元素内移动时,mousemove事件就会被触发,任何HTML元素都可以接受此事件。

.mouseout()

当鼠标指针离开元素时,mouseout事件就会被触发,任何HTML元素都可以接受此事件。

.mouseover()

当鼠标指针进入元素内时,mouseover事件就会被触发,任何HTML元素都可以接受此事件。

.mouseup()

当鼠标指针在元素内,并且鼠标按键被释放时,mouseup事件就会被触发,任何HTML元素都可以接受此事件。

.toggle()

.toggle()方法的处理程序绑定一个click事件,如果提供两个以上的处理函数,.toggle()将在它们中循环。

$.isArray()

函数用于判断指定参数是否是一个数组
函数的返回值为Boolean类型,如果指定的参数是数组,则返回true,否则返回false。

$.getScript()

使用一个HTTP GET请求从服务器加载并执行一个 JavaScript 文件。参考

注意不要直接在$.getScript()执行后直接调用该js文件中的变量或函数,因为$.getScript()是异步加载的,在你访问其中的某个变量或函数时,可能该js文件尚未完全加载完毕。建议你最好在success回调函数中处理,或者你能够确认此时该js文件已经加载完毕。

jQuery.makeArray()

函数用于将一个类数组对象转换为真正的数组对象,函数的返回值为Array类型,返回转换后的数组对象。

所谓”类数组对象”就是一个常规的Object对象,但它和数组对象非常相似:具备length属性,并以0、1、2、3……等数字作为属性名。不过它毕竟不是数组,没有从数组的原型对象上继承下来的内置方法(例如:push()、 sort()等)。

jQuery.isPlainObject()

函数用于判断指定参数是否是一个纯粹的对象。
所谓”纯粹的对象”,就是该对象是通过”{}”或”new Object”创建的。
函数的返回值为Boolean类型,如果指定的参数是纯粹的对象,则返回true,否则返回false。

extend()

extend(dest,src1,src2,src3…)


JavaScript

concat()

用于连接两个或多个数组,该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。

replace()

方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

vue.js进阶之vue-router

发表于 2017-09-24 | 分类于 vue

前端路由

在web开发中,路由是指根据url分配到对应的处理程序

vue-router

作用: 通过管理url,实现url和组件的对应以及通过url进行组件之间的切换
官方文档

单页应用(SPA)

加载单个HTML页面,并在用户与应用程序交互时动态更新该页面。

vue-router使用步骤

安装模块
npm install vue-router –save

引入模块
import VueRouter frome ‘vue-router’

作为Vue的插件
Vue.use(VueRouter)

创建路由实例对象
new VueRouter({ …配置参数 })

注入Vue选项参数
new Vue({ router })

告诉路由渲染的位置

hash和history模式(默认为hash,用mode更改)

1
2
3
4
let router = new Router({
mode: 'history',
...
})

router-link各种配置项


默认生成a标签,如果要生成div可使用tage=“标签”

1
<router-link to="/" tag="div">home</router-link>

导航加上小图标方法

1
2
3
4
<router-link to="/" tag="li">
<i></i>
<span>home</span>
</router-link>

定义激活状态下的class名
第一种方法
linkActiveClass: class名

1
2
3
4
5
let router = new Router({
mode: 'history',
linkActiveClass: 'is-active'
....
})

第二种方法
active-class=”class名”

1
<router-link to="/about" active-class="activeClass">about</router-link>

改变行为
在router-link增加event=“mouseover”

重定向和别名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
path: '*',
//component: noFound
// 重定向
//redirect: '/home'
//redirect: {path: '/home'}
// redirect: {name: 'About'}
redirect: (to) => { //动态设置重定向的目标
// 目标路由对象,就是访问的路径的路由信息
if( to.path === '/123' ) {
return '/home'
}else if(to.path === '/456'){
return {path: '/document'}
}else{
return {name: 'About'}
}
console.log(to)
//return '/home'
}

嵌套路由的使用

H5重力感应事件

发表于 2017-09-10

越来越多地,基于web的设备能够确定它们的方向; 也就是说,它们可以报告指示相对于重力拉力的它们的取向的改变的数据。特别地,通过这些数据,像手机等一些手持设备可以实现自动调整旋转角度来保持显示直立,以及当设备旋转到宽屏时(宽度大于高度),自动提供宽屏的网页效果。

有两种Javascript事件负责处理设备方向信息。

第一种是DeviceOrientationEvent(提供给网页开发者当设备(指手机,平板等移动设备)在浏览页面时物理旋转的信息。)它会在加速度传感器检测到设备在方向上产生变化时触发。通过处理该事件传来的数据信息,使针对由于用户移动设备引起旋转和仰角变化的行为设计交互响应成为可能。

第二种是DeviceMotionEvent,它会在加速度发生改变时触发。跟DeviceOrientationEvent不同,监听的是加速度的变化而不是方向。传感器通常都具有监听DeviceMotionEvent的能力,包括笔记本中用于保护移动存储设备的传感器。而能监听DeviceOrientationEvent事件的传感器更多出现在移动设备中。

处理方向orientation事件

要接收设备方向变化信息,你只需要注册监听deviceorientation事件:

1
window.addEventListener("deviceorientation", handleOrientation, true);

注册完事件监听处理函数后(对应例子中的handleOrientation),监听函数会定期地接收到最新的设备方向数据。
方向事件对象中包含四个值:
DeviceOrientationEvent.absolute
DeviceOrientationEvent.alpha
DeviceOrientationEvent.beta
DeviceOrientationEvent.gamma

下面是一个事件处理函数的例子:

1
2
3
4
5
6
7
8
function handleOrientation(orientData) {
var absolute = orientData.absolute;
var alpha = orientData.alpha;
var beta = orientData.beta;
var gamma = orientData.gamma;
// Do stuff with the new orientation data
}

关于每一个轴的记录值表示的是相对于标准的坐标系,设备在某一个给定轴上的旋转量。Orientation and motion data explained这篇文章有更详细的描述,下面是对这篇文章的总结。
DeviceOrientationEvent.alpha 表示设备沿z轴上的旋转角度,范围为0~360。
DeviceOrientationEvent.beta 表示设备在x轴上的旋转角度,范围为-180~180。它描述的是设备由前向后旋转的情况。
DeviceOrientationEvent.gamma 表示设备在y轴上的旋转角度,范围为-90~90。它描述的是设备由左向右旋转的情况。

例子

这个例子会成功运行在支持检测自己方向的设备中的支持deviceorientation事件的浏览器中。

想象一下花园(garden)中的一个球(ball):
https://developer.mozilla.org/zh-CN/docs/Web/API/Detecting_device_orientation

https://developer.mozilla.org/zh-CN/docs/Web/API/DeviceOrientationEvent

https://developer.mozilla.org/zh-CN/docs/Web/Guide/Events/Orientation_and_motion_data_explained

webapp开发相关jquery手势事件之jGestures
http://www.haorooms.com/post/jquery_jGestures

html5图片随手机重力感应而移动效果
http://www.haorooms.com/post/html5_image_zlgy

视觉差效果制作总结和案例下载
http://blog.csdn.net/confidence68/article/details/52054556

ECMAScript6常用语法

发表于 2017-06-03

let和const

let命令:用来声明变量,和var非常类似

  1. 所声明的变量只在所在的代码块内有效。
1
2
3
4
5
6
7
{
let a = 1;
var b = 2;
console.log(a) //1
}
console.log(a); //err not defined
console.log(b); //2
  1. 使用Let声明的变量在域解析的时候不会被提升。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
console.log(a); //err not defined
let a = 2;
console.log(b); //undefined
var b = 1;
typeof c; //err not defined
let c = 3;
let f = 10;
function fn() {
f = 7; //暂时性死去
let f = 2;
}
fn(); ////err not defined
  1. let不允许在同一个作用域下声明已经存在的变量。
1
2
3
4
5
var a = 1;
let a; //err
let a = 1;
let a = 2; //err

for循环的梗

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
var aLi = document.getElementsByTagName('li');
for(var i = 0; i < aLi.length; i++){
aLi[i].onclick = function() {
console.log(i);
}
}
// 得到是只会是aLi.length
for (var i = 0; i < aLi.length; i++) {
aLi[i].index = i
aLi[i].onclick = function () {
console.log(this.index);
}
}
// 添加自定义属性可以拿到每次循环的i
for (var i = 0; i < aLi.length; i++) {
(function (i) {
aLi[i].onclick = function () {
console.log(i);
}
})(i);
}
// 用闭包方式拿到每次循环的i
for(let i = 0; i < aLi.length; i++){
aLi[i].onclick = function() {
console.log(i);
}
}
// let直接搞定 拿到每次循环的i

在循环语句之内是父作用域,在循环体之中是一个子作用域

1
2
3
4
5
for (let i = 0; i < 3; i++) {
let i = 10;
console.log(i); //10 循环体的i不受循环语句内i的影响
}
console.log(i); //err not defined 循环体中的i外部访问不到

const命令:用来声明一个常量,常量就是不可以变化的量
const同样有let的三条特点,此外还要注意:
1 声明的时候必须赋值;
2 声明的常量储存简单的数据类型时候不可改变其值,如果储存的是对象,那么引用不可以被改变,至于对象里面的数据如何变化是没有关系的

1
2
3
const obj = { a : 10 };
obj.a = 20;
console.log(obj);//{ a : 20 }

变量的解构赋值

基本概念:本质上就是一种匹配模式,只要等号两边的模式相同,那么左边的变量就可以被赋予对应的值。
解构赋值主要分为:
1 数组的解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//let a = 1;
//let b = 2;
//let c = 3;
let [a, b, c] = [1, 2, 3];
console.log(a, b , c); //1 2 3
let [a, [ [ b ], c] ] = [1, [ [ 2 ], 3] ]
console.log(a, b , c); //1 2 3
let [, , c] = [1, 2, 3];
console.log(c); // 3
let [x] = [];
console.log(x); //undefined
let [y = 1] = [];
console.log(y); //1

2 对象的解构赋值

1
2
3
4
5
6
let {a,b} = {b: 'bbb', a: 'aaa'};
console.log(a,b); ///aaa bbb
let {a : b} = {a : 1};
console.log(b) //1
console.log(a) //err not defined

3 基本类型的解构赋值

1
2
3
4
5
6
7
let [a, b, c, d] = '1234';
console.log(a, b, c,d) // 1 2 3 4
let {length : len} = "adele";
console.log(len); //5
null和undefined不能被解构赋值

数据解构 Set

集合的基本概念:集合是由一组无序且唯一(即不重复)的项组成的,这个数据结构使用了与有限集合相同的数学概念,应用在计算机的数据结构中。
特点: key 和 value 相同 没有重复的value
ES6提供了数据结构Set,类似于数组,但是成员的值是唯一的,没有重复的值。
1 如何创建 Set

1
2
const s = new Set([1,2,3]);
console.log(s);

2 Set 类属性

1
console.log(s.size); // 3

3 Set类的方法
set.add(value) 添加一个数据,返回set结构本身

1
2
s.add('a').add('b').add('c');
console.log(s);

set.delete(value) 删除指定数据,返回一个布尔值,表示删除是否成功

1
2
console.log(s.delete('a'));
console.log(s);

set.has(value) 判断该值是否为set的成员,返回一个布尔值

1
2
console.log(s.has('a')); // false
console.log(s.has('1')); //true

set.clear() 清楚所有数据,没有返回值

1
2
s.clear();
console.log(s);

keys() 返回键名的遍历器

//键和值相同```
1
2
values() 返回键值的遍历器
```console.log(s.values()); //键和值相同

entries() 返回键值对的遍历器

//键和值相同```
1
forEach() 使用回调函数遍历每个成员

s.forEach(function (value, key, set){
console.log(value + “adele”);
})
console.log(s); //没有变化

1
2
3
4
5
6
7
8
9
10
**利用set为数组去重**
数据结构 Map
---
字典:是用来存储不重复key的hash结构。不同于集合(set)的是,字典使用的是[键, 值]的形式来储存数据的
JS的对象(object : {})只能用字符串当键,这给其使用带来很大限制
ES6的Map数据结构类似于对象,也是键值对的集合,但“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。也就是说Object结构提供了“字符串-值”的对应,Map结构提供了 “值-值”的对应,是一种完美的Hash结构实现,如果你需要 “键值对”的数据结构,Map比Object更适合
1 如何创建一个 Map

const map = new Map([
[‘a’, 1],
[‘b’, 2]
]);
console.log(map);

1
2
2 Map 类的属性

console.log(map.size);

1
2
3
4
5
3 Map 类的方法
set(key, value) 设置键名key对应值为value,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则重新生成该值
```
map.set("adele", "fe").set("adai", "rd")

get(key) get方法读取key对应的键值,如果找不到key,返回undefined

delete(key) 删除某个键值,返回true,如果删除失败,返回false

has(key) 方法返回一个布尔值,表示某个键是否在当前Map对象之中

clear() 清楚所有数据,没有返回值

keys() 返回键名的遍历器

values() 返回键值的遍历器

entries() 返回键值对的遍历器

forEach() 使用回调函数遍历每个成员

map.forEach( function( key, value, map){
console.log(key + ‘:’ + value);
})

map使用的一些注意事项
map数据结构中NaN是同一个键
map里key的排列顺序按照添加的顺序排列

iterator和for-of循环

Iterator是一个接口,为各种不同的数据结构(数组、对象、Set、Map)提供统一的访问机制。任何数据结构只要部署Iterator接口就可以完成遍历操作,而且这种遍历操作时依次处理该数据结构的所有成员

Iterator遍历器的作用
为各种数据结构提供一个统一的、简便的访问接口
使得数据结构的成员能够按照某种次序排列
ES6新增了遍历命令for…of循环,Iterator接口主要供其消费。

1、手写Iterator接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const arr = [1, 2, 3];
function iterator(arr){
let index = 0;
return {
next: function () {
return index < arr.length ?
{value: arr[index++], done: false} :
{value: undefined, done: true};
}
}
}
const it = iterator(arr);
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Iterator的遍历过程

  1. 创建一个指针对象,指向当前数据结构的起始位置,也就是说遍历器对象本质上就是一个指针对象
  2. 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
  3. 第二次调用指针对象的next方法,指针指向数据结构的第二个成员
  4. 不断调用指针对象的next 方法,直到它指向数据结构的结束位置。

每一次调用next方法都会返回数据结构当前的成员信息。具体来说就是返回一个包含value 和done两个属性的对象。其中 value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。

  1. 凡是具有 symbol.iterator 属性的数据结构都具有 Iterator 接口
    arr、set、map(object没有symbol.iterator )
    具备iterator接口的数据结构都可以进行如下操作
    结构复制
    扩展运算符 (… 作用为将数据结构展开)

利用Set为数组去重

1
2
let arr = [{}, 1, 'a', 1, 'a', 'b', []];
console.log([...new Set(arr)]);

for…of循环

1
2
3
4
5
6
7
8
9
10
11
12
13
const ofArr = [1, 2, 3, 4];
for(let i of ofArr) {
console.log(i);//i为数据结构中的每一项
}
const m = new Map();
m.set('a', 1).set('b', 2).set('c', 3)
for(let data of m){
console.log(data);
}
for(let [key, value] of m){
console.log(key, value);
}

class的基本使用

ES6中新增加了类的概念,可以使用class 关键字声明一个类,之后以这个类来实例化对象

1
2
3
4
5
6
7
8
9
10
11
12
class Adele {
constructor(a, b){
this.a = a;
this.b = b;
return this;
}
print(){
console.log(this.a + ' ' + this.b);
}
}
const adele = new Adele('hello', 'word').print();

Adele中的constructor方法是构造方法,this关键字则代表实例对象

Adele这个类除了构造方法还定义了一个print方法。注意,定义“类”的方法时,前面不需要加上function这个关键字,直接把函数定义放进去就可以了,另外方法之间不需要逗号分隔,加了会报错。

构造函数的prototype属性在ES6的“类”上继续存在,而且类的所有方法都定义在类的prototype属性上面

定义在类中的方法都是不可以枚举的

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显示定义,一个空的constructor方法会被默认添加

生成类的实例对象的写法与ES5完全一样,也是使用new命令,如果忘记加上new,像函数那样调用class将会报错

class的继承

子类继承父类使用estends 关键字
为父类指定静态方法使用 static 方法名字
super

在构造函数中可以当一个函数来使用,相当于调用父类的构造函数
在原型方法中可以当一个对象来使用,相当于父亲的原型对象,并且会自动绑定this到子类上

Symbol数据类型

Symbol表示独一无二的值,它是JS中的第七种数据类型。
基本数据类型:Null Undefined Number Boolean String Symbol
引用类型:Object

Symbol函数不能使用new否则会报错,原因在于Symbol是一个原始类型的值,不是对象

Symbol函数接受一个字符串作为参数,表示对Symbol的描述,主要是为了在控制台显示,或者转为字符串的时候比较容易区分。

Symbol数据类型转换:字符产、布尔值

内置对象的扩展

字符串扩展
新增模板字符串

1
2
3
4
5
6
7
8
9
10
11
let flag = true;
let html = `
<ul>
<li>
<span>${'首页'}</span>
<span class = "${flag ? 'show' : 'hide'}"></span>
</li>
</ul>
`;
console.log(html);

repeat():对字符串做一些重复的操作

1
2
3
let str1 = 'a';
let str2 = str1.repeat(3);
console.log(str2); //aaa

includes() 类似于indexOf() ,看是否包含某个字符串
startsWith() / endsWith() 看开头 / 结尾是否包含某个字符串

数组扩展
Array.from() 将类数组转化为数组

Array.of() 创建一个数组 类似于 []

find() 对数组进行筛选,没找到返回undefined
findIndex() 返回符合条件元素的下标,没找到返回-1

fill() 对数组进行填充

对象的扩展
对象的简洁表示法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let a = 1;
const obj = {
a : a
};
//键值相同,可以像下面的方式简写
const obj = {a};
const obj = {
fn1: function(){
console.log(1);
},
fn2(){
console.log(2); //简写可以不写function
}
}
obj.fn1();
obj.fn2();

Object.is() 判断两个对象是否一样,长的一样就成

Object.assign() 将多个对象进行合并

函数的扩展
1 为函数参数指定默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function fn(a, b){
a = a || 10;
b = b || 20;
console.log(a + b);
}
fn(); //30
fn(0, 10); //20 0为false取了后面的默认值
//ES6可以直接在参数里面赋值
function fn1(a = 10, b = 20) {
console.log(a + b);
}
fn1(); //30;
fn1(0, 10); //10

2 函数的 rest 参数
rest 参数形式为(”…变量名”),用于获取函数多余的参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中

1
2
3
4
5
6
7
8
9
function sum(a, ...arr) { //rest后面不能传参数
var res = a;
for (var i = 0; i < arr.length; i++) {
res += arr[i];
}
console.log(res);
}
sum(10,1, 2, 3, 4, 5);

3 箭头函数
使用“箭头”(=>)定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const fn = a => a;
const fn2 = function (a) {
return a;
}
console.log(fn(1)); //1
console.log(fn2(2)); //2
const fn3 = (a, b) => a + b;
console.log(fn3(1, 2));//3
//多行代码需要用中括号包裹起来
const fn4 = (a, b) => {
a = a * 2;
b = b * 2;
return a + b;
}
console.log(fn4(1, 2)); // 6
//返回值为对象需要用小括号包裹
const fn5 = (a, b) => ({a, b});
console.log(fn5(1,2));

箭头函数体内没有自己的this对象,所以使用时其内部的this就是定义是所在环境的变量,而不是使用时所在环境的对象。

不能给箭头函数使用call apply bind 去改变其内部的this指向

箭头函数体内没有arguments对象,如果要要用可以用rest参数代替

不可以当做构造函数,不可以使用new命令,否则会抛出一个错误

异步操作之Promise

Promise 是ES6中新增的异步编程解决方案,体现在代码中它是一个对象,可以通过 Promise 构造函数来实例化
new Promise(cb) ===> 实例的基本作用 Pending(正在进行) Resolved(已经完成) Rejected(已经失败)

Pending(正在进行) ===> Resolved(已经完成)
Pending(正在进行) ===> Rejected(已经失败)
两个原型方法
Promise.prototype.then() //处理成功后
Promise.prototype.catch() //捕获失败后的异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const imgs = [
'http://pic2116.ytqmx.com:82/2017/0531/35/9.jpg!960.jpg']
const p = new Promise(function(resolve, reject){
const img = new Image();
img.src = imgs[0];
img.onload = function (){
resolve(this);
};
img.onerror = function () {
reject(new Error('图片加载失败'));
};
});
p.then(function (img) {
console.log('图片加载完成');
document.body.appendChild(img);
}).catch(function (err) {
console.log(err);
})

两个常用的静态方法
Promise.all()
可以将多个Promise实例包装成一个新的Promise实例
当所有Promise实例的状态都变成resolved,Promise.all的状态才会变成resolved,此时 返回值组成一个数组,传递给then中的resolve函数。
只要其中有一个Rejected,Promise.all的状态就变成Rejected,此时第一个被reject的实例的返回值会传递给p的回调函数。

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
const imgs = [
'http://pic2116.ytqmx.com:82/2017/0531/35/9.jpg!960.jpg',
'http://pic2116.ytqmx.com:82/2017/0531/35/10.jpg!960.jpg'
]
function loadImg(url){
const p = new Promise(function(resolve, reject){
const img = new Image();
img.src = url;
img.onload = function (){
resolve(this);
};
img.onerror = function () {
reject(new Error('图片加载失败'));
};
});
return p;
}
const allDone = Promise.all([loadImg(imgs[0]), loadImg(imgs[1])]);
allDone.then(function (datas){
datas.forEach(function (item, i) {
document.body.appendChild(item);
});
}).catch(function (arr) {
console.log(arr);
})

Promise.resolve()
将一个对象转换为Promise对象
1 参数是Promise实例,将不做任何修改,原封不动地返回这个实例
2 j将对象转为Promise对象,然后立即执行thenable对象的then方法

1
2
3
4
Promise.resolve(
then(resolve, reject){
}
)

3 参数是一个基本数据类型或者不传参数,那么返回一个状态为 resolved的Promise 对象

JS面向对象之组件开发

发表于 2017-05-29 | 分类于 js

组件开发是什么

组件开发 : 多组对象,像兄弟之间的关系( 代码复用的一种形式 )
对象的多种表现形式
提高对象的复用性
如何配置参数和默认参数
例子 : 拖拽
例子 : 弹窗

什么是组件?

对面向对象的深入应用(UI组件,功能组件)
将 配置参数、方法、事件,三者进行分离
参见 jQuery UI

创建自定义事件

自定义事件:就是让函数能够具备事件的某些特性

有利于多人协作开发代码
如何去挂载自定义事件与事件函数

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
55
window.onload = function(){
var oDiv = document.getElementById('div1');
var oSpan = document.getElementById('span1');
bindEvent(oDiv , 'click',function(){
alert(1);
});
bindEvent(oDiv , 'click',function(){
alert(2);
});
bindEvent(oSpan , 'show',function(){
alert(3);
});
bindEvent(oSpan , 'show',function(){
alert(4);
});
bindEvent(oSpan , 'hide',function(){
alert(5);
});
fireEvent(oSpan , 'show'); //3 , 4
};
function bindEvent(obj,events,fn){
//obj : 楼层
//events : 书架
//fn : 一本书
obj.listeners = obj.listeners || {};
obj.listeners[events] = obj.listeners[events] || [];
obj.listeners[events].push( fn );
if(obj.addEventListener){
obj.addEventListener(events,fn,false);
}
else{
obj.attachEvent('on'+events,fn);
}
}
function fireEvent(obj,events){ //主动触发自定义事件
for(var i=0;i<obj.listeners[events].length;i++){
obj.listeners[events][i]();
}
}
<div id="div1">div</div>
<span id="span1">span</span>

css3新特性回顾

发表于 2017-02-24 | 分类于 css3

选择器

属性选择器

注:前四个为CSS2定义的属性选择器

E[attr] 属性名,不确定具体属性值
E[attr=”value”] 指定属性名,并指定其对应属性值
E[attr ~=”value”] 指定属性名,找到的是具有此属性名,且与其它属性名之间用空格隔开
E[attr |= “value”] 指定属性名,属性值以value-开头或者值为value
E[attr ^= “value”] 指定属性名,属性值以value开头
E[attr $=”value”] 指定属性名,属性值以value结束
E[attr *=”value”] 指定了属性名,属性值中包含了value

阅读全文 »

HTML5常用标签语法

发表于 2017-02-22 | 分类于 html5

HTML5标签语义化

为什么标签要语义化

  1. 搜索引擎友好。
  2. 更容易让屏幕阅读器读出网页内容。
  3. 去掉或样式丢失的时候能让页面呈现清晰的结构。
  4. 便于团队开发和维护。

应注意的问题

  • 尽可能减少使用无语义标签div和span。
  • 语义不明显,可以用p也可以使用div的情况下,尽量用p。
  • 不要使用纯样式标签,例如b、font和u等,改用CSS设置。
  • 使用HTML5的结构元素。
    阅读全文 »
1234
Adele

Adele

Coding Peasant

37 日志
12 分类
28 标签
© 2018 Adele
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4