综合一

编程知识 更新时间:2023-04-28 05:09:36

自我介绍

左固定右自适应布局

这是一个很常见的布局,当然也可以实现右侧自适应,左侧自适应。比如常见的网页中,左侧导航栏是固定的,右侧的内容区要自适应浏览器的大小。 
现在我们来看下HTML布局:

<div id="outer">

  <div id="sidebar" style="height:240px;">固定宽度区</div>

  <div id="content" style="height:340px;">自适应区</div>

</div>

<div id="footer">后面的一个DIV,以确保前面的定位不会导致后面的变形</div>

下面讲一下常见的方法: 
1
、将左侧div浮动,右侧div设置margin-left

       .sidebar{

            width: 300px;

            height: 300px;

            background-color: pink;

            float:left;

        }

        .content{

            margin-left: 300px;

            height: 100px;

            background-color: blue;

        }

        .footer{

            background-color: red;

        }

        .outer:after{

            display: block;

            content:'';

            clear: both;

            visibility: hidden;

        }

        .outer{

            zoom:1;

        }

效果图如下: 

大家要注意html中必须使用div标签,不要妄图使用什么p标签来达到目的。因为div有个默认属性,即如果不设置宽度,那他会自动填满他的父标签的宽度。这里的content就是例子。

当然我们不能让他填满了,填满了他就不能和sidebar保持同一行了。我们给他设置一个margin。由于sidebar在左边,所以我们设置contentmargin-left值,值比sidebar的宽度大一点点——以便区分他们的范围。例子中是300.

假设content的默认宽度是100%,那么他设置了margin后,他的宽度就变成了100%-300,此时content发现自己的宽度可以与sidebar挤在同一行了,于是他就上来了。

而宽度100%是相对于他的父标签来的,如果我们改变了他父标签的宽度,那content的宽度也就会变——比如我们把浏览器窗口缩小,那wrap的宽度就会变小,而content的宽度也就变小——但,他的实际宽度100%-300始终是不会变的。

这个方法看起来很完美,只要我们记得清除浮动(这里我用了最简单的方法),那footer也不会错位。而且无论contentsidebar谁更长,都不会对布局造成影响.

但实际上这个方法有个限制——htmlsidebar必须在content之前! 
如果siderbar当到了content后面,就会出现如下的效果: 

但我需要sidebarcontent之后!因为我的content里面才是网页的主要内容,我不想主要内容反而排在次要内容后面。

但如果sidebarcontent之后,那上面的一切都会化为泡影。

可能有的人不理解,说你干嘛非要sidebar在后面呢?这个问题说来话长,反正问题就是——content必须在sidebar之前,但content宽度要自适应,怎么办?接着往下看。

2、固定区采用绝对定位,自适应区仍然设置margin 
CSS
代码如下:

        .sidebar{

            width: 300px;

            height: 300px;

            background-color: pink;

            position: absolute;

            top:0;

            left: 0;

 

        }

        .content{

            height: 100px;

            background-color: blue;

        }

        .footer{

            background-color: red;

        }

 

        .outer{

            position: relative;

        }

效果图: 

可以发现,此时下面的红色div受影响了。其实这与footer无关,而是因为outersidebar的无视造成的。看来这种定位方式只能满足sidebar自己,但对他的兄弟们却毫无益处。

3、标准浏览器的方法 
当然,以不折腾人为标准的w3c标准早就为我们提供了制作这种自适应宽度的标准方法。那就简单了:把outer设为display:table并指定宽度100%,然后把content+sidebar设为display:table-cell;然后只给sidebar指定一个宽度,那么content的宽度就变成自适应了。 
对应的CSS代码

       .sidebar{

            width: 300px;

            height: 300px;

            background-color: pink;

            display:table-cell;

 

        }

        .content{

            height: 100px;

            background-color: blue;

            display:table-cell;

        }

        .footer{

            background-color: red;

        }

 

        .outer{

            display: table;

            width:100%;

        }

不过这种做法,如果sidebar写在content前面,sidebar会固定在左侧,否则固定在右侧。 
HTML

<div class="outer">

    <div class="sidebar">

        sidebar固定区域

    </div>

    <div class="content">

        content自适应区域

    </div>

</div>

<div class="footer">

    后面的一个DIV,以确保前面的定位不会导致后面的变形

</div>

代码很少,而且不会有额外标签。不过这是IE7都无效的方法。

———————再说一点————————

如果不考虑ie7及以下版本,则使用标准方法;如果不在意sidebarcontent的顺序,则用第一种方法;如果不考虑对其他兄弟元素的影响,用第3种方法。

以上代码都没在IE6测试,有问题不负责解释。让IE6寿终正寝的办法就是——从此不再理他。

左边定宽,右边自适应布局的几种方法

实际的页面开发中经常会遇到左边定宽,右边自适应的需求,特别是一些管理系统,比如左边显示信息或操作列表,右边显示详情,如下所示:、

 

 针对这种布局,首先抽象出页面结构如下:

 

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Document</title>
 6     <style>
 7         * {
 8             padding: 0;
 9             margin: 0;
10             color: #fff;
11             font-size: 30px;
12             font-weight: bold;
13             text-align: center;
14             box-sizing: border-box;
15         }
16         aside {
17             width: 200px;
18             height: 200px;
19             padding-top: 75px;
20             background: #5A6A94;
21         }
22         section {
23             height: 200px;
24             padding-top: 75px;
25             background: #BE4F4F;
26         }
27     </style>
28 </head>
29 <body>
30     <!-- 左边定宽 -->
31     <aside class="left">Left</aside>
32     <!-- 右边自适应 -->
33     <section class="right">Right</section>
34 </body>
35 </html>

 

 

浏览器中效果:

 

需要实现的效果如下:

 

那么针对这种常见的布局,方式是非常多的,下面给出几种比较简单和常见的方法。

 

方法一:左边设置左浮动,右边宽度设置100%

【分析】这样的方式简单得让我怀疑,但是效果上确实是实现了。

 

方法二 父容器设置 displayflexRight部分设置 flex

【分析】displayflex; 设置为弹性盒子,其子元素可以通过设置 flex 的数值来控制所占空间的比例。

 

方法三设置浮动 + css 中使用 calc() 函数

【分析】

1. 浮动。(注意:为了不影响其他元素,别忘了在父级上清除浮动)

2. calc() = calc(四则运算用于在 css 中动态计算长度值,需要注意的是,运算符前后都需要保留一个空格,例如:width: calc(100% - 10px)

3. vw viewport width1vw = viewport 宽度的 1%, 100vw = viewport width,

同样的还有 vh viewport height1vw = viewport 高度的 1% 100vh = viewport height

浏览器支持情况: 主流浏览器、IE10+ 

vw vh 会随着viewport 的变化而变化,因此十分适合于自适应场景来使用。

 

方法四:使用负margin

首先修改页面结构,为自适应部分添加容器 .container, 同时改变左右部分的位置,如下:

 

设置样式:

【分析】

1. 首先设置左边部分和右边部分左浮动,并为自适应部分(Right)设置宽度100%。此时的效果是这样的:

2. 设置左边部分左外边距为负100%,此时效果如下:

但是右边部分的宽度仍然为100%,部分内容被 Left 所覆盖。

3.  Right 部分添加左边距(即 Left 部分的宽度)

此时可以看到,Right 部分的内容居中显示了。

 

 

清除浮动的方式

在各种浏览器中显示效果也有可能不相同,这样让清除浮动更难了,下面总结8种清除浮动的方法,测试已通过 ie chrome firefox opera,需要的朋友可以参考下

清除浮动是每一个 web前台设计师必须掌握的机能。css清除浮动大全,共8种方法。 

浮动会使当前标签产生向上浮的效果,同时会影响到前后标签、父级标签的位置及 width height 属性。而且同样的代码,在各种浏览器中显示效果也有可能不相同,这样让清除浮动更难了。解决浮动引起的问题有多种方法,但有些方法在浏览器兼容性方面还有问题。 


下面总结8种清除浮动的方法(测试已通过 ie chrome firefox opera,后面三种方法只做了解就可以了): 

1
,父级div定义 height 
 

复制代码

代码如下:


<style type="text/css"> 
.div1{background:#000080;border:1px solid red;/*
解决代码*/height:200px;} 
.div2{background:#800080;border:1px solid red;height:100px;margin-top:10px} 
.left{float:left;width:20%;height:200px;background:#DDD} 
.right{float:right;width:30%;height:80px;background:#DDD} 
</style> 
<div class="div1"> 
<div class="left">Left</div> 
<div class="right">Right</div> 
</div> 
<div class="div2"> 
div2 
</div> 


原理:父级div手动定义height,就解决了父级div无法自动获取到高度的问题。 

优点:简单、代码少、容易掌握 

缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级div不一样时,会产生问题 

建议:不推荐使用,只建议高度固定的布局时使用 

2
,结尾处加空div标签 clear:both 
 

复制代码

代码如下:


<style type="text/css"> 
.div1{background:#000080;border:1px solid red} 
.div2{background:#800080;border:1px solid red;height:100px;margin-top:10px} 
.left{float:left;width:20%;height:200px;background:#DDD} 
.right{float:right;width:30%;height:80px;background:#DDD} 
/*
清除浮动代码*/ 
.clearfloat{clear:both} 
</style> 
<div class="div1"> 
<div class="left">Left</div> 
<div class="right">Right</div> 
<div class="clearfloat"></div> 
</div> 
<div class="div2"> 
div2 
</div> 


原理:添加一个空div,利用css提高的clear:both清除浮动,让父级div能自动获取到高度 

优点:简单、代码少、浏览器支持好、不容易出现怪问题 

缺点:不少初学者不理解原理;如果页面浮动布局多,就要增加很多空div,让人感觉很不好 

建议:不推荐使用,但此方法是以前主要使用的一种清除浮动方法 

3
,父级div定义 伪类:after zoom 
 

复制代码

代码如下:


<style type="text/css"> 
.div1{background:#000080;border:1px solid red;} 
.div2{background:#800080;border:1px solid red;height:100px;margin-top:10px} 
.left{float:left;width:20%;height:200px;background:#DDD} 
.right{float:right;width:30%;height:80px;background:#DDD} 
/*
清除浮动代码*/ 
.clearfloat:after{display:block;clear:both;content:"";visibility:hidden;height:0} 
.clearfloat{zoom:1} 
</style> 
<div class="div1 clearfloat"> 
<div class="left">Left</div> 
<div class="right">Right</div> 
</div> 
<div class="div2"> 
div2 
</div> 


原理:IE8以上和非IE浏览器才支持:after,原理和方法2有点类似,zoom(IE转有属性)可解决ie6,ie7浮动问题 

优点:浏览器支持好、不容易出现怪问题(目前:大型网站都有使用,如:腾迅,网易,新浪等等) 

缺点:代码多、不少初学者不理解原理,要两句代码结合使用才能让主流浏览器都支持。 

建议:推荐使用,建议定义公共类,以减少CSS代码。 

4
,父级div定义 overflow:hidden 
 

复制代码

代码如下:


<style type="text/css"> 
.div1{background:#000080;border:1px solid red;/*
解决代码*/width:98%;overflow:hidden} 
.div2{background:#800080;border:1px solid red;height:100px;margin-top:10px;width:98%} 
.left{float:left;width:20%;height:200px;background:#DDD} 
.right{float:right;width:30%;height:80px;background:#DDD} 
</style> 
<div class="div1"> 
<div class="left">Left</div> 
<div class="right">Right</div> 
</div> 
<div class="div2"> 
div2 
</div> 


原理:必须定义widthzoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度 

优点:简单、代码少、浏览器支持好 

缺点:不能和position配合使用,因为超出的尺寸的会被隐藏。 

建议:只推荐没有使用position或对overflow:hidden理解比较深的朋友使用。 

5
,父级div定义 overflow:auto 
 

复制代码

代码如下:


<style type="text/css"> 
.div1{background:#000080;border:1px solid red;/*
解决代码*/width:98%;overflow:auto} 
.div2{background:#800080;border:1px solid red;height:100px;margin-top:10px;width:98%} 
.left{float:left;width:20%;height:200px;background:#DDD} 
.right{float:right;width:30%;height:80px;background:#DDD} 
</style> 
<div class="div1"> 
<div class="left">Left</div> 
<div class="right">Right</div> 
</div> 
<div class="div2"> 
div2 
</div> 


原理:必须定义widthzoom:1,同时不能定义height,使用overflow:auto时,浏览器会自动检查浮动区域的高度 

优点:简单、代码少、浏览器支持好 

缺点:内部宽高超过父级div时,会出现滚动条。 

建议:不推荐使用,如果你需要出现滚动条或者确保你的代码不会出现滚动条就使用吧。 

6
,父级div 也一起浮动 
 

复制代码

代码如下:


<style type="text/css"> 
.div1{background:#000080;border:1px solid red;/*
解决代码*/width:98%;margin-bottom:10px;float:left} 
.div2{background:#800080;border:1px solid red;height:100px;width:98%;/*
解决代码*/clear:both} 
.left{float:left;width:20%;height:200px;background:#DDD} 
.right{float:right;width:30%;height:80px;background:#DDD} 
</style> 
<div class="div1"> 
<div class="left">Left</div> 
<div class="right">Right</div> 
</div> 
<div class="div2"> 
div2 
</div> 


原理:所有代码一起浮动,就变成了一个整体 

优点:没有优点 

缺点:会产生新的浮动问题。 

建议:不推荐使用,只作了解。 

7
,父级div定义 display:table 
 

复制代码

代码如下:


<style type="text/css"> 
.div1{background:#000080;border:1px solid red;/*
解决代码*/width:98%;display:table;margin-bottom:10px;} 
.div2{background:#800080;border:1px solid red;height:100px;width:98%;} 
.left{float:left;width:20%;height:200px;background:#DDD} 
.right{float:right;width:30%;height:80px;background:#DDD} 
</style> 
<div class="div1"> 
<div class="left">Left</div> 
<div class="right">Right</div> 
</div> 
<div class="div2"> 
div2 
</div> 


原理:将div属性变成表格 

优点:没有优点 

缺点:会产生新的未知问题。 

建议:不推荐使用,只作了解。 

8
,结尾处加 br标签 clear:both 
 

复制代码

代码如下:


<style type="text/css"> 
.div1{background:#000080;border:1px solid red;margin-bottom:10px;zoom:1} 
.div2{background:#800080;border:1px solid red;height:100px} 
.left{float:left;width:20%;height:200px;background:#DDD} 
.right{float:right;width:30%;height:80px;background:#DDD} 
.clearfloat{clear:both} 
</style> 
<div class="div1"> 
<div class="left">Left</div> 
<div class="right">Right</div> 
<br class="clearfloat" /> 
</div> 
<div class="div2"> 
div2 
</div> 


原理:父级div定义zoom:1来解决IE浮动问题,结尾处加 br标签 clear:both 

建议:不推荐使用,只作了解。

 

Js继承

大多OO语言都支持两种继承方式: 接口继承和实现继承 ,而ECMAScript中无法实现接口继承,ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现,下文给大家技术js实现继承的六种方式,需要的朋友参考下

 

前言:大多OO语言都支持两种继承方式: 接口继承和实现继承 ,而ECMAScript中无法实现接口继承,ECMAScript只支持实现继承,而且其实现继承主要是依靠 原型链 来实现。

1.原型链

基本思想:利用原型让一个引用类型继承另外一个引用类型的属性和方法。

构造函数,原型,实例之间的关系:每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

原型链实现继承例子:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

function SuperType() {

this.property = true;

}

SuperType.prototype.getSuperValue = function() {

return this.property;

}

function subType() {

this.property = false;

}

//继承了SuperType

SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function (){

return this.property;

}

var instance = new SubType();

console.log(instance.getSuperValue());//true

2.借用构造函数

基本思想:在子类型构造函数的内部调用超类构造函数,通过使用call()apply()方法可以在新创建的对象上执行构造函数。

例子:

?

1

2

3

4

5

6

7

8

9

10

11

function SuperType() {

this.colors = ["red","blue","green"];

}

function SubType() {

SuperType.call(this);//继承了SuperType

}

var instance1 = new SubType();

instance1.colors.push("black");

console.log(instance1.colors);//"red","blue","green","black"

var instance2 = new SubType();

console.log(instance2.colors);//"red","blue","green"

3.组合继承

基本思想:将原型链和借用构造函数的技术组合在一块,从而发挥两者之长的一种继承模式。

例子:

?

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

function SuperType(name) {

this.name = name;

this.colors = ["red","blue","green"];

}

SuperType.prototype.sayName = function() {

console.log(this.name);

}

function SubType(name, age) {

SuperType.call(this,name);//继承属性

this.age = age;

}

//继承方法

SubType.prototype = new SuperType();

Subtype.prototype.constructor = Subtype;

Subtype.prototype.sayAge = function() {

console.log(this.age);

}

var instance1 = new SubType("EvanChen",18);

instance1.colors.push("black");

consol.log(instance1.colors);//"red","blue","green","black"

instance1.sayName();//"EvanChen"

instance1.sayAge();//18

var instance2 = new SubType("EvanChen666",20);

console.log(instance2.colors);//"red","blue","green"

instance2.sayName();//"EvanChen666"

instance2.sayAge();//20

4.原型式继承

基本想法:借助原型可以基于已有的对象创建新对象,同时还不必须因此创建自定义的类型。

原型式继承的思想可用以下函数来说明:

?

1

2

3

4

5

function object(o) {

function F(){}

F.prototype = o;

return new F();

}

例子:

?

1

2

3

4

5

6

7

8

9

10

11

var person = {

name:"EvanChen",

friends:["Shelby","Court","Van"];

};

var anotherPerson = object(person);

anotherPerson.name = "Greg";

anotherPerson.friends.push("Rob");

var yetAnotherPerson = object(person);

yetAnotherPerson.name = "Linda";

yetAnotherPerson.friends.push("Barbie");

console.log(person.friends);//"Shelby","Court","Van","Rob","Barbie"

ECMAScript5通过新增Object.create()方法规范化了原型式继承,这个方法接收两个参数:一个用作新对象原型的对象和一个作为新对象定义额外属性的对象。

?

1

2

3

4

5

6

7

8

9

10

11

var person = {

name:"EvanChen",

friends:["Shelby","Court","Van"];

};

var anotherPerson = Object.create(person);

anotherPerson.name = "Greg";

anotherPerson.friends.push("Rob");

var yetAnotherPerson = Object.create(person);

yetAnotherPerson.name = "Linda";

yetAnotherPerson.friends.push("Barbie");

console.log(person.friends);//"Shelby","Court","Van","Rob","Barbie"

5.寄生式继承

基本思想:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真正是它做了所有工作一样返回对象。

例子:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

function createAnother(original) {

var clone = object(original);

clone.sayHi = function () {

alert("hi");

};

return clone;

}

var person = {

name:"EvanChen",

friends:["Shelby","Court","Van"];

};

var anotherPerson = createAnother(person);

anotherPerson.sayHi();///"hi"

6.寄生组合式继承

基本思想:通过借用函数来继承属性,通过原型链的混成形式来继承方法

其基本模型如下所示:

?

1

2

3

4

5

function inheritProperty(subType, superType) {

var prototype = object(superType.prototype);//创建对象

prototype.constructor = subType;//增强对象

subType.prototype = prototype;//指定对象

}

例子:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

function SuperType(name){

this.name = name;

this.colors = ["red","blue","green"];

}

SuperType.prototype.sayName = function (){

alert(this.name);

};

function SubType(name,age){

SuperType.call(this,name);

this.age = age;

}

inheritProperty(SubType,SuperType);

SubType.prototype.sayAge = function() {

alert(this.age);

}

以上内容给大家介绍了javascript实现继承的六种方式,希望对大家有所帮助!

1.js原型(prototype)实现继承

代码如下

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

<body>

<script type="text/javascript">

 function Parent(name,age){

   this.name=name;

   this.age=age;

   this.sayHi=function(){

    alert("Hi, my name is "+this.name+", my age is "+this.age);

   }

  }

//Child继承Parent

  function Child(grade){

   this.grade=grade;

   this.sayGrade=function(){

    alert("My grade is "+this.grade);

   }

  }

  Child.prototype=new Parent("小明","10");///

  var chi=new Child("5");

  chi.sayHi();

  chi.sayGrade();

</script>

</body>

2.构造函数实现继承 

代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

<body>

<script type="text/javascript">

 function Parent(name,age){

   this.name=name;

   this.age=age;

   this.sayHi=function(){

    alert("Hi, my name is "+this.name+", my age is "+this.age);

   }

  }

//Child继承Parent

  function Child(name,age,grade){

   this.grade=grade;

   this.sayHi=Parent;///

   this.sayHi(name,age);

   this.sayGrade=function(){

    alert("My grade is "+this.grade);

   }

  }

  var chi=new Child("小明","10","5");

  chi.sayHi();

  chi.sayGrade();

</script>

</body>

3.call , apply实现继承         -----很方便!

代码如下:

?

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

<body>

<script type="text/javascript">

 function Parent(name,age){

   this.name=name;

   this.age=age;

   this.sayHi=function(){

    alert("Hi, my name is "+this.name+", my age is "+this.age);

   }

  }

  function Child(name,age,grade){

   this.grade=grade;

   // Parent.call(this,name,age);///

   // Parent.apply(this,[name,age]);/// 都可

   Parent.apply(this,arguments);///

   this.sayGrade=function(){

    alert("My grade is "+this.grade);

   }

  // this.sayHi=function(){

   //  alert("Hi, my name is "+this.name+", my age is "+this.age+",My grade is "+this.grade);

   // }

  }

  var chi=new Child("小明","10","5");

  chi.sayHi();

  chi.sayGrade();

</script>

</body>

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!

 

怎么去除url地址的参数

javascript 删除 url 中指定参数,并返回 url

前言

在之前写了一篇博文javascript 操作 url  search 部分方法函数》.在这篇博文里面,我们通过写好的函数可以对url中的各种参数进行查询,设置.唯独,忘记了删除.

而今天就是遇到要删除某个参数的问题.郁闷,于是,写了这个函数.

实现代码

// 删除url中某个参数,并跳转
function funcUrlDel(name){
    var loca = window.location;
    var baseUrl = loca.origin + loca.pathname + "?";
    var query = loca.search.substr(1);
    if (query.indexOf(name)>-1) {
        var obj = {}
        var arr = query.split("&");
        for (var i = 0; i < arr.length; i++) {
            arr[i] = arr[i].split("=");
            obj[arr[i][0]] = arr[i][1];
        };
        delete obj[name];
        var url = baseUrl + JSON.stringify(obj).replace(/[\"\{\}]/g,"").replace(/\:/g,"=").replace(/\,/g,"&");
        return url
    };
}

功能:删除url中指定的参数,并返回删除参数后的完整url

使用方法

示例

url: http//xx/list?page=1&a=5

执行代码

funcUrlDel("page")

返回

http//xx/list?a=5

其他说明

会忽略 hash ,如果需要,自行加上即可.

使用jquery获取url以及使用jquery获取url参数是我们经常要用到的操作,下面通过文字说明加代码分析的形式给大家解析,具体详情请看下文。

1jquery获取url很简单,代码如下:

复制代码代码如下:


window.location.href;


 

其实只是用到了javascript的基础的window对象,并没有用jquery的知识。

2jquery获取url参数比较复杂,要用到正则表达式,所以学好javascript正则式多么重要的事情

首先看看单纯的通过javascript是如何来获取url中的某个参数:

?

1

2

3

4

5

6

//获取url中的参数

function getUrlParam(name) {

 var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象

 var r = window.location.search.substr(1).match(reg); //匹配目标参数

 if (r != null) return unescape(r[2]); return null; //返回参数值

}

 

通过这个函数传递url中的参数名就可以获取到参数的值,比如url

http://localhost:33064/WebForm2.aspx?reurl=WebForm1.aspx

我们要获取reurl的值,可以这样写:

复制代码代码如下:


var xx = getUrlParam('reurl');

明白了javascript获取url参数的方法,我们可以通过这个方法为jquery扩展一个方法来通过jquery获取url参数,下面的代码为jquery扩展了一个getUrlParam()方法

?

1

2

3

4

5

6

7

(function ($) {

  $.getUrlParam = function (name) {

   var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");

   var r = window.location.search.substr(1).match(reg);

   if (r != null) return unescape(r[2]); return null;

  }

 })(jQuery);

jquery扩展了这个方法了之后我们就可以通过如下方法来获取某个参数的值了:

  

复制代码代码如下:


 var xx = $.getUrlParam('reurl');

完整代码:

?

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

<script src="js/jquery-1.7.2.min.js" type="text/javascript"></script>

<script type="text/javascript">

 $(function () {

  //方法二:

  (function ($) {

   $.getUrlParam = function (name) {

    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");

    var r = window.location.search.substr(1).match(reg);

    if (r != null) return unescape(r[2]); return null;

   }

  })(jQuery);

  //方法二:

  var xx = $.getUrlParam('reurl');

  //方法一:

  // var xx = getUrlParam('reurl');

 

  alert(xx);

 });

 //方法一:

 //获取url中的参数

 function getUrlParam(name) {

  var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象

  var r = window.location.search.substr(1).match(reg); //匹配目标参数

  if (r != null) return unescape(r[2]); return null; //返回参数值

 }

</script>

2014-4-23 修改

今天在用上面的方法获取url中的参数时,url中传递的中文参数在解析的时候无论怎么测试,获取的都是乱码。经过一番调试后发现,我再传递参数时,对汉字编码使用的是 encodeURI ,而上面的方法在解析参数编码时使用的是unescape ,修改为 decodeURI 就可以了。

附: W3School中的介绍:

JavaScript unescape() 函数

unescape() 函数可对通过 escape() 编码的字符串进行解码。

参数

描述

string

必需。要解码或反转义的字符串。

说明

该函数的工作原理是这样的:通过找到形式为 %xx %uxxxx 的字符序列(x 表示十六进制的数字),用 Unicode 字符 \u00xx \uxxxx 替换这样的字符序列进行解码。

提示和注释

注释:ECMAScript v3 已从标准中删除了 unescape() 函数,并反对使用它,因此应该用 decodeURI() decodeURIComponent() 取而代之。

综上: javascript对参数编码解码方法要一致:

escape()   unescape()

encodeURI()   decodeURI()

encodeURIComponent()    decodeURIComponent() 

网上找的另一种javascript获取url中参数的方法:

?

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

<script language="JavaScript" type="text/javascript">

function GetUrlParms()

{

 var args=new Object();

 var query=location.search.substring(1);//获取查询串

 var pairs=query.split("&");//在逗号处断开

 for(var i=0;i<pairs.length;i++)

 {

  var pos=pairs[i].indexOf('=');//查找name=value

   if(pos==-1) continue;//如果没有找到就跳过

   var argname=pairs[i].substring(0,pos);//提取name

   var value=pairs[i].substring(pos+1);//提取value

   args[argname]=unescape(value);//存为属性

 }

 return args;

}

var args = new Object();

args = GetUrlParms();

//如果要查找参数key:

if(args["id"]!=undefined)

{

//如果要查找参数key:

var value1 = args["id"] ;

alert(value1);

}</script>

 jquery url参数和在url加参数

?

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

(function ($) {

 $.extend({

  Request: function (m) {

   var sValue = location.search.match(new RegExp("[\?\&]" + m + "=([^\&]*)(\&?)", "i"));

   return sValue ? sValue[1] : sValue;

  },

  UrlUpdateParams: function (url, name, value) {

   var r = url;

   if (r != null && r != 'undefined' && r != "") {

    value = encodeURIComponent(value);

    var reg = new RegExp("(^|)" + name + "=([^&]*)(|$)");

    var tmp = name + "=" + value;

    if (url.match(reg) != null) {

     r = url.replace(eval(reg), tmp);

    }

    else {

     if (url.match("[\?]")) {

      r = url + "&" + tmp;

     } else {

      r = url + "?" + tmp;

     }

    }

   }

   return r;

  }

 

 });

})(jQuery);

使用方法

dev.zhang/IOF.Signup/index_uscn_chs.html?act=1

1、取值使用

$.Request("act") = 1

2url加参数

$.UrlUpdateParams(window.location.href, "mid", 11111),

结果window.location.href?mid=11111

 

盒子居中

布局中经常会遇到让一个盒子水平且垂直居中的情况,以下总结了几种居中方法:

  1. margin固定宽高居中
  2. margin居中
  3. 绝对定位居中
  4. table-cell居中
  5. flex居中
  6. transform居中
  7. 不确定宽高居中(绝对定位百分数)
  8. button居中

不兼容IE低版本的可以用其他方法hack

不多说,直接上代码:
大多数方法的html都相同,所以写一个了,不同的再单独写出来。

demo中有代码和效果)

HTML:

<body>

    <div id="container">

        <div id="box"></div>

    </div>

</body>

  • margin固定宽高居中

这种定位方法,纯粹是靠宽高和margin拼出来的,不灵活。

CSS:

#container {

    width: 600px;

    height: 500px;

    border: 1px solid #000;

    margin: auto;

}

#box {

    width: 200px;

    height: 200px;

    margin: 150px 200px;

    background-color: #0ff;

}

点击查看demo

  • margin居中

利用负的margin来进行居中,需要知道固定宽高,限制比较大。

CSS:

#container {

    position: relative;

    width: 600px;

    height: 500px;

    border: 1px solid #000;

    margin: auto;

}

#box {

    position: absolute;

    width: 200px;

    height: 200px;

    left: 50%;

    top: 50%;

    margin: -100px -100px;

    background-color: #0ff;

}

点击查看demo

  • 绝对定位居中

利用绝对定位居中,非常常用的一种方法。

CSS:

#container {

    position: relative;

    width: 600px;

    height: 500px;

    border: 1px solid #000;

    margin: auto;

}

#box {

    position: absolute;

    width: 200px;

    height: 200px;

    left: 0;

    top: 0;

    right: 0;

    bottom: 0;

    margin: auto;

    background-color: #0ff;

}

点击查看demo

  • table-cell居中

利用table-cell来控制垂直居中。

CSS:

#container {

    display: table-cell;

    width: 600px;

    height: 500px;

    vertical-align: middle;

    border: 1px solid #000;

}

#box {

    width: 200px;

    height: 200px;

    margin: 0 auto;

    background-color: #0ff;

}

点击查看demo

  • flex居中

CSS3中引入的新布局方式,比较好用。缺点:IE9以及IE9一下不兼容。

CSS:

#container {

    display: -webkit-flex;

    display: flex;

    -webkit-align-items: center;

            align-items: center;

    -webkit-justify-content: center;

            justify-content: center;

    width: 600px;

    height: 500px;

    border: 1px solid #000;

    margin: auto;

}

#box {

    width: 200px;

    height: 200px;

    background-color: #0ff;

}

点击查看demo

  • transform居中

这种方法灵活运用CSStransform属性,较为新奇。缺点是IE9下不兼容。

CSS:

#container {

    position: relative;

    width: 600px;

    height: 600px;

    border: 1px solid #000;

    margin: auto;

}

#box {

    position: relative;

    top: 50%;

    left: 50%;

    width: 200px;

    height: 200px;

    transform: translate(-50%, -50%);

    -webkit-transform: translate(-50%, -50%);

    -ms-transform: translate(-50%, -50%);

    -moz-transform: translate(-50%, -50%);

    background-color: #0ff;

}

点击查看demo

  • 不确定宽高居中(绝对定位百分数)

这种不确定宽高的居中,较为灵活。只需要保证leftright的百分数一样就可以实现水平居中,保证topbottom的百分数一样就可以实现垂直居中。

CSS:

 #container {

    position: relative;

    width: 600px;

    height: 500px;

    border: 1px solid #000;

    margin: auto;

}

#box {

    position: absolute;

    left: 30%;

    right: 30%;

    top: 25%;

    bottom: 25%;

    background-color: #0ff;

}

点击查看demo

  • button居中

利用button做外容器,里边的块元素会自动垂直居中,只需要控制一下水平居中就可以达到效果。

HTML:

<button>

    <div></div>

</button>

CSS:

button {

    width: 600px;

    height: 500px;

    border: 1px solid #000;

}

div {

    width: 200px;

    height: 200px;

    margin: 0 auto;

    background-color: #0ff;

}

说到让一个div水平居中,立马想到最常用的就是margin:0 auto;但是这个的前提是必须知道盒子的宽度,盒子居中主要有两种情况:

一.确定盒子的宽度,解决办法有:

1.1 margin:0 auto;

1.2   position:relative;left:50%;margin-left:-0.5*width;(用绝对定位也可以)

二.不确定盒子宽度的,而且盒子宽度可变的,方法如下

2.1 position:relative:left:50%;transform:translateX(-50%);-webkit-transform:translateX(-50%);-moz-transform:translateX(-50%);//这里的50%是指盒子本身的50%;

2.2 width:fit-content;width:-moz-fit-content;width:-webket-fit-content;margin:auto;

1.第一种

利用margin,div1的宽减去div2的宽就是div2margin-left的数值:(100-40)/2=30

div1的高减去div2的高就是div2margin-top的数值:(100-40)/2=30

按 Ctrl+C 复制代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>demo</title>
    </head>
    <body>
        <style type="text/css">
            .div1{  width: 100px; height: 100px; border: 1px solid #000000;} 
            .div2{ width:40px ; height: 40px; background-color: green;}
            .div22{
                margin-left: 30px;margin-top: 30px;
            }
        </style>
        <div class="div1">
            <div class="div2 div22">
            </div>
        </div>
    </body>
</html>

 

第一种

第2种

利用css的 position属性,把div2相对于div1的top、left都设置为50%,然后再用margin-top设置为div2的高度的负一半拉回来,用marg-left设置为宽度的负一半拉回来,css如下设置

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>demo</title>
    </head>
    <body>
        <style type="text/css">
            .div1{  width: 100px; height: 100px; border: 1px solid #000000;} 
            .div2{ width:40px ; height: 40px; background-color: green;}
 
            .div11{
                position: relative;
            }
            .div22{
                position: absolute;top:50%;left: 50%;margin-top: -20px;margin-left: -20px;
            }
        </style>
 
        <div class="div1 div11">
            <div class="div2 div22">
 
            </div>
        </div>
 
    </body>
</html>

 

第二种

第三种

【】【】还是用css的position属性,如下的html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>demo</title>
    </head>
    <body>
        <style type="text/css">
            .div1{  width: 100px; height: 100px; border: 1px solid #000000;} 
            .div2{ width:40px ; height: 40px; background-color: green;}
 
            .div11{
                position: relative;
            }
            .div22{
                position: absolute;margin:auto; top: 0;left: 0;right: 0;bottom: 0;
            }
        </style>
 
        <div class="div1 div11">
            <div class="div2 div22">
 
            </div>
        </div>
 
    </body>
</html>

 

第三种

第四种

利用css3的新增属性table-cell, vertical-align:middle;

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>demo</title>
    </head>
    <body>
        <style type="text/css">
            .div1{  width: 100px; height: 100px; border: 1px solid #000000;} 
            .div2{ width:40px ; height: 40px; background-color: green;}
 
            .div11{
                display: table-cell;vertical-align: middle;
            }
            .div22{
                margin: auto;
            }
        </style>
 
        <div class="div1 div11">
            <div class="div2 div22">
            </div>
        </div>
 
    </body>
</html>

 

第四种

第五种方法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>demo</title>
    </head>
    <body>
        <style type="text/css">
            .div1{  width: 100px; height: 100px; border: 1px solid #000000;} 
            .div2{ width:40px ; background-color: green;}
 
            .div11{
                display: table-cell;vertical-align: middle;
            }
            .div22{
                margin: auto;
            }
        </style>
 
        <div class="div1 div11">
            <div class="div2 div22">
               div居中方法
            </div>
        </div>
 
    </body>
</html>

 

第五种方法

第六种方法

利用flexbox布局

直接在父元素上使用flexbox的布局

 <!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>demo</title>
    <style type="text/css">
        .div1 {
            width: 100px;
            height: 100px;
            border: 1px solid #000000;
        }
 
        .div2 {
            height: 40px;
            width: 40px;
            background-color: green;
        }
 
        .div11 {
            display: flex;
            /*!*flex-direction: column;*!可写可不写*/
            justify-content: center;
            align-items: center;
        }
 
    </style>
</head>
<body>
 
 
<div class="div1 div11">
    <div class="div2 div22">
 
    </div>
</div>
 
</body>
</html>

 

第六种方法

第七种方法

利用transform的属性,注意子绝父相定位

缺点:需要支持Html5

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>demo</title>
    <style type="text/css">
        body {
            margin: 100px auto;
            position: relative;
        }
 
        .div1 {
            width: 100px;
            height: 100px;
            border: 1px solid #000000;
            background-color: red;
        }
 
        .div2 {
            height: 40px;
            width: 40px;
            background-color: green;
        }
 
        .center {
            position: absolute;
            top: 50%;
            left: 50%;
            -ms-transform: translate(-50%, -50%);
            -moz-transform: translate(-50%, -50%);
            -o-transform: translate(-50%, -50%);
            transform: translate(-50%, -50%);
        }
 
    </style>
</head>
<body>
 
 
<div class="div1 center">
    我是外部盒子
    <div class="div2 center">
        我要居中
    </div>
</div>
</body>
</html>

 

第七种

第八种

两者都要固定定位,不常用

缺点:需要设置position属性,网页复杂时容易扰乱页面布局,而且只是元素的起始位置居中

<html>
<head>
    <meta charset="UTF-8">
    <title>demo</title>
    <style type="text/css">
 
 
        .div1 {
            width: 100px;
            height: 100px;
            border: 1px solid #000000;
            background-color: red;
            position: relative;
        }
 
        .div2 {
            height: 40px;
            width: 40px;
            background-color: green;
            margin:30px 30px;
 
        }
 
        .center{
            position: fixed;
            left: 50%;
        }
 
    </style>
</head>
<body>
 
 
<div class="div1 center">
   
    <div class="div2 center">
        我要居中
    </div>
</div>
</body>
</html>

 

第八种方法

 

Js实现eventHandler

js事件的监听器的使用



 

1、当同一个对象使用.onclick的写法触发多个方法的时候,后一个方法会把前一个方法覆盖掉,也就是说,在对象的onclick事件发生时,只会执行最后绑定的方法。而用事件监听则不会有覆盖的现象,每个绑定的事件都会被执行。如下:

[javascript] view plain copy

  1. <span style="font-size:18px;">window.onload = function(){  
  2.     var btn = document.getElementById("yuanEvent");  
  3.     btn.onclick = function(){  
  4.         alert("第一个事件");  
  5.     }  
  6.     btn.onclick = function(){  
  7.         alert("第二个事件");  
  8.     }  
  9.     btn.onclick = function(){  
  10.         alert("第三个事件");  
  11.     }  
  12. }</span>  

最后只输出:第三个事件,因为后一个方法都把前一个方法覆盖掉了。

原生态的事件绑定函数addEventListener:
 

[javascript] view plain copy

  1. var eventOne = function(){  
  2.     alert("第一个监听事件");  
  3. }  
  4. function eventTwo(){  
  5.     alert("第二个监听事件");  
  6. }  
  7. window.onload = function(){  
  8.     var btn = document.getElementById("yuanEvent");  
  9.     //addEventListener:绑定函数  
  10.     btn.addEventListener("click",eventOne);  
  11.     btn.addEventListener("click",eventTwo);  
  12. }  

输出:第一个监听事件 和 第二个监听事件

2、采用事件监听给对象绑定方法后,可以解除相应的绑定,写法如下:
 

[javascript] view plain copy

  1. var eventOne = function(){  
  2.     alert("第一个监听事件");  
  3. }  
  4. function eventTwo(){  
  5.     alert("第二个监听事件");  
  6. }  
  7. window.onload = function(){  
  8.     var btn = document.getElementById("yuanEvent");  
  9.     btn.addEventListener("click",eventOne);  
  10.     btn.addEventListener("click",eventTwo);  
  11.     btn.removeEventListener("click",eventOne);  
  12. }  

输出:第二个监听事件

3、解除绑定事件的时候一定要用函数的句柄,把整个函数写上是无法解除绑定的。
错误写法:
 

[javascript] view plain copy

  1. btn.addEventListener("click",function(){  
  2.     alert(11);  
  3. });  
  4. btn.removeEventListener("click",function(){  
  5.     alert(11);  
  6. });  

正确写法:
 

[javascript] view plain copy

  1. btn.addEventListener("click",eventTwo);  
  2. btn.removeEventListener("click",eventOne);  


 

总结:对函数进行封装后的监听事件如下,兼容各大主流浏览器。

[javascript] view plain copy

  1. /* 
  2.  * addEventListener:监听Dom元素的事件 
  3.  *   
  4.  *  target:监听对象 
  5.  *  type:监听函数类型,如click,mouseover 
  6.  *  func:监听函数 
  7.  */  
  8. function addEventHandler(target,type,func){  
  9.     if(target.addEventListener){  
  10.         //监听IE9,谷歌和火狐  
  11.         target.addEventListener(type, func, false);  
  12.     }else if(target.attachEvent){  
  13.         target.attachEvent("on" + type, func);  
  14.     }else{  
  15.         target["on" + type] = func;  
  16.     }   
  17. }  
  18. /* 
  19.  * removeEventHandler:移除Dom元素的事件 
  20.  *   
  21.  *  target:监听对象 
  22.  *  type:监听函数类型,如click,mouseover 
  23.  *  func:监听函数 
  24.  */  
  25. function removeEventHandler(target, type, func) {  
  26.     if (target.removeEventListener){  
  27.         //监听IE9,谷歌和火狐  
  28.         target.removeEventListener(type, func, false);  
  29.     } else if (target.detachEvent){  
  30.         target.detachEvent("on" + type, func);  
  31.     }else {  
  32.         delete target["on" + type];  
  33.     }  
  34. }  
  35. var eventOne = function(){  
  36.     alert("第一个监听事件");  
  37. }  
  38. function eventTwo(){  
  39.     alert("第二个监听事件");  
  40. }  
  41. window.onload = function(){  
  42.     var bindEventBtn = document.getElementById("bindEvent");  
  43.     //监听eventOne事件  
  44.     addEventHandler(bindEventBtn,"click",eventOne);  
  45.     //监听eventTwo事件  
  46.     addEventHandler(bindEventBtn,"click",eventTwo );  
  47.     //监听本身的事件  
  48.     addEventHandler(bindEventBtn,"click",function(){  
  49.         alert("第三个监听事件");  
  50.     });  
  51.     //取消第一个监听事件  
  52.     removeEventHandler(bindEventBtn,"click",eventOne);  
  53.     //取消第二个监听事件  
  54.     removeEventHandler(bindEventBtn,"click",eventTwo);  
  55. }  

[javascript] view plain copy

  1.   

实例:

[html] view plain copy

  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  5.         <title>Event</title>  
  6.         <script type="text/javascript">  
  7.             function addEventHandler(target,type,func){  
  8.                 if(target.addEventListener){  
  9.                     //监听IE9,谷歌和火狐  
  10.                     target.addEventListener(type, func, false);  
  11.                 }else if(target.attachEvent){  
  12.                     target.attachEvent("on" + type, func);  
  13.                 }else{  
  14.                     target["on" + type] = func;  
  15.                 }   
  16.             }  
  17.             function removeEventHandler(target, type, func) {  
  18.                 if (target.removeEventListener){  
  19.                     //监听IE9,谷歌和火狐  
  20.                     target.removeEventListener(type, func, false);  
  21.                 } else if (target.detachEvent){  
  22.                     target.detachEvent("on" + type, func);  
  23.                 }else {  
  24.                     delete target["on" + type];  
  25.                 }  
  26.             }  
  27.             var eventOne = function(){  
  28.                 alert("第一个监听事件");  
  29.             }  
  30.             function eventTwo(){  
  31.                 alert("第二个监听事件");  
  32.             }  
  33.             window.onload = function(){  
  34.                 var bindEventBtn = document.getElementById("bindEvent");  
  35.                 //监听eventOne事件  
  36.                 addEventHandler(bindEventBtn,"click",eventOne);  
  37.                 //监听eventTwo事件  
  38.                 addEventHandler(bindEventBtn,"click",eventTwo );  
  39.                 //监听本身的事件  
  40.                 addEventHandler(bindEventBtn,"click",function(){  
  41.                     alert("第三个监听事件");  
  42.                 });  
  43.                 //取消第一个监听事件  
  44.                 removeEventHandler(bindEventBtn,"click",eventOne);  
  45.                 //取消第二个监听事件  
  46.                 removeEventHandler(bindEventBtn,"click",eventTwo);  
  47.             }  
  48.         </script>  
  49.   
  50.   
  51.     </head>  
  52.     <body>  
  53.         <input type="button" value="测试" id="bindEvent">  
  54.         <input type="button" value="测试2" id="yuanEvent">  
  55.     </body>  
  56. </html>  

js事件(Event)知识整理

转载  2012-10-11   作者:     我要评论

事件(Event)知识整理,本文由网上资料整理而来,需要的朋友可以参考下

 

鼠标事件 

鼠标移动到目标元素上的那一刻,首先触发mouseover 
之后如果光标继续在元素上移动,则不断触发mousemove 
如果按下鼠标上的设备(左键,右键,滚轮……),则触发mousedown 
当设备弹起的时候触发mouseup 
目标元素的滚动条发生移动时(滚动滚轮/拖动滚动条。。)触发scroll 
滚动滚轮触发mousewheel,这个要区别于scroll 
鼠标移出元素的那一刻,触发mouseout 

事件注册 

平常我们绑定事件的时候用dom.onxxxx=function(){}的形式 
这种方式是给元素的onxxxx属性赋值,只能绑定有一个处理句柄。 
但很多时候我们需要绑定多个处理句柄到一个事件上,而且还可能要动态的增删某个处理句柄 
下面的事件注册方式就能解决这个需求。 

先介绍一下四个方法 

复制代码代码如下:


//IE以外 
target.addEventListener(type,listener,useCapture) 
target.removeEventListener(type,listener,useCapture); 
target
:文档节点、documentwindow XMLHttpRequest 
type
:字符串,事件名称,不含“on”,比如“click”“mouseover”“keydown”等。 
listener
:实现了 EventListener 接口或者是 JavaScript 中的函数。 
useCapture
:是否使用捕捉,一般用 false 
//IE 
target.attachEvent(type, listener); 
target.detachEvent(type, listener); 
target
:文档节点、documentwindow XMLHttpRequest 
type
:字符串,事件名称,含“on”,比如“onclick”“onmouseover”“onkeydown”等。 
listener
:实现了 EventListener 接口或者是 JavaScript 中的函数。 
两者使用的原理:可对执行的优先级不一样,实例讲解如下: 
ele.attachEvent("onclick",method1); 
ele.attachEvent("onclick",method2); 
ele.attachEvent("onclick",method3); 

执行顺序为method3->method2->method1 
ele.addEventListener("click",method1,false); 
ele.addEventListener("click",method2,false); 
ele.addEventListener("click",method3,false); 

执行顺序为method1->method2->method3 
兼容后的方法 
var func = function(){}; 
//
例:addEvent(window,"load",func) 
function addEvent(elem, type, fn) { 
if (elem.attachEvent) { 
elem.attachEvent('on' + type, fn); 
return; 

if (elem.addEventListener) { 
elem.addEventListener(type, fn, false); 


//
例:removeEvent(window,"load",func) 
function removeEvent(elem, type, fn) { 
if (elem.detachEvent) { 
elem.detachEvent('on' + type, fn); 
return; 

if (elem.removeEventListener) { 
elem.removeEventListener(type, fn, false); 


获取事件对象和事件源(触发事件的元素

复制代码代码如下:


function eventHandler(e){ 
//
获取事件对象 
e = e || window.event;//IE
Chrome下是window.event FF下是
//
获取事件源 
var target = e.target || e.srcElement;//IE
Chrome下是srcElement FF下是target 


取消事件默认行为(例如点击一个<a>后不跳转页面而是执行一个函数

复制代码代码如下:


function eventHandler(e) { 
e = e || window.event; 
//
防止默认行为 
if (e.preventDefault) { 
e.preventDefault();//IE
以外 
} else { 
e.returnValue = false;//IE 
//
注意:这个地方是无法用return false代替的 
//return false
只能取消元素 


阻止事件冒泡 

复制代码代码如下:


function myParagraphEventHandler(e) { 
e = e || window.event; 
if (e.stopPropagation) { 
e.stopPropagation();//IE
以外 
} else { 
e.cancelBubble = true;//IE 



事件委托 

例如,你有一个很多行的大表格,在每个<tr>上绑定点击事件是个非常危险的想法,因为性能是个大问题。流行的做法是使用事件委托。 

事件委托描述的是将事件绑定在容器元素上,然后通过判断点击的target子元素的类型来触发相应的事件。 
事件委托依赖于事件冒泡,如果事件冒泡到table之前被禁用的话,那以下代码就无法工作了。 

复制代码代码如下:


myTable.onclick = function () { 
e = e || window.event; 
var targetNode = e.target || e.srcElement; 
//
测试如果点击的是TR就触发 
if (targetNode.nodeName.toLowerCase() === 'tr') { 
alert('You clicked a table row!'); 



事件(Event)知识整理(

事件流 

DOM同时支持两种事件模型:捕获型事件和冒泡型事件 
并且每当某一事件发生时,都会经过捕获阶段->处理阶段->冒泡阶段(有些浏览器不支持捕获

捕获阶段是由上层元素到下层元素的顺序依次。而冒泡阶段则正相反。 

如下图 


当事件触发时body会先得到有事件发生的信息,然后依次往下传递,直到到达最详细的元素。这就是事件捕获阶段。 
还记得事件注册方法ele.addEventListener(type,handler,flag)吧,Flag是一个Boolean值,true表示事件捕捉阶段执行,false表示事件冒泡阶段执行。 
接着就是事件冒泡阶段。从下往上 依次执行事件处理函数(当然前提是当前元素为该事件注册了事件句柄) 
在这个过程中,可以阻止事件的冒泡,即停止向上的传递。 
阻止冒泡有时是很有必要的,例如 

复制代码代码如下:


<div οnclick=funcA()> 
<button οnclick=funcB()>Click</button> 
</div> 



本意是如果点击div中按钮以外的位置时执行funcA,点击button时执行funcB。但是实际点击button时就会先后执行funcB,funcA 
而如果在button的事件句柄中阻止冒泡的话,div就不会执行事件句柄了。

 

组合构造

JS中创建对象有很多种方法,而创建自定义类型的最常见的方式,就是使用组合使用构造函数模式和原型模式创建对象。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性,那么来看看为什么这种方式是最常用的。 
先简单介绍在JS中创建对象的方式有如下几种:

  • 工厂模式
  • 构造函数模式
  • 原型模式
  • 组合使用构造函数模式和原型模式
  • 动态原型模式
  • 寄生构造函数模式
  • 稳妥构造函数模式

依次来看:

  1. 工厂模式 
    这种模式就是抽象了创建具体对象的过程,也是最基本的一种设计模式,就像下面这样咯:

function createPerson(name,age,gender){

    var obj = new Object();

    obj.name = name;

    obj.age = age;

    obj.gender = gender;

    obj.sayName = function(){

        alert(this.name);

    };

    return obj;

}

//接下来就可以创建对象了var person = createPerson("Stan",0000,"male");

如果创建多个这种类似的对象,当然很ok啦,但是有更好的模式创建对象。 
2.
构造函数模式

function Person(name,age,gender){

    this.name = name;

    this.age = age;

    this.gender = gender;

    this.sayName = function(){

        alert(this.name);

    };

}

//然后可以用new操作符来创建Person的新实例

var person = new Person("Stan",0000,"male");

//最直观的就是代码比工厂模式少吧。

//另外,创建自定义的构造函数意味着将来可以将它的实例标识为一种特定类型,这是构造函数模式胜过工厂模式的地方(努力理解中。)

//也可以像下面这种创建并调用

Person("Stan",0000,"male");

window.sayName();

//或是在另一个对象的作用域中调用

var obj = new Object();

Person.call(obj,"Stan",0000,"male");

obj.sayName();

//这里是在obj对象的作用域中调用Person(),因此调用后obj就拥有了所有属性和sayName()方法

这里说说构造函数模式的问题,定义在构造函数中的方法在每次实例化的时候都会被创建一次,并且每次被创建的方法都是一个新的对象(JS中函数即对象),即创建两个完成同样任务的Function实例是没有必要的,也就是说,如果一个方法可以被共享使用的话,不应该这么做。如果写成下面这样:

function Person(name,age,gender){

    this.name = name;

    this.age = age;

    this.gender = gender;

    this.sayName = sayName;

}

function sayName(){

    alert(this.name);

}

这样把sayName()定义成全局函数,虽然解决了多个函数做同一样件事情而不用每次创建的问题,但是假如需要N个全局函数,那么我们这个自定义的引用类型就没有丝毫的封装性可言了。所以有更好的原型模式可以解决这个问题

3.原型模式 
我们创建的每个函数都 一个prototype属性,这个属性是一个指针,指向一个对象(原型对象),使用原型对象的好处是不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。就像下面这样:

function Person(){}

 

Person.prototype.name = "Stan";

Person.prototype.age = 0000;

Person.prototype.gender = "male";

Person.prototype.sayName = function(){

    alert(this.name);

}

 

var person = new Person();

person.sayName();

//原型对象中的所有属性和方法都是可以被实例所共享的

当我们在调用person.sayName()方法时,会先后执行两次搜索,先从对象实例本身开始,如果在实例中找到该方法,则调用 ,若没有找到,会继续搜索指针指向的原型对象,找到则调用方法。有一个问题,如果我们在实例中添加一个属性,而该属性与实例原型中的一个属性同名,该属性将会屏蔽掉原型中的那个属性,就像下面这样:

function Person(){}

 

Person.prototype.name = "Stan";

 

var person = new Person();

person.name = "Joe";

alert(person.name);//结果是Joe

即使将这个name属性设置为null,也只会在实例中设置这个属性,而不会恢复其指向原型的连接 。可以使用delete操作符完全的删除实例属性,从而可以重新访问到原型中的属性。像下面这样:

function Person(){}

 

Person.prototype.name = "Stan";

 

var person = new Person();

person.name = null;

alert(person.name);//结果是null,而不是Stan

 

//可以这样做:

delete person.name;

alert(person.name);

另外还可以把原型语法像下面这样写:

function Person(){}

 

Person.prototype = {

    name : "Stan",

    age : 0000,

    gender : "male",

    sayName : function(){

        alert(this.name);

    }

};

这种写法实际上是重写了原型对象,所以接下来看一个问题,即原型的动态性 
所谓的原型的动态性,即随时可以为原型添加属性和方法,并且修改能够立即在所有对象实例中反映出来,像下面这样:

function Person(){}

 

var person  = new Person();

Person.prototype.name = "Stan";

alert(person.name);

虽然person实例是在添加新属性之前创建的,但是仍然可以立即在实例中访问到name属性,但是如果全部重写了原型对象,就会出问题了,像下面这样:

function Person(){}

 

var person  = new Person();

Person.prototype = {

    name : "Stan",

    age : 0000,

    gender : "male",

    sayName : function(){

        alert(this.name);

    }

};

alert(person.name);//undefined

这是为什么呢?因为重写原型切断了现有原型(重写后的原型)与任何之前已经存在的对象实例之间的联系,person引用的仍然是最初的原型,这里person实例最初的原型中除了默认的一些属性外,是没有name属性的,所以就会undefined咯!

原型对象看似还可以,但它也是有问题的,什么问题呢,就是其共享的本性,分析下,原型中所有属性是被很多实例共享的,这种共享对于函数非常合适,对于那些包含基本值的属性也还行,因为我们还可以通过在实例上添加一个同名属性来隐藏掉原型中的对应属性(不会影响到其它的实例的属性),但是如果包含引用类型值的属性来说,问题就来了,看下面:

function Person(){}

 

Person.prototype = {

    colors : ["red","green","pink"]

};

 

var person1 = new Person();

person1.colors.push("black");

 

var person2 = new Person();

alert(person2.colors); // red,green,pink,black

看到问题了吧,大多数时候,实例一般都是要属于自己的全部属性的,即我们不会这么单独使用原型模式,所以这才到今天我们要说的主题:组合使用构造函数模式和原型模式创建对象 
怎么组合呢,其实就是用构造函数模式定义实例属性(不会被共享),而用原型模式用于定义方法和共享的属性,另外这种组合模式还支持向构造函数传递参数,像下面这样:

function Person(name,age,gender){

    this.name = name;

    this.age = age;

    this.gender = gender;

    this.colors = ["red","green","pink"];

}

Person.prototype = {

    sayName : function(){

        alert(this.name);

    }

}

 

var person1 = new Person("Stan",0000,"male");

var person2 = new Person("Joe",1111,"female");

 

person1.colors.push("black");

alert(person1.colors); // red,green,pink,black

alert(person2.colors); // red,green,pink

alert(person1.sayName == person2.sayName); // true

先说到这里吧。

 

判断数组类型

这么基础的东西实在不应该再记录了,不过嘛,温故知新~就先从数据类型开始吧

js六大数据类型:numberstringobjectBooleannullundefined

string 由单引号或双引号来说明,如"string"

number:什么整数啊浮点数啊都叫数字,你懂的~

Boolean: 就是truefalse

undefined:未定义,就是你创建一个变量后却没给它赋值~

null: 故名思久,null就是没有,什么也不表示

object: 这个我也很难解释的说。就是除了上面五种之外的类型

--------------------上面的都是浮云,下面的才是神马------------------------------

数据类型判断之 typeof

typeof可以解决大部分的数据类型判断,是一个一元运算,放在一个运算值之前,其返回值为一个字符串,该字符串说明运算数的类型,所以判断某个是否为String类型,可以直接 if(typeof(你的值) == "string"){}

以下是各种数据类型返回结果:

?

1

2

3

4

5

6

7

8

9

10

var a="string"; console.log(a); //string

var a=1; console.log(a); //number

var a=false; console.log(a); //boolean

var a; console.log(typeof a); //undfined

 

var a = null; console.log(typeof a); //object

var a = document; console.log(typeof a); //object

var a = []; console.log(a); //object

 

var a = function(){}; console.log(typeof a) //function 除了可以判断数据类型还可以判断function类型

这样一来就很明显了,除了前四个类型外,null、对象、数组返回的都是object类型;

对于函数类型返回的则是function,再比如typeof(Date)typeof(eval)等。

然后这里就可以再引申出另一个灰常热门并且解决方法已普遍存在的问题,如何判断数据是个数组类型?

---------------------------------------其实这才是我的目的,咩~----------------------------------------------

js判断数组类型的方法

方法一之 instanceof

instance,故名思义,实例,例子,所以instanceof 用于判断一个变量是否某个对象的实例,是一个三目运算式---typeof最实质上的区别

a instanceof b?alert("true"):alert("false")  //注意b值是你想要判断的那种数据类型,不是一个字符串,比如Array

举个栗子:

?

1

2

var a=[];

console.log(a instanceof Array) //返回true

方法二之 constructor

W3C定义中的定义:constructor 属性返回对创建此对象的数组函数的引用

就是返回对象相对应的构造函数。从定义上来说跟instanceof不太一致,但效果都是一样的

: (a instanceof Array)   //a是否Array的实例?true or false

   (a.constructor == Array)  // a实例所对应的构造函数是否为Array? true or false

举个栗子:

?

1

2

3

4

5

6

7

8

function employee(name,job,born){

 this.name=name;

 this.job=job;

 this.born=born;

}

 

var bill=new employee("Bill Gates","Engineer",1985);

console.log(bill.constructor); //输出function employee(name, jobtitle, born){this.name = name; this.jobtitle = job; this.born = born;}

那么判断各种类型的方法就是:

?

1

2

3

4

5

console.log([].constructor == Array);

console.log({}.constructor == Object);

console.log("string".constructor == String);

console.log((123).constructor == Number);

console.log(true.constructor == Boolean);

-------------------------------------以下不是原创--------------------------------------

较为严谨并且通用的方法:

?

1

2

3

4

function isArray(object){

 return object && typeof object==='object' &&

   Array == object.constructor;

}

!!注意:

使用instaceofconstrucor,被判断的array必须是在当前页面声明的!比如,一个页面(父页面)有一个框架,框架中引用了一个页面(子页面),在子页面中声明了一个array,并将其赋值给父页面的一个变量,这时判断该变量,Array == object.constructor;会返回false

原因:

1array属于引用型数据,在传递过程中,仅仅是引用地址的传递。
2、每个页面的Array原生对象所引用的地址是不一样的,在子页面声明的array,所对应的构造函数,是子页面的Array对象;父页面来进行判断,使用的Array并不等于子页面的Array;切记,不然很难跟踪问题!

方法三之 特性判断法

以上方法均有一定的缺陷,但要相信人民大众的智慧是无所不能及的,我们可根据数组的一些特性来判断其类型

?

1

2

3

4

5

6

7

function isArray(object){

 return object && typeof object==='object' &&

   typeof object.length==='number' &&

   typeof object.splice==='function' &&

    //判断length属性是否是可枚举的 对于数组 将得到false

   !(object.propertyIsEnumerable('length'));

}

lengthsplice并不一定是数组,因为可以为对象添加属性,而不能枚举length属性,才是最重要的判断因子。

ps: 在这里普及下 propertyIsEnumerable 方法:

object. propertyIsEnumerable(proName)

判断指定的属性是否可列举

备注:如果 proName 存在于 object 中且可以使用一个 For…In 循环穷举出来,那么 propertyIsEnumerable 属性返回 true。如果 object 不具有所指定的属性或者所指定的属性不是可列举的,那么 propertyIsEnumerable 属性返回 false

propertyIsEnumerable 属性不考虑原型链中的对象。

示例:

?

1

2

var a = new Array("apple", "banana", "cactus");

document.write(a.propertyIsEnumerable(1));

方法四之 最简单的方法

?

1

2

3

function isArray(o) {

 return Object.prototype.toString.call(o) === ‘[object Array]‘;

}

以上就是本文的全部内容,了解更多JavaScript的语法,大家可以查看:《JavaScript 参考教程》、《JavaScript代码风格指南》,也希望大家多多支持脚本之家。

 

怎么区分数组和对象

判断一个变量类型是数组还是对象

  因为无论是数组还是对象,对于typeof的操作返回值都为object,所以就有了区分数组类型和对象类型的需要:

方一:通过length属性:一般情况下对象没有length属性值,其值为undefiend,而数组的length值为number类型

  缺点:非常不实用,当对象的属性存在length,且其值为number(比如类数组),则该方法失效,不建议使用,看看即可。

*方二:通过instanceof来判断区分

  

 

        var arr = [1, 2, 3];
        var obj = {
            name: 'lyl',
            age: 18,
            1: 'name'
        }
        console.log(arr instanceof Array); //true
        console.log(obj instanceof Array); //false

 

*方三:通过constructor

  

 

     var arr = [1, 2, 3];
        var obj = {
            name: 'lyl',
            age: 18,
            1: 'name'
        }
        console.log(arr.constructor === Array); //true
        console.log(obj.constructor === Array); //false

 

*方四:通过toString()方法,数组原型和对象原型定义的toString()方法不同

  原理参考:http://wwwblogs/ziyunfei/archive/2012/11/05/2754156.html

  

 

     var arr = [1, 2, 3];
        var obj = {
            name: 'lyl',
            age: 18,
            1: 'name'
        }
        console.log(Object.prototype.toString.call(arr) === '[object Array]'); //true
        console.log(Object.prototype.toString.call(boj) === '[object Array]'); //false

 

 

方五:随便找一个数组仅有的方法,来判断数组和对象谁有该方法即可(样例以sort来举例)

  

 

     var arr = [1, 2, 3];
        var obj = {
            name: 'lyl',
            age: 18,
            1: 'name'
        }

  
        console.log(arr.sort === Array.prototype.sort); //true
        console.log(obj.sort === Array.prototype.sort); //false

 

 

  

   总结:方法应用权重:

    优先使用方四toString,因为该方法几乎无缺陷。

    次之可以使用方二instanceof和方三constructor

    剩下的方法玩玩即可,不实用

判断objectName是否是数组

1、objectName instanceof Array

2、objectName.constructor == Array

基本数据类型也可以使用此方法。

(123).constructor == Number // true
  • 1

12判断有误差。 
a)
在不同 iframe 中创建的 Array 并不共享 prototype 
b)
即使为true,也有可能不是数组。 
function SubArray(){ 

SubArray.prototype = []; 
myArray = new SubArray; 
alert(myArray instanceof Array)

3、特性判断

a)length 
b)splice 
c)length
不可枚举

    function isArray(object){
    return  object && typeof object==='object' &&    
            typeof object.length==='number' &&  
            typeof object.splice==='function' &&    
             //判断length属性是否是可枚举的 对于数组 将得到false  
            !(object.propertyIsEnumerable('length'));
}

lengthsplice并不一定是数组,因为可以为对象添加属性,而不能枚举length属性,才是最重要的判断因子。

4、Array.isArray(objectName);

ES5方法

5、Object.prototype.toString.call(objectName)

获取this对象的[[Class]]属性的值.[Class]]是一个内部属性,所有的对象都拥有该属性. 表明该对象的类型 
Object.prototype.toString.call(objectName) === ‘[object Array]‘;

 

Js数据类型

js的基本数据类型有哪些?

ECMAScript中有5中简单数据类型(也称为基本数据类型)UndefinedNullBooleanNumberString。还有1中复杂的数据类型————ObjectObject本质上是由一组无序的名值对组成的。

其中UndefinedNullBooleanNumber都属于基本类型。ObjectArrayFunction则属于引用类型,String有些特殊,具体的会在下面展开分析。

变量

ECMAScript中用var关键字来定义变量,因为js是弱类型的,所以无法确定变量一定会存储什么值,也就不知道变量到底会是什么类型,而且变量的类型可以随时改变。

这就是ECMAScript是松散类型的来由,所谓松散类型就是可以用来保存任何类型的数据。

ps:
es6中新增了let命令来声明变量、const命令声明一个只读的常量。

let的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

const一旦声明,常量的值就不能改变。

关于letconst这里不做展开讨论,可以参考 阮一峰 - ECMAScript 6 入门

typeof 操作符

由于js中的变量是松散类型的,所以它提供了一种检测当前变量的数据类型的方法,也就是typeof关键字.
通过typeof关键字,对这5种数据类型会返回下面的值(以字符串形式显示)
undefined ---------- 如果值未定义 Undefined

boolean ---------- 如果这个值是布尔值 Boolean

string ---------- 如果这个值是字符串 String

number ---------- 如果这个值是数值类型 Number

object ---------- 如果这个值是对象或null Object

需要注意的是typeof null返回为object,因为特殊值null被认为是一个空的对象引用。

Undefined

Undefined类型只有一个值,即特殊的undefined。在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined。不过,一般建议尽量给变量初始化,但是在早期的js版本中是没有规定undefined这个值的,所以在有些框架中为了兼容旧版浏览器,会给window对象添加undefined值。

window['undefined'] = window['undefined'];  
//或者
window.undefined = window.undefined;  

Null

Null类型是第二个只有一个值的数据类型,这个特殊的值是null。从逻辑角度来看,null值表示一个空对象指针,而这也正是使用typeof操作符检测null时会返回object的原因。

  var car = null;
  console.log(typeof car); // "object"

如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为null而不是其他值。这样一来,只要直接检测null值就可以知道相应的变量是否已经保存了一个对象的引用了。
例如:

  if(car != null){
    //对car对象执行某些操作
  }

实际上,undefined值是派生自null值的,因此ECMA-262规定对它们的相等性测试要返回true

console.log(undefined == null); //true

尽管nullundefined有这样的关系,但它们的用途完全不同。无论在什么情况下都没有必要把一个变量的值显式地设置为undefined,可是同样的规则对null却不适用。换句话说,只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存null值。这样做不仅可以体现null作为空对象指针的惯例,而且也有助于进一步区分nullundefined

Boolean

该类型只有两个字面值:truefalse。这两个值与数字值不是一回事,因此true不一定等于1,而false也不一定等于0

虽然Boolean类型的字面值只有两个,但JavaScript中所有类型的值都有与这两个Boolean值等价的值。要将一个值转换为其对应的Boolean值,可以调用类型转换函数Boolean(),例如:

    var message = 'Hello World';
    var messageAsBoolean = Boolean(message);

在这个例子中,字符串message被转换成了一个Boolean值,该值被保存在messageAsBoolean变量中。可以对任何数据类型的值调用Boolean()函数,而且总会返回一个Boolean值。至于返回的这个值是true还是false,取决于要转换值的数据类型及其实际值。下表给出了各种数据类型及其对象的转换规则。

数据类型

转换为true的值

转换为false的值

Boolean

true

false

String

任何非空的字符串

""(空字符串)

Number

任何非0数值(包括无穷大)

0NAN

Object

任何对象

null

Undefined

不适用

undefined

    var message = 'Hello World';
    if(message)
    {
        alert("Value is true");
    }

运行这个示例,就会显示一个警告框,因为字符串message被自动转换成了对应的Boolean值(true)。由于存在这种自动执行的Boolean转换,因此确切地知道在流控制语句中使用的是什么变量至关重要。

ps:使用!!操作符转换布尔值
!!一般用来将后面的表达式强制转换为布尔类型的数据(boolean),也就是只能是true或者false;

nullundefined等其他用隐式转换的值,用!操作符时都会产生true的结果,所以用两个感叹号的作用就在于将这些值转换为等价的布尔值;

var foo;  
alert(!foo);//undifined情况下,一个感叹号返回的是true;  
alert(!goo);//null情况下,一个感叹号返回的也是true;  
var o={flag:true};  
var test=!!o.flag;//等效于var test=o.flag||false;  
alert(test);

这段例子,演示了在undifinednull时,用一个感叹号返回的都是true,用两个感叹号返回的就是false,所以两个感叹号的作用就在于,如果明确设置了变量的值(非null/undifined/0/”“等值),结果就会根据变量的实际值来返回,如果没有设置,结果就会返回false

还有其他的小技巧,可以参考这12JavaScript技巧

Number

这种类型用来表示整数和浮点数值,还有一种特殊的数值,即NaN(非数值 Not a Number)。这个数值用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。例如,在其他编程语言中,任何数值除以0都会导致错误,从而停止代码执行。但在JavaScript中,任何数值除以0会返回NaN,因此不会影响其他代码的执行。

NaN本身有两个非同寻常的特点。首先,任何涉及NaN的操作(例如NaN/10)都会返回NaN,这个特点在多步计算中有可能导致问题。其次,NaN与任何值都不相等,包括NaN本身。例如,下面的代码会返回false

alert(NaN == NaN);    //false

String

String类型用于表示由零或多个16Unicode字符组成的字符序列,即字符串。字符串可以由单引号(')或双引号(")表示。

String类型的特殊性

string类型有些特殊,因为字符串具有可变的大小,所以显然它不能被直接存储在具有固定大小的变量中。由于效率的原因,我们希望JS只复制对字符串的引用,而不是字符串的内容。但是另一方面,字符串在许多方面都和基本类型的表现相似,而字符串是不可变的这一事实(即没法改变一个字符串值的内容),因此可以将字符串看成行为与基本类型相似的不可变引用类型

BooleanNumberString 这三个是Javascript中的基本包装类型,也就是这三个其实是一个构造函数,他们是Function的实例,是引用类型,至于这里的String与以上说的String是同名,是因为其实上文说的String是指字符串,这里的String指的是String这个构造函数,上面那么写,是为了更好的理解,因为Javascript是松散类型的。我们可以看下String实例化的例子:

var name = String("jwy");
alert(typeof name);//"string"
var x=new String('12345')
typeof x //object
x='12345'
typeof x //string
var author = "Tom";
alert(typeof name);//"string"

至于author这个会有lengthsubstring等等这些方法,其实string只是String的一个实例,类似于C#中的String,和string.

注意,typeof 变量 如果值是"string" 的话,也就是这个变量是字符串,在Javascript中,字符串是基本类型,而在C#Java中,字符串是引用类型,但是Javascript中的String是引用类型,因为它是Javascript中定义好的基本包装类型,在C#中,Stringstring其实是一样的。

本帖只是简要的copy了一些JavaScript高级程序设计(第三版)内容,外加了自己侧重的角度,看本帖的朋友还是要看书啊,这里只是做个参考。

 

Es6 symbol

1、Symbol概述

JavaScript基本数据类型有6种:Undefined、Null、Boolean、String、Number、Object。

ES6新增了一种数据类型:Symbol,表示独一无二的值,Symbol最大的用途是用来定义对象的唯一属性名。

ES5的对象属性名都是字符串,容易造成属性名的冲突。如使用了一个其他人提供的对象,但又想为其添加新的方法(mixin模式),那么新方法的名字有可能与已有方法产生冲突。因此,需要保证每个属性的名字都是独一无二,以防止属性名的冲突。这就是ES6引入Symbol的原因。

Symbol值通过Symbol函数生成。

[javascript] view plain copy

  1. var symbol1 = Symbol();  
  2. var symbol2 = Symbol("Alice");  
  3. console.log(symbol1, symbol2) // 输出:Symbol() Symbol(Alice)  

typeof运算符用于Symbol类型值,返回symbol。

[javascript] view plain copy

  1. console.log(typeof Symbol("Alice")) // 输出:symbol  

Symbol类型的值是一个独一无二的值,Symbol函数的参数只是表示对当前Symbol值的描述,因此相同参数的Symbol函数的返回值是不相等的。

[javascript] view plain copy

  1. console.log(Symbol() === Symbol()); // 输出:false  
  2. console.log(Symbol("Alice") === Symbol("Alice")); // 输出:false  

Symbol不是一个构造函数,如果用new Symbol会报错(Symbol是一个原始类型的值,不是对象)。

[javascript] view plain copy

  1. var symbol = new Symbol(); // 报错:TypeError  

由于Symbol值不是对象,所以不能添加属性。

[javascript] view plain copy

  1. var symbol = Symbol();  
  2. symbol.name = "Alice"// 报错:TypeError  

Symbol值不能与其他类型的值进行运算。

[javascript] view plain copy

  1. console.log(Symbol('Alice') + "Bruce"); // 报错  

Symbol值可以显式转为字符串,也可以转为布尔值,但是不能转为数值。

[javascript] view plain copy

  1. var symbol = Symbol("Alice");  
  2. console.log(symbol.toString()); // 输出:Symbol(Alice)  
  3. console.log(Boolean(symbol)); // 输出:Symbol(Alice)  
  4. if (symbol)  
  5.     console.log("YES"); // 输出:Yes  
  6. console.log(Number(symbol)); // 报错:TypeError  


 

2、作为对象属性名的Symbol

由于每一个Symbol值都是不相等的,这意味着Symbol值可以用于对象的属性名,保证不会出现同名的属性,这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。

对象的属性名可以有两种类型,一种是原来的字符串,另一种是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

通过方括号结构和Object.defineProperty,将对象的属性名指定为一个Symbol值。

方法一:

[javascript] view plain copy

  1. var name = Symbol();  
  2. var obj = {  
  3.     [name]: "Alice"  
  4. };  

方法二:

[javascript] view plain copy

  1. var name = Symbol();  
  2. var obj = {};  
  3. obj[name] = "Alice";  

方法三:

[javascript] view plain copy

  1. var obj = {};  
  2. Object.defineProperty(obj, name, { value: 'Alice' });  

在对象的内部,使用Symbol值定义属性时,Symbol值必须放在方括号之中,如果不放在方括号中,该属性名就是字符串,而不是代表的Symbol值。

[javascript] view plain copy

  1. var name = Symbol();  
  2. var obj1 = {  
  3.     [name]: "Alice"  
  4. };  
  5. var obj2 = {  
  6.     name: "Bruce"  
  7. };  
  8. console.log(obj1.name); // 输出:undefined  
  9. console.log(obj1[name]); // 输出:Alice  
  10. console.log(obj2.name); // 输出:Bruce  
  11. console.log(obj2[name]); // 输出:undefined  

Symbol值作为对象属性名时,不能用点运算符。由于点运算符后面总是字符串,所以不会读取name作为标识名所指代的那个值,导致属性名实际上是一个字符串,而不是一个Symbol值。

[javascript] view plain copy

  1. var obj = {};  
  2. var name = Symbol();  
  3. obj.name = 'Alice';  
  4. console.log(obj.name);  
  5. console.log(obj[name]);  
  6. console.log(obj['name']);  


 

3、作为对象函数名的Symbol

[javascript] view plain copy

  1. var func = Symbol();  
  2. var obj = {  
  3.     func: function() {  
  4.         console.log("YES");  
  5.     }  
  6. };  
  7. obj.func(); // 输出:YES  


 

4、获取对象属性的两种方法

1) Object.getOwnPropertySymbols()方法

返回只包含Symbol类型的属性名的数组

2) Object.getOwnPropertyNames()方法

返回只包含字符串类型的属性名的数组

[javascript] view plain copy

  1. var obj = {};  
  2. var age = Symbol("age");  
  3. var job = Symbol("job");  
  4. obj[age] = "Alice";  
  5. obj[job] = "student";  
  6. obj.age = 23;  
  7. var symbols = Object.getOwnPropertySymbols(obj);  
  8. var names = Object.getOwnPropertyNames(obj);  
  9. console.log(symbols.length); // 输出:2  
  10. console.log(symbols); // 输出:[Symbol(age), Symbol(job)]  
  11. console.log(obj[symbols[0]]); // 输出:Alice  
  12. console.log(names.length); // 输出:1  
  13. console.log(obj[names[0]]); // 输出:23  


 

5、Symbol.for()和Symbol.keyFor()方法

1) Symbol.for()方法

类似于单例模式,首先在全局中搜索有没有以该参数为名称的Symbol值,如果有则返回该Symbol值,否则新建并返回一个以该参数为名称的Symbol值。

[javascript] view plain copy

  1. var symbol1 = Symbol.for('Alice');  
  2. var symbol2 = Symbol.for('Alice');  
  3. console.log(symbol1 === symbol2) // 输出:true  

2) Symbol.keyFor()方法

返回一个已创建的Symbol类型值的key,实质是检测该Symbol是否已创建。

[javascript] view plain copy

  1. var symbol1 = Symbol.for("Alice");  
  2. console.log(Symbol.keyFor(symbol1)); // 输出:"Alice"  
  3. var symbol2 = Symbol("Alice");  
  4. console.log(Symbol.keyFor(symbol2)); // 输出:undefined  

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn/zhouziyu2011/arti

 

编码实现插入排序

数据结构中的基础排序算法包括冒泡,选择和插入排序,它们的核心思想都是对一组数据按照一定的顺序重新排列,排列时用到的主要是一组嵌套的for循环,其中外循环遍历数组的每一项,内循环则用于比较元素。以下将按照升序排列为例。

1.冒泡排序

冒泡排序时数组的数据会像气泡一样从数组的一段漂浮到另一端,因此才有了冒泡这个命名。基本步骤如下:

1.依次两两比较相邻的元素,如果第一个比第二个大,则进行交换。

2.经过第一轮比较之后,最大的数已经出现在数组最后一个位置了。

3.然后再对除了最后一个元素外的所有数都重复一遍上述比较,结束后第二个的数会到达数组倒数第二个位置。

4.再依次对剩下的数进行重复,直到排序完毕。

下面看看代码描述:

function bubbleSort(arr){

    for(var i=0; i<arr.length; i++){

        for(var j=0; j<arr.length-i; j++){

            //当第一个数大于第二个时,交换它们

            if(arr[j]>arr[j+1]){

                var temp = arr[j];

                arr[j] = arr[j+1];

                arr[j+1] = temp;

            }

        }

    }

}

 //测试

 var testArr = [35,22,1,56,88,25];

 bubbleSort(testArr);

 alert(testArr); //输出1,22,25,35,56,88


 

2.选择排序

步骤如下:

1.从数组的开头起,将第一个元素和其他所有元素都进行一次比较,选择出最小的元素放在数组的第一个位置。

2.然后再从第二个元素开始,将第二个元素和除第一个之外的所有元素进行一次比较,选择出最小的元素放在数组的第二个位置。

3.对后面的第三,第四……的元素分别重复上面的步骤,知道所有的数据完成排序。

代码描述如下:

function selectSort(arr){

    var minIndex;//定义minIndex变量用于存储每一趟比较时的最小数的下标

    for(var i=0; i<arr.length; i++){

        minIndex = i;

        for(var j=i+1; j<arr.length; j++){

           if(arr[minIndex]>arr[j]){

               minIndex = j;

           }

        }

        //每轮比较后若arr[i]不是我们需要的最小那个数,则进行交换

        if(minIndex!=i){

           var temp = arr[i];

            arr[i] = arr[minIndex];

            arr[minIndex] = temp;

        }

    }

}

 //测试

 var testArr = [35,22,1,56,88,25];

 selectSort(testArr);

 alert(testArr); //输出1,22,25,35,56,88


 

3.插入排序

插入排序的思想非常简单,主要如下:

步骤:

1.首先将数组第1个数看成是一个有序序列。

2.将数组的第2个数按照关键字大小插入到这个有序序列中,插入后得到了一包含两个数的有序序列。

3.接下来再重复上面的步骤将第3,第4……第n-1个数分别插入到该有序序列中,最终得到一个包含n个数的有序序列。

代码描述:

function insertSort(arr){

  var temp//temp变量用于临时存储待插入元素

  for(var i=1; i<arr.length; i++){

     temp = arr[i];

      //从前往后查找插入位置

     for(var j=i; j>0&&arr[j-1]>temp; j--){

         arr[j]=arr[j-1]; //将大于temparr[j]元素后移

     }

      arr[j]=temp;

  }

}

 //测试

 var testArr = [35,22,1,56,88,25];

 insertSort(testArr);

 alert(testArr); //输出1,22,25,35,56,88


 

 

 

 

 

 

Html5视频是哪个标签    video

现在如果要在页面中使用video标签,需要考虑三种情况,支持Ogg Theora或者VP8(如果这玩意儿没出事的话)的(OperaMozillaChrome),支持H.264的(SafariIE 9Chrome),都不支持的(IE678)。好吧,现在让我们从技术层面来认识HTML 5的视频,包括video标签的使用,视频对象可以用到的媒介属性和方法,以及媒介事件。

Video标签的使用

Video标签含有srcposterpreloadautoplayloopcontrolswidthheight等几个属性, 以及一个内部使用的标签<source>Video标签内除了可以包含<source>标签外,还可以包含当指定的视频都不能 播放时,返回的内容。

(1) src属性和poster属性

你能想象src属性是用来干啥的。跟<img>标签的一样,这个属性用于指定视频的地址。而poster属性用于指定一张图片,在当前视频数据无效时显示(预览图)。视频数据无效可能是视频正在加载,可能是视频地址错误等等。

<video width="658" height="444" src="http://www.youname/images/first.mp4" poster="http://www.youname/images/first.png" autoplay="autoplay"></video>

 

(2) preload属性

这个属性也能通过名字了解用处,此属性用于定义视频是否预加载。属性有三个可选择的值:nonemetadataauto。如果不使用此属性,默认为auto

<video width="658" height="444" src="http://www.youname/images/first.mp4" poster="http://www.youname/images/first.png" autoplay="autoplay" preload="none"></video>

 

None:不进行预加载。使用此属性值,可能是页面制作者认为用户不期望此视频,或者减少HTTP请求。

Metadata:部分预加载。使用此属性值,代表页面制作者认为用户不期望此视频,但为用户提供一些元数据(包括尺寸,第一帧,曲目列表,持续时间等等)。

Auto:全部预加载。

(3) autoplay属性

又是一个看名字知道用处的属性。Autoplay属性用于设置视频是否自动播放,是一个布尔属性。当出现时,表示自动播放,去掉是表示不自动播放。

<video width="658" height="444" src="http://www.youname/images/first.mp4" poster="http://www.youname/images/first.png" autoplay="autoplay" preload="none"></video>

 

注意,HTML中布尔属性的值不是truefalse。正确的用法是,在标签中使用此属性表示true,此时属性要么没有值,要么其值恒等于他的名字 (此处,自动播放为<video autoplay />或者<video autoplay=”autoplay” />);而在标签中不使用此属性表示false(此处不进行自动播放为<video />)。

 (4) loop属性

<video width="658" height="444" src="http://www.youname/images/first.mp4" poster="http://www.youname/images/first.png" autoplay="autoplay" loop="loop"></video>

 

一目了然,loop属性用于指定视频是否循环播放,同样是一个布尔属性。

(5) controls属性

<video width="658" height="444" src="http://www.youname/images/first.mp4" poster="http://www.youname/images/first.png" autoplay="autoplay" preload="none" controls="controls"></video>

 

Controls属性用于向浏览器指明页面制作者没有使用脚本生成播放控制器,需要浏览器启用本身的播放控制栏。

控制栏须包括播放暂停控制,播放进度控制,音量控制等等。

每个浏览器默认的播放控制栏在界面上不一样。由于我浏览器的诡异问题,FirefoxSafariVideo标签不正常,所以这两个只能在网上找截图了。

(6) width属性和height属性

属于标签的通用属性了,这个不用多说。

(7) source标签

<video width="658" height="444" poster="http://www.youname/images/first.png" autoplay="autoplay" preload="none" controls="controls"><source src="http://www.youname/images/first.ogv" /><source src="http://www.youname/images/first.ogg" /></video>

 

Source标签用于给媒体(因为audio标签同样可以包含此标签,所以这儿用媒体,而不是视频)指定多个可选择的(浏览器最终只能选一个)文件地址,且只能在媒体标签没有使用src属性时使用。

浏览器按source标签的顺序检测标签指定的视频是否能够播放(可能是视频格式不支持,视频不存在等等),如果不能播放,换下一个。此方法多用于兼容不同的浏览器。Source标签本身不代表任何含义,不能单独出现。

此标签包含srctypemedia三个属性。

src属性:用于指定媒体的地址,和video标签的一样。

Type属性:用于说明src属性指定媒体的类型,帮助浏览器在获取媒体前判断是否支持此类别的媒体格式。

Media属性:用于说明媒体在何种媒介中使用,不设置时默认值为all,表示支持所有媒介。你想到<style>标签的media属性了么?一样一样一样的。

(8) 一个完整的例子

<video width="658" height="444" poster="http://www.youname/images/first.png" autoplay="autoplay" preload="none" controls="controls"><source src="http://www.youname/images/first.ogv" /><source src="http://www.youname/images/first.ogg" /></video>

 

这段代码在页面中定义了一个视频,此视频的预览图为poster的属性值,显示浏览器的默认媒体控制栏,预加载视频的元数据,循环播放,宽度为900像素,高度为240像素。

第一选择视频地址为第一个source标签的src属性值,视频类别为Ogg视频,视频编码译码器为Theora,音频编码译码器为Vorbis,播放媒 介为显示器;第二选择视频地址不再累述。如果你还要兼容IE的话,可以在最后一个source标签后再加上Flash播放器的标签集,或者使用一点 JavaScript代码。

 

经常会使用到伪类的是哪一个标签   a

上面是伪类的正确顺序,简称 lvha(love-ha)。你一直知道这个顺序但是为什么这样呢?原理是怎么样的? 
a:link{color:#f30;} 
a:visited{color:#000;} 
a:hover{color:#fff;} 
a:active{color:#f99;}

原理  

首先伪类的特殊性(应用优先级)是同样的,所以后出现的伪类会覆盖先出现的伪类(同时激活) 
lvha
规则是由于CSS特殊性导致,css特殊性有一个按顺序的规则(同一条css规则,后出现会覆盖前面的同样规则) 
在这里,比如把hover放在active后面,那么实际你在激活(active)链接的时候就触发了hover伪类,hover在后面覆盖了active的颜色,所以始终无法看到active的颜色 
如果把visited放在hover的后面,那么已经访问过的链接始终触发visited伪类,根据第一条会覆盖hover里面的颜色。 
其实 link visited 这两个伪类,并不需要顺序关系。(他们两的位置可以交换)

 

Css3中圆角是哪个属性   boder-radius

CSS3属性之圆角效果——border-radius属性

css3之前,要实现圆角的效果可以通过图片或者用margin属性实现(可以参考这里:http://www.hicss/css-practise-of-image-round-box/)。实现过程很繁琐,但CSS3的到来简化了实现圆角的方式。

CSS3实现圆角需要使用border-radius属性,但因为浏览器兼容性的问题,在开发过程中要加私有前缀。

1

2

3

4

-webkit-border-radius

-moz-border-radius

-ms-border-radius

-o-border-radius

 border-radius属性其实可以分为四个其他的属性:

1

2

3

4

5

border-radius-top-left         /*左上角*/

border-radius-top-right       /*右上角*/

border-radius-bottom-right /*右下角*/

border-radius-bottom-left   /*左下角*/

//提示:按顺时针方式

下面用几个实例来展示border-radius的具体用法。

1border-radius单个属性值:

1

2

//HTML清单

<div class="roundedCorner">

1

2

3

4

5

6

.roundedCorner{

    width:100px;

    height:100px;

    background-color:#f90;

    border-radius:10px;//左上,右上,右下,坐下都是10px

}

效果:

                                              

2border-radius是个属性值方式:

1

2

3

4

5

6

7

<div class="roundedCorner2"></div><br/><br/><br/>//HTML清单

.roundedCorner2{

    width:100px;

    height:100px;

    background-color:#f99;

    border-radius:20px 10px 5px 2px;

}

 效果:

                                            

不过在开发的过程中(我的工作中),经常用到的是border-radius单属性值,设置4个不同圆角的情况很少。

border-radius的优势不仅仅在制作圆角的边框,还是利用border-radius属性来画圆和半圆。

1、制作半圆的方法:

元素的高度是宽度的一半,左上角和右上角的半径元素的高度一致(大于高度也是可以的,至少为height值)。

1

2

3

4

5

6

7

<div class="semi-circle"></div>

.semi-circle{

    width:100px;

    height:50px;//高度是宽度的一半

    background-color:#000;

    border-radius:50px 50px 0 0;//左上和右上至少为height值

}

效果: 

                                                     

知道了如何画上半圆,就会举一反三画其他方向的圆了,这里不再赘述。

 

2、画实心圆的方法:

宽度和高度一致(正方形),然后四个角设置为高度或者宽度的1/2.

1

2

3

4

5

6

7

<div class="circle"></div>

.circle{

    width:100px;

    height:100px;

    background-color:#cb18f8;

    border-radius:50px;

}

效果:

                                                       

 

总结:

CSS3实现圆角的方式既优雅又方便,但是兼容性不够好,如果需要考虑旧版本的浏览器的话,可以考虑优雅降级的方式。开始提到的两种方式的优点是兼容性好,但不够优雅。

w3c上的官方解释,是这样子的:

border-radius: 1-4 length|% / 1-4 length|%;

1-4指的是radius的四个值,length和%指的是值的单位。

写过border的人都知道border可以带四个参数分别设置四个边框(上左下右的顺序),同样的,border-radius也可以带四个参数,并且以顺时针的方向解析,上左,上右,下右,下左:

1

2

3

.box{

    border-radius: 5px 10px 20px 50px         

}

展示结果:

两个参数的时候,是上左和下右,上右和下左,比如.div1{border-radius: 2em 1em},就不截图了,直接demo

三个参数的时候,是上左,上右和下左,下右,比如.div1{border-radius: 2em 1em 3em}demo

 

那么以斜杠/分开后面的参数是怎么回事呢?是这样子的,第一个参数表示圆角的水平半径,第二个参数表示圆角的垂直半径,所以你现在就可以画一个左右不对称的圆角啦:

1

.div1{border-radius: 2em/1em}

 

看到这里你会不会以如果四个圆角都要分别制定特殊的形状,是不是 2em/1em , 1em/0.5em, 3em/1em, 1em/1em像上面那个四个参数一样的设定(我就是这么以为的),答案是错!误!的!因为官方的解释就是前面放1-4后面放1-4啊!鱼不是被吃掉的就是被笨s~

1

2

3

.div1{

        border-radius:10px 20px 30px 40px/40px 30px 20px 10px

}

按顺时针的顺序,斜杠/左边是四个圆角的水平半径,右边是四个圆角的垂直半径,但是通常我们很少写右边的参数,那就是默认右边等于左边的值。当然你也可以省略一些值,比如这样子写.div1{border-radius: 2em 1em 4em / 0.5em 3em;},解析顺序你就可以按照上面的自己推算一下啦。

 

;怎么实现一个页面刷新了当前所填写的信息还在

页面本身是不具备保存历史数据的功能的,需要借助其它手段来实现,常用方法如下:

  1. 异步更新页面。这种方法实际上页面是没有刷新的,通过AJAX导步获取信息来更新页面,这样可以保留原页面需要保留的数据。一些网站的发表评论后,评论内容更新,用的就是这个方法。
  2. 使用COOKIE保存。把需要保存的数据存储到COOKIE中,页面更新时,读取COOKIE渲染到页面上。比较常见的如:登录框记录用户名,下次登录无须重新输入。但COOKIE存储的数据量有限,不适合大的数据存储
  3. 服务器端保存数据。与COOKIE保存类似,只不过内容是保存在服务器端,利用会话机制在页面更新时从服务器读取内容重新渲染。这是一种常见的而保险的方法。像一些文本编辑器,保存草稿等,就是通过这样的方式实现的

 

本篇文章主要是对JS刷新当前页面的几种方法进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助

 

reload 方法,该方法强迫浏览器刷新当前页面。
语法:location.reload([bForceGet])                                                                                                                           参数: bForceGet 可选参数, 默认为 false,从客户端缓存里取当前页。true, 则以 GET 方式,从服务端取最新的页面, 相当于客户端点击 F5("刷新")

replace 方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,你不能通过前进后退来访问已经被替换的URL
语法: location.replace(URL)   

在实际应用的时候,重新刷新页面的时候,我们通常使用: location.reload() 或者是 history.go(0) 来做。因为这种做法就像是客户端点F5刷新页面,所以页面的method="post"的时候,会出现"网页过期"的提示。那是因为Session的安全保护机制。可以想到: 当调用 location.reload() 方法的时候, aspx页面此时在服务端内存里已经存在, 因此必定是 IsPostback 的。如果有这种应用: 我们需要重新加载该页面,也就是说我们期望页面能够在服务端重新被创建, 我们期望是 Not IsPostback 的。这里,location.replace() 就可以完成此任务。被replace的页面每次都在服务端重新生成。

你可以这么写: location.replace(location.href);

返回并刷新页面:

location.replace(document.referrer);
document.referrer //
前一个页面的URL

不要用 history.go(-1),或 history.back();来返回并刷新页面,这两种方法不会刷新页面。

附:
Javascript刷新页面的几种方法:
1    history.go(0) 
2    location.reload() 
3    location=location 
4    location.assign(location) 
5    document.execCommand('Refresh') 
6    window.navigate(location) 
7    location.replace(location) 
8    document.URL=location.href

自动刷新页面的方法:

1.页面自动刷新:把如下代码加入<head>区域中
<meta http-equiv="refresh" content="20">
其中20指每隔20秒刷新一次页面.

2.页面自动跳转:把如下代码加入<head>区域中
<meta http-equiv="refresh" content="20;url=http://www.jb51">
其中20指隔20秒后跳转到http://www.jb51页面

3.页面自动刷新js

复制代码代码如下:


<script language="JavaScript">
function myrefresh()
{
       window.location.reload();
}
setTimeout('myrefresh()',1000); //
指定1秒刷新一次
</script>


JS刷新框架的脚本语句

//如何刷新包含该框架的页面用   
<script language=JavaScript>
   parent.location.reload();
</script>  


//子窗口刷新父窗口
<script language=JavaScript>
    self.opener.location.reload();
</script>
(
 或 <a href="javascript:opener.location.reload()">刷新</a>   )

//如何刷新另一个框架的页面用   
<script language=JavaScript>
   parent.
另一FrameID.location.reload();
</script>

如果想关闭窗口时刷新或者想开窗时刷新的话,在<body>中调用以下语句即可。

<body οnlοad="opener.location.reload()"> 开窗时刷新
<body onUnload="opener.location.reload()"> 关闭时刷新

<script language="javascript">
window.opener.document.location.reload()
</script>

 

使用过哪些框架

Bootstrap、html5-boilerplate、Meteor、Semantic UI、Foundation、Materialize、Vue、Skeleton、Amaze UI、UIkit、Yui、kissy、MUI、Arale、JX、GMU、ZUI、Clouda Touch.js这些是目前比较流行的框架

目前比较流行的是:vue、react、angular 三大前端框架

使用过哪些库

前端特别流行的库很多,完全是根据不同需求来的。

  1. 最流行的当属jQuery, 这货是用来做HTML元素选择操作、css和动画、事件绑定、ajax封装等所有网页基本业务的,其中很多设计特点,和方法名称,都被业内完全认可的,跟jQuery类似的库有很多:prototype,mootools,国内也有很多公司做了自己的类似的库。
  2. 由于IE8以下浏览器不能兼容ES5的一些数组对象操作的方法,underscore.js 做了这些常用方法的兼容,并且扩展了大量的常用数据操作方法。 数据过滤、分组、选择、循环等等。
  3. 模块化的库: 实在是多的数不胜数,最流行的当属requireJs和seaJs,比较纯粹的模块化库,此外,BAT以及其他顶级的(不顶级的)互联网公司几乎只有有一个技术能力不错的前端架构,都会有自己的库,百度的最出名的是esl,腾讯的JX,阿里系的seaJS和KISSY,等。
  4. 还有一些专做图表制作的,比如业内最出名的矢量图库highcharts,百度的canvas图库echarts等。
  5. js进行复杂的HTML拼装的时候。可能需要使用js模板引擎,这样的库也是数不胜数,handlebars,Mustache,jade等
  6. 随着前端 MV* 流行,这样的框架也是多不胜数: 以前的backbone、canjs,现在的新贵angular等

前端是一个工作项目非常杂的职业岗位,以上我讲到的,只是我自己在工作中接触比较多的一些类型,其他还有很多更专业的库,例如使用D3.js进行复杂的3D图形和动画制作,随着Node.js的流行,还有更多的非浏览器平台的功能可以推广使用,甚至应用在浏览器端。

 

近段时间所遇到的感觉比较困难的难题和怎么解决的

1.margin-top,margin-bottom不能正常显示时

.有时会遇到外层中的子层使用margin-top不管用的情况;这里我们需要在子层的前后加上一个

   div{height:0;overflow:hidden;}

CSS样式表中:

#box {background-color:#eee;}

#box p {margin-top: 20px;margin-bottom: 20px;text-align:center;}

解决方法:在P标签前后各加2个空的div<divstyle="height:0;overflow:hidden"></div>

.网页中头部,中部,底部的居底部有时给个margin-bottom:10px;不管用也是要给个清除属性的.clear{clear:both;font-size:0;line-height:0;}在底部<div id="footer"></div>下加个<div></div>

2.div层中高度自适应问题

    网页前端科技人员在设计网页时不可能知道客户在要他们自己的网站内容页里加多少文字或图片内容

    这时我们就不能规定div层的高度,为此应写成min-height:200px;height:auto!important;height:

    200px;overflow:visible;这样ie7,ff,ie6浏览器的高度自适应问题就解决了,这些在

    http://www.xueshengshu/网站中用到最多了。

3.div层中子层的居底部对齐问题

    div中的定位问题有很多也很麻烦,但弄懂了就OK了,在一个大的div层中如何让子层的内容居底部

    对齐就涉及到了position定位问题;

   

    div#box{position:relative;border:1px solidred;width:600px;hegiht:400px;}

    div子层#box .wrap{position:absolute;bottom:0;border:1px dashedblue;width:200px;height:

    100px},最近写的网站中http://www.msgc/就用到了

4.div层中清除clear属性的一小部分应用

   div中一个大的层里面有很多子层,若是加上边框在ie7ie6中或许会正常显示,但是在ff中可能

   只会成一条线了,此时在最外层的后面加上<div style="clear:both"></div>或者设 .wrapfix:after{

  content: ".";

  display: block;

  height: 0;

  clear: both;

  visibility: hidden;

 }后在每个浮动外框调用wrapfixhttp://www.xueshengshu学生书网里用到最多了。

5.解决IE8div移位、错位等兼容性问题

   <head>标签后面的第一句话加上<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />OK

6.单行文字居中与字体样式问题

   div中一个层中只有一行文字,要让这层中的文字居中,可设line-height的高度和层的高度一样,注意这一层中的文字不能换行,此外,设了line-height时再给定字体样式font:bold 14px "宋体";这时要把font:bold 14px "宋体";放在line-height的前面,否则字体样式不显示文字也不居中;或者将font:bold 14px "宋体";改成font-size:16px;font-weight:bold;font-family:"宋体";OK了。

7.鼠标滑上去的特殊效果

 往往为了达到显眼的效果,我们会写到一些好看的效果,方法一在样式表中写:ul li a{border:1px solid red;}ul li a:hoverimg{filter:alpha(opacity=40ul标签中调用即可方法二:在样式表中写上:.hover img{filter:alpha(opacity=40);}div中调用οnmοuseοver="this.className='hover'"οnmοuseοut="this.className=this.classtype"即可

8.IE6中高度不对问题

 今天在div中给定了高度为1px,其它浏览器显示正常,可是ie6中显示的高度就不对了,这时我给样式表中加了个font-size:0px;line-height:0px;就好了

9.ul在外框里margin-top不起作用的问题

 div大框子里用了ul作导航的时候为了合ul层居中显示,设ul的样式表为margin-top:-15px不起作用了,此时应该将div大框设定高度后给个line-heightheight一样的高度,ul层就自动居中了。

例如http://www.hopes-home/main.aspx

10.ffmargin-top有时不起作用的问题

 今天头晕脑涨的把这问题给解决了,这几天写标网都有累似问题,可是一直都是换个写法解决的,今天的这个办法也不只可行试试还是可以的,在一个div外框层中给个宽度例如,#div_wrap{width:280px;height:100%;}

其次在这个框子里设一个.div_top{widh:100%;font:bold12px "宋体";height:24px;line-height:24px;}

.div_center{border:1px solid#dbdbdb;border-top:none;background:#fff;min-height:460px !important;height:auto!important;height:460px;overflow:visible;}

 最后在这个div_center里套个ul li时经常会在ff中出问题,也就是在div_topdiv_center中莫名的多了几个像素的空格,这时给ul样式表设个display:inline-table即可;

11.list-style-image的用法

div中经常用到新闻列表前面有图标的样式,有两种简单的方法

.可以写成ul.menu{width:100%;}  ul.menuli{background:url(em_img/small_icon.jpg) 5px center no-repeat;list-style-position:inside;padding-left:18px;}即可在各浏览器正常显示

. 可以设ul.menu{width:80%;}   ul.menuli{list-style-image:url(em_img/small_icon.jpg); }

此时新闻列表前的小图标即可在ie6ie7ie8,ff中都正常显示但,ie6需要不断的刷新才能正常显示小图标;

 

12.

IE6 li:hover兼容问题

<scripttype="text/javascript"><!--//--><![CDATA[//><!--

sfHover =function() {

var sfEls = document.getElementById("nav").getElementsByTagName_r("LI");

for (var i=0; i<sfEls.length; i++) {

sfEls[i].οnmοuseοver=function() {

this.className+=" sfhover";

}

sfEls[i].οnmοuseοut=function() {

this.className=this.className.replace(new RegExp(" sfhover\b"), "");

}

}

}

if (window.attachEvent) window.attachEvent("onload", sfHover);

//--><!>

</script>

13.ie6下支持position:absolute;

最近写一个短信平台的页面用到的底部固定的层,在ffie7,ie8下都是好的,可到ie6下就不行了,转了整个地球终于出来了:

background-attachment:fixed; }

 #bottomNav {background-color:#096; z-index:999; position:fixed; bottom:0; left:0;width:100%; _position:absolute;

 _top: expression_r(documentElement.scrollTop+ documentElement.clientHeight-this.offsetHeight); overflow:visible; }

样式表中调用即可!详细请见高度自适应屏幕尺寸!

14.border:none;border:0;的区别

1.性能差异

border:0;】把border设为“0”像素虽然在页面上看不见,但按border默认值理解,浏览器依然对border-width/border-color进行了渲染,即已经占用了内存值。

border:none;】把border设为“none”即没有,浏览器解析“none”时将不作出渲染动作,即不会消耗内存值。

2.兼容性差异

兼容性差异只针对浏览器IE6IE7与标签buttoninput而言,在winwin7vista XP主题下均会出现此情况。

border:none;】当border“none”时似乎对IE6/7无效边框依然存在

border:0;】当border“0”时,感觉比“none”更有效,所有浏览器都一致把边框隐藏

总结:

1. 对比border:0;border:none;之间的区别在于有渲染和没渲染,感觉他们和display:none;visibility:hidden;的关系类似,而对于border属性的渲染性能对比暂时没找测试的方法,虽然认为他们存在渲染性能上的差异但也只能说是理论上。

2. 如何让border:none;实现全兼容?只需要在同一选择符上添加背景属性即可

对于border:0;border:none;个人更向于使用,border:none;,因为border:none;毕竟在性能消耗没有争议,而且兼容性可用背景属性解决不足以成为障碍。

15.ie下。png的图片不会有灰色背景出现

注:首推PNG8,即使在IE6中它的透明背景也能被正确显示。PNG8使用的技巧是,输出时把杂边设置为和背景接近的颜色

1.几经周折终于把ie6.png有色图问题解决了,原来IE6.0原本支持png8的索引色透明度,但不支持png8位以上的alpha 透明度,在IE6.0下,非PNG8格式的透明图片部分,会显示为淡淡的灰绿色。在网页中头部加个代码<!--[if IE 6]>

<script type="text/javascript" src="http://zmingcx/wp-content/themes/HotNewspro/js/pngfix.js"></script>

<script src="js/DD_belatedPNG.js"></script>

<script>

DD_belatedPNG.fix('.png_bg');

</script>

<![endif]-->即可!

2.在样式里写#png-container{

width: 300px;

height: 150px;

background: none;

filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../imgs/logoB.png',sizingMethod='crop');border:1px solid red;display:block;

}到页面中调用<div id="png-container ">

<img src="imgs/logoB.png" alt="" />

</div>注意图片要保存为png-8格式的才行!

3. 将背景图片写成style="_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../imgs/dialog/da_fr.png',sizingMethod='scale');background:url(../imgs/dialog/da_fr.png) no-repeat!important;_background: none transparent scroll repeat 0% 0%;);"即可。ffie7ie6下都不会有灰色背景了,这个怎么又失灵了,唉害得我纠结了好几天!。

16.表格自动换行

唉,最讨厌表格了,可是编辑软件平台有很多报表要用到表格来写,搞的我郁闷半死,要想让表格里td的内容到了一定宽度自动换行就要先设一个全局样式table{table-layout:fixed;}

td{word-break: break-all; word-wrap:break-word;};             

17.iframe高度自适应

div加一个样式style="position:relative;"

再给iframe 加一个样式如下,只有把iframe定义成绝对定位后,才能自适应高度

style="position:absolute; height:100%;"

18.ie8inputbug

我滴个孩来!一个小的两个input输入框,一个是文本框,一个是按钮,却怎么也接不到一起去,可把我给急坏了,这小问题花了我差不多一下午的时间,纠结半天终于给弄出来了,但不知原因,这么写就对了!

要定义input{ vertical-align:middle;}即可!

19.按钮的链接路径

编写网页前台时会碰到按钮的链接路径怎么给的问题!只要在button里加个οnclick="window.location.href='orderCheck.htm‘"即可!

<button type="button"οnclick="window.location.href='orderCheck.htm'">Add toCart</button>

20.图片加alt好处

网页中<img src=""alt=""/> 中的alt是很重要的,这涉及到网页的亲和力问题(http://www.yixieshi/ucd/9345.html),网页中的图片若是不加alt在图片没加载出来的时候会什么信息也看不到,加了alt则在加载不出来图片的时候显示图片的信息便于用户查看信息!

21.

去除chrome浏览器下inputtextarea点击选中框

取消chromeinputtextarea的聚焦边框:

input,button,select,textarea{outline:none}

取消chrometextarea可拖动放大:

textarea{resize:none}

最后,写在一起,重置inputtextarea的默认样式:

input,button,select,textarea{outline:none}

textarea{resize:none}

 

21.页面中流动条问题

打开一个空白页面,观察浏览器右侧,会发现IE浏览器会有一段滚动条的槽道,而Firefox浏览器下没有。

22). 手机, Adroid2.2, 平板电脑, 浏览器, mobile safari

最近给平板电脑做页面,经历了一番探索,搞定了。

下面来说说我的解决方案。

 

 

测试设备:

   GT-P1000 三星平板电脑(其实为大号手机)

   操作系统:android2.1

   浏览器:Mobile Safari/533.1

   User Agent打印结果:

       Mozilla/5.0 (Linux; U; Android 2.1;zh-cn; GT-P1000 Build/FROYO) AppleWebKit/533

.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

 

 

1. jsp页面顶上增加以下文档类型声明:

Java代码

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance/tech/DTD/xhtml-mobile12.dtd">      

<html xmlns="http://www.w3/1999/xhtml"> 

 

 

 

      如果不加上文档类型声明的话,在浏览器里打开页面后,页面会根据移动设备屏幕的大小自动缩放页面,并且当点击输入框时,页面会自动放大,特别难看。加上声明之后,页面会展现原始大小,手指也可以拖动屏幕进行页面放大。

 

2. 普通的网页字体大小,在移动设备浏览器上看到的效果是字体变小

所以css的字体大小要做大一点。

 

我是研究了雅虎移动版的网站:

http://hk.m.yahoo/

 

23.页面中流动条问题

 

网页中改变input输入框的背景时,当输入的文字超过一定数字时,背景图片会跑,这时只要限定inputmaxlength就行了!

 

24.inputgoogle浏览器下若用背景图片写并且点击上去有效果的话会掉下来

解决的办法是将input里的value=""中加一个空格! 即写成value=" "

25.解决ff下面td的换行问题<tablestyle="table-layout:fixed" width="200">

<tr>

<td width="25%" style="word-break :break-all; overflow:hidden;">abcdefghigklmnopqrstuvwxyz1234567890</td>

<td width="75%" style="word-wrap :break-word; overflow:hidden;">abcdefghigklmnopqrstuvwxyz1234567890</td>

</tr>

</table>

26)巧妙clearfix解决css浮动问题

如何用clear来解决css浮动问题,应该是众多前端开发人员所关心的问题,是clear还是clearfix,其实我们最终一个目的就是让浮动产生更多的影响,最为一个前端人员,我们有必要深入研究和探讨...

万能float闭合,得知很多朋友都在使用下面的通用解决办法:

1.clear{clear:both;height:0;overflow:hidden;}

上诉办法是在需要清除浮动的地方加个div.clear或者br.clear,我们知道这样能解决基本清浮动问题。但是这种方法的最大缺陷就是改变了html结构,虽然只是加个div

 

最优浮动闭合方案(这是我们推荐的):

1.clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden}

2.clearfix{*+height:1%;}

用法很简单,在浮动元素的父云素上添加class="clearfix"。你会发现这个办法也有个弊端,但的确是小问题。改变css写法就ok了:

1.clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden}

2.clearfix{*+height:1%;}

以上写法就避免了改变html结构,直接用css解决了。

很拉轰的浮动闭合办法:

1.clearfix{overflow:auto;_height:1%}

这种办法是我看国外的一篇文章得到的方案,测试了,百试不爽,真的很简单,很给力。喜欢的同学也可以试试这个办法。

 

这种方法是端友radom提供的,测试通过:

1.clearfix{overflow:hidden;_zoom:1;}

chromeinput[type=text]placeholder不垂直居中的问题解决

line-height: normal;  

line-height: 22px\9; 

去掉超链接或按钮点击时的虚框线

a,a:hover,input,button{outline:none;blur:expression_r(this.onFocus=this.blur());} input:active {outline:none;}input::-moz-focus-inner{border:0px}

 

修改select默认的样式

select{background:none;width:400px;border:1pxsolid #d8d8d8;}

option{vertical-align: middle;}

 

最近关注哪些技术

首先我们来回顾一下 2017 年新的前端技术和新的方向。微信跳一跳相信大部分的人都玩过,这个用 H5 编写的小游戏,曾经一度刷爆朋友圈,仅是这一款及其简单的小游戏,就带来了不容小觑的流量。这种状况的一个比较合理的解释是这很符合现代人的生活状态,可以用来消磨时间解解压;再者是基于简单的 H5 开发的,从技术层面来说也不是一个很难攻克的关。跳一跳火了之后,相继出现的还有悦动音符、欢乐坦克等多款微信小游戏,都有大量的用户群体。所以,在 2018 年符合现代潮流的 H5 小游戏会不会迎来它的春天?或者说,前端开发人员要不要入小游戏的坑?

说到前端,我们不得不提其三驾马车 React,Angular 和 Vue。2017年,React 继续在前端领域占据主导地位,备受期待的 React 16 也正式发布。值得关注的是 Facebook 将 React 的开源许可证由原来的 BSD+ 改成了对用户友好的 MIT,并将其 Jest、Flow、Immutable.js 和 GraphQL 等项目也更改为了 MIT 许可证。这种能减少代码重写易于重构的框架还是很受开发者欢迎的。但它是否能在 2018 年坐稳“王位”,还需不断完善整个框架的功能才是。

Angular 也不甘落后,在用户使用群体上,它排名第二。并且也在2017年发布了两个大版本,Angular 4 优化了视图引擎、减少代码体积;Angular 5 中包含了像是编译器的改进,能更快的构建/重建。基本上说Angular这个框架是比较完整的,但是对于复杂的界面开发就不是那么友好了。所以他的地位一直在遭受挑战,而框架中的黑马 Vue 大有替代之势,2017年,Vue 依然越来越受欢迎,该框架提供基于组件的架构。它已经被包括 GitLab 在内的许多大型公司采用,在 Stack Overflow 上的关注度居高不下。所以会是Vue的2018年?不要去猜测2018年学习哪个框架会更好,先打好基础的架构。

2017年前端出现的热词之一必然有PWA。PWA(Progressive Web App)是 Google 于 2016 年提出的概念,2017 年已被迅速采用。可显著提高加载速度、可离线工作、可被添加至主屏、全屏执行、推送通知消息等等。国内有不少公司实践了PWA,例如饿了么、阿里等。今年的谷歌开发者大会上也提到过这个概念。但是对于开发者而言,目前大部分的文档和资料都是以英文文档的形式存在,研究PWA的中文资料很少。但是PWA不能包含原生OS相关代码。PWA仍然是网站,只是在缓存、通知、后台功能等方面表现更好。Electron程序相当于包裹OS原生启动器(Launcher)的网站,2018年,许多Electron程序可能转化为PWA。

GraphQL 这个东西,或许在国内鲜有闻之。但是,它仍是一项不错的技术,同时在调查中,也体现出不俗的潜力。GraphQL有很多优点,不再管理多个端点并获取不必要的数据,GraphQL 允许客户端声明式地定义所需的数据,并从单个端点检索所有数据。这也证实了它在刚出现时就被认为是革命性的 API 工具。或将代替 Rest 在后端的地位。但是目前来说它的特性不是特别优秀,也会有不断的bug,可当SkyWalking在 5.0版本中采用GraphQL作为新一代接口语言后,团队成员不约而同的发出感慨--"未来已来"。那这个前端有什么联系?好好利用 GraphQL ,对于你开发前端的后端接口nodeJS有很大的帮助。

TypeScript,微软老大开发的语言,号称弥补了 JavaScript 的所有缺陷。一经问世 ,就发展迅猛,出处打着要取代JavaScript的旗号。TypeScript 由微软创建,也是新版 Angular 采用的语言,其强类型正是优势所在。 而 Flow 则提供了一种更加灵活的方式来引入类型,而不需要进行重构。语言没有好坏之分,谁取代谁是很难的,有幸看到的是两门语言的并驾齐驱吧。(部分内容来自:前端大全

技术是不断的发展着的,前端现在也不单单是做几个页面那么简单,基础的架构以及与后端的数据交互都是学习前端需要了解的。你不仅要懂得前端发展的风向,掌握风向就掌握了第一生产力。你还要有完美的技术,让web界面每一处的运行都很通畅,让用户有更好的体验。所以说做前端也需要掌握一套完整的开发体系,眼下的 2018 年我们该如何构建一个成熟的前端开发体系?如何以最佳实践的方式进行团队开发?3.24 深圳源创会前端专场,开源中国邀请腾讯、阿里、华为大咖齐聚,为你探索H5的性能天花板,把当下流行的技术进行彻底的剖析,教你构建一个成熟的开发体系。另有各种意想不到的惊喜,还不来源创会充充电?给你一个报名链接>>>带上你所有的疑惑过来吧。

 

关闭浏览器cookie立即失效,而且只是针对于user页面失效

项目,对行业的理解

Html5新增元素

HTML5 中的新元素

下面列出的 HTML5 的新元素,以及对它们的描述。

新的语义/结构元素

HTML5 提供的新元素可以构建更好的文档结构:

标签

描述

<article>

定义文档内的文章。

<aside>

定义页面内容之外的内容。

<bdi>

定义与其他文本不同的文本方向。

<details>

定义用户可查看或隐藏的额外细节。

<dialog>

定义对话框或窗口。

<figcaption>

定义 <figure> 元素的标题。

<figure>

定义自包含内容,比如图示、图表、照片、代码清单等等。

<footer>

定义文档或节的页脚。

<header>

定义文档或节的页眉。

<main>

定义文档的主内容。

<mark>

定义重要或强调的内容。

<menuitem>

定义用户能够从弹出菜单调用的命令/菜单项目。

<meter>

定义已知范围(尺度)内的标量测量。

<nav>

定义文档内的导航链接。

<progress>

定义任务进度。

<rp>

定义在不支持 ruby 注释的浏览器中显示什么。

<rt>

定义关于字符的解释/发音(用于东亚字体)。

<ruby>

定义 ruby 注释(用于东亚字体)。

<section>

定义文档中的节。

<summary>

定义 <details> 元素的可见标题。

<time>

定义日期/时间。

<wbr>

定义可能的折行(line-break)。

阅读更多有关 HTML5 语义的内容。

新的表单元素

标签

描述

<datalist>

定义输入控件的预定义选项。

<keygen>

定义键对生成器字段(用于表单)。

<output>

定义计算结果。

阅读更多有关 HTML 表单元素中新老元素。

新的输入类型

新的输入类型

新的输入属性

  • color
  • date
  • datetime
  • datetime-local
  • email
  • month
  • number
  • range
  • search
  • tel
  • time
  • url
  • week
  • autocomplete
  • autofocus
  • form
  • formaction
  • formenctype
  • formmethod
  • formnovalidate
  • formtarget
  • height 和 width
  • list
  • min 和 max
  • multiple
  • pattern (regexp)
  • placeholder
  • required
  • step

学习 HTML 输入类型中的所有新老输入类型。

学习 HTML 输入属性中的所有输入属性。

HTML5 - 新的属性语法

HTML5 允许四种不同的属性语法。

该例演示 <input> 标签中使用的不同语法:

标签

描述

Empty

<input type="text" value="John Doe" disabled>

Unquoted

<input type="text" value=John>

Double-quoted

<input type="text" value="John Doe">

Single-quoted

<input type="text" value='John Doe'>

HTML5 中,根据属性所需,可能会使用所有这四种语法。

HTML5 图像

标签

描述

<canvas>

定义使用 JavaScript 的图像绘制。

<svg>

定义使用 SVG 的图像绘制。

阅读更多有关 HTML5 Canvas 的内容。

阅读更多有关 HTML5 SVG 的内容。

新的媒介元素

标签

描述

<audio>

定义声音或音乐内容。

<embed>

定义外部应用程序的容器(比如插件)。

<source>

定义 <video> 和 <audio> 的来源。

<track>

定义 <video> 和 <audio> 的轨道。

<video>

定义视频或影片内容。

阅读更多有关 HTML5 视频的内容。

阅读更多有关 HTML5 音频的内容。

 

数据结构:链表和数组的比较

[数据结构] 数组与链表的优缺点和区别

20161115 16:25:00

阅读数:6627

概述

  数组 是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。同样的道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素。如果应用需要快速访问数据,很少插入和删除元素,就应该用数组。

  链表 中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起,每个结点包括两个部分:一个是存储 数据元素 的 数据域,另一个是存储下一个结点地址的 指针。 
  如果要访问链表中一个元素,需要从第一个元素开始,一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了,只要修改元素中的指针就可以了。如果应用需要经常插入和删除元素你就需要用链表

内存存储区别

数组从中分配空间, 对于程序员方便快速,但自由度小。

链表从中分配空间, 自由度大但申请管理比较麻烦. 

逻辑结构区别

数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。 

链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项) 

总结

1、存取方式上,数组可以顺序存取或者随机存取,而链表只能顺序存取; 

2、存储位置上,数组逻辑上相邻的元素在物理存储位置上也相邻,而链表不一定; 

3、存储空间上,链表由于带有指针域,存储密度不如数组大; 

4、按序号查找时,数组可以随机访问,时间复杂度为O(1),而链表不支持随机访问,平均需要O(n); 

5、按值查找时,若数组无序,数组和链表时间复杂度均为O(1),但是当数组有序时,可以采用折半查找将时间复杂度降为O(logn); 

6、插入和删除时,数组平均需要移动n/2个元素,而链表只需修改指针即可; 

7、空间分配方面: 
  数组在静态存储分配情形下,存储元素数量受限制,动态存储分配情形下,虽然存储空间可以扩充,但需要移动大量元素,导致操作效率降低,而且如果内存中没有更大块连续存储空间将导致分配失败; 
  链表存储的节点空间只在需要的时候申请分配,只要内存中有空间就可以分配,操作比较灵活高效;

 

操作系统:进程和线程的描述

一、进程

进程:指在系统中能独立运行并作为资源分配的基本单位,它是由一组机器指令、数据和堆栈等组成的,是一个能独立运行的活动实体。

    注意,进程一般有三个状态:就绪状态、执行状态和等待状态【或称阻塞状态】;进程只能由父进程建立,系统中所有的进程形成一种进程树的层次体系;挂起命令可由进程自己和其他进程发出,但是解除挂起命令只能由其他进程发出。

 

进程控制块(PCB):PCB不但可以记录进程的属性信息,以便操作系统对进程进行控制和管理,而且PCB标志着进程的存在,操作系统根据系统中是否有该进程的进程控制块PCB而知道该进程存在与否。系统建立进程的同时就建立该进程的PCB,在撤销一个进程时,也就撤销其PCB,故进程的PCB对进程来说是它存在的具体的物理标志和体现。一般PCB包括以下三类信息:进程标识信息;处理器状态信息;进程控制信息。

    由程序段、相关的数据段和PCB三部分构成了进程实体(又称进程印像),一般,我们把进程实体就简称为进程。

进程的特征:
1.动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的。
2.并发性:任何进程都可以同其他进程一起并发执行。
3.独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
4.异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。


二、线程


线程:线程是进程中的一个实体,作为系统调度和分派的基本单位。Linux下的线程看作轻量级进程。


线程的性质:
1.线程是进程内的一个相对独立的可执行的单元。若把进程称为任务的话,那么线程则是应用中的一个子任务的执行。
2.由于线程是被调度的基本单元,而进程不是调度单元。所以,每个进程在创建时,至少需要同时为该进程创建一个线程。即进程中至少要有一个或一个以上的线程,否则该进程无法被调度执行。
3.进程是被分给并拥有资源的基本单元。同一进程内的多个线程共享该进程的资源,但线程并不拥有资源,只是使用他们。
4.线程是操作系统中基本调度单元,因此线程中应包含有调度所需要的必要信息,且在生命周期中有状态的变化。
5.由于共享资源【包括数据和文件】,所以线程间需要通信和同步机制,且需要时线程可以创建其他线程,但线程间不存在父子关系。


多线程使用的情形:前台和后台工作情况;异步处理工作情况;需要加快执行速度情况;组织复杂工作的情况;同时有多个用户服务请求的情况等。
 
线程机制的优点:
多线程运行在同一个进程的相同的地址空间内,和采用多进程相比有以下优点:
1.创建和撤销线程的开销较之进程要少。创建线程时只需要建立线程控制表相应的表目,或有关队列,而创建进程时,要创建PCB表和初始化,进入有关进程队列,建立它的地址空间和所需资源等。
2.CPU在线程之间开关时的开销远比进程要少得多。因开关线程都在同一地址空间内,只需要修改线程控制表或队列,不涉及地址空间和其他工作。
3.线程机制也增加了通讯的有效性。进程间的通讯往往要求内核的参与,以提供通讯机制和保护机制,而线程间的通讯是在同一进程的地址空间内,共享主存和文件,无需内核参与。


三、进程和线程的区别


(1)调度:
        在传统的操作系统中,CPU调度和分派的基本单位是进程。而在引入线程的操作系统中,则把线程作为CPU调度和分派的基本单位,进程则作为资源拥有的基本单位,从而使传统进程的两个属性分开,线程编程轻装运行,这样可以显著地提高系统的并发性。同一进程中线程的切换不会引起进程切换,从而避免了昂贵的系统调用,但是在由一个进程中的线程切换到另一进程中的线程,依然会引起进程切换。
 
(2)并发性:
      在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间也可以并发执行,因而使操作系统具有更好的并发性,从而更有效地提高系统资源和系统的吞吐量。例如,在一个为引入线程的单CPU操作系统中,若仅设置一个文件服务进程,当它由于某种原因被封锁时,便没有其他的文件服务进程来提供服务。在引入线程的操作系统中,可以在一个文件服务进程设置多个服务线程。当第一个线程等待时,文件服务进程中的第二个线程可以继续运行;当第二个线程封锁时,第三个线程可以继续执行,从而显著地提高了文件服务的质量以及系统的吞吐量。


(3)拥有资源:
      不论是引入了线程的操作系统,还是传统的操作系统,进程都是拥有系统资源的一个独立单位,他可以拥有自己的资源。一般地说,线程自己不能拥有资源(也有一点必不可少的资源),但它可以访问其隶属进程的资源,亦即一个进程的代码段、数据段以及系统资源(如已打开的文件、I/O设备等),可供同一个进程的其他所有线程共享。


(4)独立性:
        在同一进程中的不同线程之间的独立性要比不同进程之间的独立性低得多。这是因为
 

为防止进程之间彼此干扰和破坏,每个进程都拥有一个独立的地址空间和其它资源,除了共享全局变量外,不允许其它进程的访问。但是同一进程中的不同线程往往是为了提高并发性以及进行相互之间的合作而创建的,它们共享进程的内存地址空间和资源,如每个线程都可以访问它们所属进程地址空间中的所有地址,如一个线程的堆栈可以被其它线程读、写,甚至完全清除。


 

(5)系统开销:
 

       由于在创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O设备等。因此,操作系统为此所付出的开销将显著地大于在创建或撤消线程时的开销。类似的,在进程切换时,涉及到整个当前进程CPU环境的保存环境的设置以及新被调度运行的CPU环境的设置,而线程切换只需保存和设置少量的寄存器的内容,并不涉及存储器管理方面的操作,可见,进程切换的开销也远大于线程切换的开销。此外,由于同一进程中的多个线程具有相同的地址空间,致使他们之间的同步和通信的实现也变得比较容易。在有的系统中,现成的切换、同步、和通信都无需操作系统内核的干预。


 

(6)支持多处理机系统:
       在多处理机系统中,对于传统的进程,即单线程进程,不管有多少处理机,该进程只能运行在一个处理机上。但对于多线程进程,就可以将一个进程中的多个线程分配到多个处理机上,使它们并行执行,这无疑将加速进程的完成。因此,现代处理机OS都无一例外地引入了多线程。

前后台怎么链接的

作者:岳逢楽
链接:https://www.zhihu/question/21444314/answer/18245559
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这个问题我理解为:如何把一个Web程序的前端和后端联系起来。以下内容基于此理解进行回答。

先不考虑AJAX,从简单的说起。

前端和后端之所以需要对接,是因为前端页面只负责提供视图没有内容,而后端只提供内容,两者所谓的对接,就是把后端的内容放在前端页面预留出来的位置上。(虽然说是前端后端,但这一对接实际发生在服务器端)。
所以服务器端进行的活动如下:
接收用户请求——》找到负责处理的程序——》处理程序找到要传输给用户的前端页面——》该前端页面留出位置——》后端到数据库取数据——》后端把数据放在前端留出来的位置上——》结合成真正用户看到的html文件——》传输给用户。


(写完发现下面可以不用看了,没有办法用三言两语说清楚,最后你还是得找本书来看)
以博客中常见的输出文章的作者信息为例:

<!DOCTYPE html>

<html>

    <head></head>

    <body>

        <div>write by Aeolia on 2013-08-07</div>

    </body>

</html>

很明显其中的作者名称‘Aeolia’和发布日期‘2013-08-07’要替换掉
具体方法看你后台用的是什么技术:
1,后台php
把HTML文件改为php文件

<?php

    //从数据库获得数据,存在变量writer和date中

?>

<!DOCTYPE html>

<html>

    <head></head>

    <body>

        <div>write by <?php echo writer;?>on <?php echo date;?></div>

    </body>

</html>

===============================================================
2,后台JSP
Servlet文件(*代表此处有省略)

package *

import *

public class Servlet extends HttpServlet {

    public void 处理GET请求的方法{

          //1,从数据库获得数据,存为变量writer和date

          //2,把变量writer和date设置为request的属性

          //3,调用要跳转的JSP页面

    }

}

JSP文件
把HTML文件改为JSP文件

<%

      //从request里把writer和date取出来。

%>

<!DOCTYPE html>

<html>

    <head></head>

    <body>

        <div>write by <%=writer%>on <%=date%></div>

    </body>

</html>


==============================================================
3,Ruby on Rails
controller文件

class Controller < ApplicationController

    def index

           //数据库里取article对象

           //把article对象的数据respond到视图中

    end

end

视图文件
把HTML文件后面添加后缀erb,为index.html.erb,放在视图文件夹下
<div>write by <%=article.writer%>on <%=article.date%></div>

如果是前端做好了,那就是根据后端部分将数据填上了。

一种方式是后端程序员拿着你这个页面直接改,插入数据。这个适合一些模板类的工具例如PHP,http://ASP.NET,JSP,此外还有形式上相似的比如rhtml、django模板、Velocity等等。PHP中有一个也致力于此的库叫Smarty处理一些简单的情形还是非常不错的。
采用这种方式,前端做好页面后面就帮不上忙了,只能让后端去熟悉你前端的设计,让后你作为前端稍微解释一下一些细节。

一种方式是ajax取数据,也就是让后端暴露出数据,让前端取回来填充页面。除了XML格式,json格式也比较流行。这种情况下是前端完成剩余的部分,前端和后端需要约定好数据格式的细节。
这种方式的缺点是很依赖前后端的沟通,而且几乎没法实现测试驱动开发。
于是这种方式有各种变种,比如Ember.js,knockout.js,backbone.js这些工具使用的方式。很多时候需要给数据先设计一个schema,未必是前端或者后端写,可能是在项目前期约定好的,前端和后端就按照预先约定好的做正确的实现就可以了,这些库会帮你把数据在恰当的位置显示出来,并实现一些交互功能。



作者:知乎用户
链接:https://www.zhihu/question/21444314/answer/18249432
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

举例说明怎么学习一项技能

html+cssjavascriptmysqlphpxmlhttp协议、WebServicelinux系统

俗话说的好,冰冻三尺并非一日之寒。如果你能静下心来慢慢的看完我写的以下文章,会对你想要学习或者已经在学习当中的同学会起到一个比较不错的效果!

学习web前端,是一个漫长的路程,这是针对我自身的经历告诉正在看这篇文章的你。如果你现在抱有的态度是学学看或者没有一定的耐心我真诚的告诉你放弃吧!Web前端想要学习好,真的是一个漫长的过程。有的人现在有可能已经工作了,有的人有可能现在正在上学。关于我,现在已经工作了我并没有选择什么学习班或者培训班去专门的学习web前端!再说我也没有时间跟金钱投资在学习!从而极少数人会坚持下来的一条路。自学!

1,首先推荐关于已经在上班的同学时间规划做一个说明!

正常上班中午休息两个小时拿出来学习,也就是中午除掉中午吃饭半个小时完全够用,剩下的一个半小时拿出来用作学习。下午6:00下班吃饭会耽误20分钟也就是说6:20-22:00的时间是拿出来学习?不要告诉自己中午要睡觉什么的一切是借口!现在你还年轻需要那么多睡眠干嘛?以上我说的这种习惯,不要是强迫性的。我的学习进度就是这样的!粗略计算已经坚持18个月。如果你能,我相信你一定能成功的学会web前端,并且完全不需要花费大量的时间跟金钱!

2,针对正在上学的同学,时间真的多了!多不多你自己清楚!

首先第一步你要学会的就是html+css这也是最基础的东西,htmlcss达到一个什么标准呢?只要能够做出一个简单的网站就可以了!最起码的html标签、表单、浮动、内联转块状图片定位、有序列表、无序列表、伪类、什么是div?Div是干嘛的?最好会使用firefox bug做一些简单的调错firefox bug这个工具后期也会用到!学习Html花费不要太长时间,做多不要超过一个星期。以下是html+css的一个思维导图希望对你有用!

今天的文章就先更新到这!继续关注我的博客更新!有关自学的同学不懂得也可以在下面留言我会在第一时间回答大家的问题!或者直接在博客软文频道中查找。相关学习内容笔记!再或者都不知道怎么学的我这边也有学习的教程全是系统话的教程!是关于燕十八老师的教程!也是我正在看的!现在已经更新到了16大节课!蛮不错的教程!公益讲师!不要去淘宝买哦!有想要学习的直接跟我要就好!不需要花那一份钱!省下的钱可以自己买些书看看多好!对吧,下一篇见!

 

解释并写一个闭包,以及什么地方用得到

作者:知乎用户
链接:https://www.zhihu/question/34547104/answer/59515735
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

目前以上答案似乎都只是再说闭包是个什么样子。补充一点吧。

近似正确的短答案:闭包就是一个函数把外部的那些不属于自己的对象也包含(闭合)进来了。

短答案:JavaScript中的闭包,无非就是变量解析的过程

首先看一段话:
每次定义一个函数,都会产生一个作用域链(scope chain)。当JavaScript寻找变量varible时(这个过程称为变量解析),总会优先在当前作用域链的第一个对象中查找属性varible ,如果找到,则直接使用这个属性;否则,继续查找下一个对象的是否存在这个属性;这个过程会持续直至找到这个属性或者最终未找到引发错误为止

看个简单版的例子:

(function(){

    var hello="hello,world";

    function welcome(hi){

        alert(hi);        //解析到作用域链的第一个对象的属性

        alert(hello);    //解析到作用域链的第二个对象的属性

    }

    welcome("It's easy");

})();



运行结果很简单,一个弹窗It's easy.一个弹窗hello,world。
分析过程如下:
对于函数welcome(),定义welcome的时候会产生一个作用域链对象,为了表示方便,记作scopechain。scopechain是个有顺序的集合对象。

  • scopechain的第一个对象:为了方便表示记作sc1, sc1有若干属性,引用本函数的参数和局部变量,如sc1.hi ;
  • scopechain的第二个对象:为了方便表示记作sc2,sc2有若干属性,引用外层函数的参数和局部变量,如sc2.hello;
  • ...
  • scopechain的最后一个对象:为了方便表示记作scn,scn引用的全局的执行环境对象,也就是window对象!,如scn.eval();

 

这里之所以可以弹出hello,world,原因就是变量解析时在welcome函数作用域链的第一个对象上找不到hello属性,然后就去第二个对象上找去了(结果还真找到了)。

所以,JavaScript中的所谓的高大上的闭包其实很简单,根本上还是变量解析。而之所以可以实现,还是因为变量解析会在作用域链中依次寻找对应属性的导致的。

js闭包真是十分十分重要的,再怎么强调也不过分,因为他是js能力提升中无法绕过的一 ,几乎每次面试必问的问题,因为在回答的时候.你的答案的深度,对术语的理解以及js内部解释器的运作方式的描述,都是可以看出你js实际水平的.即使 你没答对,也能让考官对你的水平有个评估。所以一定要掌握吃透,理解!!

要理解闭包,首先你要理解js几个很基本的特性:执行环境、作用域链、垃圾回收机制、函数嵌套。

执行环境 
每调用一个函数时(执行函数时),系统会为该函数创建一个封闭的局部的运行环境,即该函数的执行环境。函数总是在自己的执行环境中执行,如读写局部变量、 函数参数、运行内部逻辑。创建执行环境的过程包含了创建函数的作用域,函数也是在自己的作用域下执行的。从另一个角度说,每个函数执行环境都有一个作用域 链,子函数的作用域链包括它的父函数的作用域链。

作用域链 
简单来说,作用域链就是函数在定义的时候创建的,用于寻找使用到的变量的值的一个索引,而他内部的规则是,把函数自身的本地变量放在最前面,把自身的父级 函数中的变量放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止.当函数中需要查询一个变量的值的时候,js解释器会去作用域链去查 ,从最前面的本地变量中先找,如果没有找到对应的变量,则到下一级的链上找,一旦找到了变量,则不再继续.如果找到最后也没找到需要的变量,则解释器返 undefined

垃圾回收机制 
一般来说,一个函数在执行开始的时候,会给其中定义的变量划分内存空间保存,以备后面的语句所用,等到函数执行完毕返回了,这些变量就被认为是无用的了. 对应的内存空间也就被回收了.下次再执行此函数的时候,所有的变量又回到最初的状态,重新赋值使用.但是如果这个函数内部又嵌套了另一个函数,而这个函数 是有可能在外部被调用到的.并且这个内部函数又使用了外部函数的某些变量的话.这种内存回收机制就会出现问题.如果在外部函数返回后,又直接调用了内部函 ,那么内部函数就无法读取到他所需要的外部函数中变量的值了.所以js解释器在遇到函数定义的时候,会自动把函数和他可能使用的变量(包括本地变量和父 级和祖先级函数的变量(自由变量))一起保存起来.也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用以后(例如被删 除了,或者没有了指针),才会销毁这个闭包,而没有任何一个闭包引用的变量才会被下一次内存回收启动时所回收.

各种专业文献上的闭包定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数(欢迎指正)。 
由于在js语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成定义在一个函数内部的函数 
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包可以用在许多地方。它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

举个栗子:

 function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){

      alert(n);

    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。 
为什么会这样呢?原因就在于f1f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制回收。

然而,由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。 
闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

如果看到这里还是不是很懂的话,转载了一篇很好的文章,http://www.felixwoo/archives/247“>这里写链接内容

一、什么是闭包? 
官方的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。 
相信很少有人能直接看懂这句话,因为他描述的太学术。其实这句话通俗的来说就是:JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的闭包。看下面这段代码:

function a() {

 var i = 0;

 function b() { alert(++i); }

 return b;

}

var c = a();

c();

这段代码有两个特点: 
1
、函数b嵌套在函数a内部; 
2
、函数a返回函数b 
引用关系如图: 
 

  这样在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说: 
  当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。 
  让我们说的更透彻一些。所谓闭包,就是在构造函数体内定义另外的函数作为目标对象的方法函数,而这个对象的方法函数反过来引用外层函数体中的临时 变量。这使得只要目标 对象在生存期内始终能保持其方法,就能间接保持原构造函数体当时用到的临时变量值。尽管最开始的构造函数调用已经结束,临时变量的名称也都消失了,但在目 标对象的方法内却始终能引用到该变量的值,而且该值只能通这种方法来访问。即使再次调用相同的构造函数,但只会生成新对象和方法,新的临时变量只是对应新 的值,和上次那次调用的是各自独立的。 
   
二、闭包有什么作用? 
  简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需 要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。 
在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c()i都是自加1alerti的值。

三、闭包内的微观世界 
  如果要更加深入的了解闭包以及函数a和嵌套函数b的关系,我们需要引入另外几个概念:函数的执行环境(excution context)、活动对象(call object)、作用域(scope)、作用域链(scope chain)。以函数a从定义到执行的过程为例阐述这几个概念。 
当定义函数a的时候,js解释器会将函数a的作用域链(scope chain)设置为定义aa所在的环境,如果a是一个全局函数,则scope chain中只有window对象。 
当执行函数a的时候,a会进入相应的执行环境(excution context) 
在创建执行环境的过程中,首先会为a添加一个scope属性,即a的作用域,其值就为第1步中的scope chain。即a.scope=a的作用域链。 
然后执行环境会创建一个活动对象(call object)。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过JavaScript代码直接访问。创建完活动对象后,把活动对象添加到a 的作用域链的最顶端。此时a的作用域链包含了两个对象:a的活动对象和window对象。 
下一步是在活动对象上添加一个arguments属性,它保存着调用函数a时所传递的参数。 
最后把所有函数a的形参和内部的函数b的引用也添加到a的活动对象上。在这一步中,完成了函数b的的定义,因此如同第3步,函数b的作用域链被设置为b所被定义的环境,即a的作用域。 
到此,整个函数a从定义到执行的步骤就完成了。此时a返回函数b的引用给c,又函数b的作用域链包含了对函数a的活动对象的引用,也就是说b可以访问到a中定义的所有变量和函数。函数bc引用,函数b又依赖函数a,因此函数a在返回后不会被GC回收。 
当函数b执行的时候亦会像以上步骤一样。因此,执行时b的作用域链包含了3个对象:b的活动对象、a的活动对象和window对象,如下图所示: 
 

如图所示,当在函数b中访问一个变量的时候,搜索顺序是: 
先搜索自身的活动对象,如果存在则返回,如果不存在将继续搜索函数a的活动对象,依次查找,直到找到为止。 
如果函数b存在prototype原型对象,则在查找完自身的活动对象后先查找自身的原型对象,再继续查找。这就是Javascript中的变量查找机制。 
如果整个作用域链上都无法找到,则返回undefined 
小结,本段中提到了两个重要的词语:函数的定义与执行。文中提到函数的作用域是在定义函数时候就已经确定,而不是在执行的时候确定(参看步骤13)。用一段代码来说明这个问题:

function f(x) {

  var g = function () { return x; }

  return g;

}

var h = f(1);

alert(h());

这段代码中变量h指向了f中的那个匿名函数(g返回) 
假设函数h的作用域是在执行alert(h())确定的,那么此时h的作用域链是:h的活动对象->alert的活动对象->window对象。 
假设函数h的作用域是在定义时确定的,就是说h指向的那个匿名函数在定义的时候就已经确定了作用域。那么在执行的时候,h的作用域链为:h的活动对象->f的活动对象->window对象。 
如果第一种假设成立,那输出值就是undefined;如果第二种假设成立,输出值则为1 
运行结果证明了第2个假设是正确的,说明函数的作用域确实是在定义这个函数的时候就已经确定了。

四、闭包的应用场景 
保护函数内的变量安全。以最开始的例子为例,函数ai只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。 
在内存中维持一个变量。依然如前例,由于闭包,函数ai的一直存在于内存中,因此每次执行c(),都会给i自加1 
通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问) 
私有属性和方法在Constructor外是无法被访问的

function Constructor(...) { 

  var that = this; 

  var membername = value;

  function membername(...) {...}

}

以上3点是闭包最基本的应用场景,很多经典案例都源于此。

五、Javascript的垃圾回收机制 
Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数ab引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

下面就是我的学习笔记,对于Javascript初学者应该是很有用的。

一、变量的作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

  var n=999;

  function f1(){

    alert(n);

  }

  f1(); // 999

另一方面,在函数外部自然无法读取函数内的局部变量。

  function f1(){

    var n=999;

  }

  alert(n); // error

这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

  function f1(){

    n=999;

  }

  f1();

  alert(n); // 999

二、如何从外部读取局部变量?

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

那就是在函数的内部,再定义一个函数。

  function f1(){

    var n=999;

    function f2(){

      alert(n); // 999

    }

  }

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,

f1就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会 "一级一级" 地向上寻找所有父对象的变量。

所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

  function f1(){

    var n=999;

    function f2(){

      alert(n); 

    }

    return f2;

  }

  var result=f1();

  result(); // 999

三、闭包的概念

上一节代码中的f2函数,就是闭包。

各种专业文献上的"闭包"closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

四、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

怎么来理解这句话呢?请看下面的代码。

  function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){

      alert(n);

    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000

这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1

因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。

其次,nAdd的值是一个匿名函数anonymous function),而这个匿名函数本身也是一个闭包,

所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

五、使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。

解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),

把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

六、思考题

如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。

代码片段一。

  var name = "The Window";

  var object = {

    name : "My Object",

    getNameFunc : function(){//alert(this.name);//My Object

      return function(){

        return this.name;// 

      };

    }

  };

        alert(this.name);// The Window

  alert(object.getNameFunc()()); // 

 

代码片段二。

  var name = "The Window";

  var object = {

    name : "My Object",

    getNameFunc : function(){

      var that = this;

      return function(){

        return that.name;

      };

    }

  };

  alert(object.getNameFunc()()); // My Object

 

一层访问一层,不能跨层访问

 

作用域

作用域链

作用域

先来谈谈变量的作用域 
变量的作用域无非就是两种:全局变量和局部变量。 
全局作用域: 
最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的:

<script>
      var outerVar = "outer";
      function fn(){
         console.log(outerVar);
      }
      fn();//result:outer
   </script>

局部作用域: 
和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无法访问的,最常见的例如函数内部

<script>
      function fn(){
         var innerVar = "inner";
      }
      fn();
      console.log(innerVar);// ReferenceError: innerVar is not defined
</script>

需要注意的是,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

   <script>
      function fn(){
         innerVar = "inner";
      }
      fn();
      console.log(innerVar);// result:inner
   </script>

再来看一个代码:

   <script>
      var scope = "global";
      function fn(){
         console.log(scope);//result:undefined
         var scope = "local";
         console.log(scope);//result:local;
      }
      fn();
   </script>

很有趣吧,第一个输出居然是undefined,原本以为它会访问外部的全局变量(scope=”global”),但是并没有。这可以算是javascript的一个特点,只要函数内定义了一个局部变量,函数在解析的时候都会将这个变量提前声明

   <script>
      var scope = "global";
      function fn(){
         var scope;//提前声明了局部变量
         console.log(scope);//result:undefined
         scope = "local";
         console.log(scope);//result:local;
      }
      fn();
   </script>

然而,也不能因此草率地将局部作用域定义为:用var声明的变量作用范围起止于花括号之间。 
javascript
并没有块级作用域 
那什么是块级作用域? 
像在C/C++中,花括号内中的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的,比如下面的c语言代码

for(int i = 0; i < 10; i++){
//i的作用范围只在这个for循环
}
printf("%d",&i);//error

但是javascript不同,并没有所谓的块级作用域,javascript的作用域是相对函数而言的,可以称为函数作用域:

   <script>
      for(var i = 1; i < 10; i++){
            //coding
      }
      console.log(i); //10  
   </script>

 

作用域链(Scope Chain

那什么是作用域链? 
我的理解就是,根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问。 
想要知道js怎么链式查找,就得先了解js的执行环境

执行环境(execution context

每个函数运行时都会产生一个执行环境,而这个执行环境怎么表示呢?js为每一个执行环境关联了一个变量对象。环境中定义的所有变量和函数都保存在这个对象中。 
全局执行环境是最外围的执行环境,全局执行环境被认为是window对象,因此所有的全局变量和函数都作为window对象的属性和方法创建的。 
js
的执行顺序是根据函数的调用来决定的,当一个函数被调用时,该函数环境的变量对象就被压入一个环境栈中。而在函数执行之后,栈将该函数的变量对象弹出,把控制权交给之前的执行环境变量对象。 
举个例子:

   <script>
      var scope = "global"; 
      function fn1(){
         return scope; 
      }
      function fn2(){
         return scope;
      }
      fn1();
      fn2();
   </script>

上面代码执行情况演示: 

了解了环境变量,再详细讲讲作用域链。 
当某个函数第一次被调用时,就会创建一个执行环境(execution context)以及相应的作用域链,并把作用域链赋值给一个特殊的内部属性([scope])。然后使用thisarguments(arguments在全局环境中不存在)和其他命名参数的值来初始化函数的活动对象(activation object)。当前执行环境的变量对象始终在作用域链的第0位。 
以上面的代码为例,当第一次调用fn1()时的作用域链如下图所示: 
(因为fn2()还没有被调用,所以没有fn2的执行环境) 
 

可以看到fn1活动对象里并没有scope变量,于是沿着作用域链(scope chain)向后寻找,结果在全局变量对象里找到了scope,所以就返回全局变量对象里的scope值。

标识符解析是沿着作用域链一级一级地搜索标识符地过程。搜索过程始终从作用域链地前端开始,然后逐级向后回溯,直到找到标识符为止(如果找不到标识符,通常会导致错误发生)—-JavaScript高级程序设计》

那作用域链地作用仅仅只是为了搜索标识符吗? 
再来看一段代码:

   <script>
      function outer(){
         var scope = "outer";
         function inner(){
            return scope;
         }
         return inner;
      }
      var fn = outer();
      fn();
   </script>

outer()内部返回了一个inner函数,当调用outer时,inner函数的作用域链就已经被初始化了(复制父函数的作用域链,再在前端插入自己的活动对象),具体如下图: 
 

一般来说,当某个环境中的所有代码执行完毕后,该环境被销毁(弹出环境栈),保存在其中的所有变量和函数也随之销毁(全局执行环境变量直到应用程序退出,如网页关闭才会被销毁) 
但是像上面那种有内部函数的又有所不同,当outer()函数执行结束,执行环境被销毁,但是其关联的活动对象并没有随之销毁,而是一直存在于内存中,因为该活动对象被其内部函数的作用域链所引用。 
具体如下图: 
outer
执行结束,内部函数开始被调用 
outer
执行环境等待被回收,outer的作用域链对全局变量对象和outer的活动对象引用都断了 

像上面这种内部函数的作用域链仍然保持着对父函数活动对象的引用,就是闭包(closure)

闭包

闭包有两个作用: 
第一个就是可以读取自身函数外部的变量(沿着作用域链寻找) 
第二个就是让这些外部变量始终保存在内存中 
关于第二点,来看一下以下的代码:

   <script>
      function outer(){
         var result = new Array();
         for(var i = 0; i < 2; i++){//注:i是outer()的局部变量
            result[i] = function(){
               return i;
            }
         }
         return result;//返回一个函数对象数组
         //这个时候会初始化result.length个关于内部函数的作用域链
      }
      var fn = outer();
      console.log(fn[0]());//result:2
      console.log(fn[1]());//result:2
   </script>

返回结果很出乎意料吧,你肯定以为依次返回01,但事实并非如此 
来看一下调用fn[0]()的作用域链图: 

可以看到result[0]函数的活动对象里并没有定义i这个变量,于是沿着作用域链去找i变量,结果在父函数outer的活动对象里找到变量i(值为2),而这个变量i是父函数执行结束后将最终值保存在内存里的结果。 
由此也可以得出,js函数内的变量值不是在编译的时候就确定的,而是等在运行时期再去寻找的。

那怎么才能让result数组函数返回我们所期望的值呢? 
看一下result的活动对象里有一个argumentsarguments对象是一个参数的集合,是用来保存对象的。 
那么我们就可以把i当成参数传进去,这样一调用函数生成的活动对象内的arguments就有当前i的副本。 
改进之后:

   <script>
      function outer(){
         var result = new Array();
         for(var i = 0; i < 2; i++){
            //定义一个带参函数
            function arg(num){
               return num;
            }
            //把i当成参数传进去
            result[i] = arg(i);
         }
         return result;
      }
      var fn = outer();
      console.log(fn[0]);//result:0
      console.log(fn[1]);//result:1
   </script>

虽然的到了期望的结果,但是又有人问这算闭包吗?调用内部函数的时候,父函数的环境变量还没被销毁呢,而且result返回的是一个整型数组,而不是一个函数数组! 
确实如此,那就让arg(num)函数内部再定义一个内部函数就好了: 
这样result返回的其实是innerarg()函数

   <script>
      function outer(){
         var result = new Array();
         for(var i = 0; i < 2; i++){
            //定义一个带参函数
            function arg(num){
               function innerarg(){
                  return num;
               }
               return innerarg;
            }
            //把i当成参数传进去
            result[i] = arg(i);
         }
         return result;
      }
      var fn = outer();
      console.log(fn[0]());
      console.log(fn[1]());
   </script>

当调用outerfor循环内i=0时的作用域链图如下: 
 

由上图可知,当调用innerarg()时,它会沿作用域链找到父函数arg()活动对象里的arguments参数num=0. 
上面代码中,函数argouter函数内预先被调用执行了,对于这种方法,js有一种简洁的写法

    function outer(){
         var result = new Array();
         for(var i = 0; i < 2; i++){
            //定义一个带参函数
            result[i] = function(num){
               function innerarg(){
                  return num;
               }
               return innerarg;
            }(i);//预先执行函数写法
            //i当成参数传进去
         }
         return result;
      }

关于this对象

关于闭包经常会看到这么一道题:

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
  alert(object.getNameFunc()());//result:The Window

javascript高级程序设计》一书给出的解释是:

this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象调用时,this等于那个对象。不过,匿名函数具有全局性,因此this对象同常指向window

 

Cdn

视界云

已认证的官方帐号

110 人赞同了该回答

CDN

全称:Content Delivery Network或Content Ddistribute Network,即内容分发网络

 

基本思路

尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。

 

目的

解决因分布、带宽、服务器性能带来的访问延迟问题,适用于站点加速、点播、直播等场景。使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度和成功率。

控制时延无疑是现代信息科技的重要指标,CDN的意图就是尽可能的减少资源在转发、传输、链路抖动等情况下顺利保障信息的连贯性。

CDN就是扮演者护航者和加速者的角色,更快准狠的触发信息和触达每一个用户,带来更为极致的使用体验。
再通俗点说就是在网速一定的前提下,CDN就像网络中快递员小哥

 

而且CDN这个快递员很是聪明
TA不是在用蛮力瞎跑、乱撞

 

TA还承建了很多家快递点,就近快递(缓存)

TA善于优化快递路径(调度)
还会对包裹进行更合理的重新打包(协议优化)

 

基础架构:最简单的CDN网络由一个DNS服务器和几台缓存服务器组成:

  1. 当用户点击网站页面上的内容URL,经过本地DNS系统解析,DNS系统会最终将域名的解析权交给CNAME指向的CDN专用DNS服务器。
  2. CDN的DNS服务器将CDN的全局负载均衡设备IP地址返回用户。
  3. 用户向CDN的全局负载均衡设备发起内容URL访问请求。
  4. CDN全局负载均衡设备根据用户IP地址,以及用户请求的内容URL,选择一台用户所属区域的区域负载均衡设备,告诉用户向这台设备发起请求。
  5. 区域负载均衡设备会为用户选择一台合适的缓存服务器提供服务,选择的依据包括:根据用户IP地址,判断哪一台服务器距用户最近;根据用户所请求的URL中携带的内容名称,判断哪一台服务器上有用户所需内容;查询各个服务器当前的负载情况,判断哪一台服务器尚有服务能力。基于以上这些条件的综合分析之后,区域负载均衡设备会向全局负载均衡设备返回一台缓存服务器的IP地址。
  6. 全局负载均衡设备把服务器的IP地址返回给用户。
  7. 用户向缓存服务器发起请求,缓存服务器响应用户请求,将用户所需内容传送到用户终端。如果这台缓存服务器上并没有用户想要的内容,而区域均衡设备依然将它分配给了用户,那么这台服务器就要向它的上一级缓存服务器请求内容,直至追溯到网站的源服务器将内容拉到本地。

 

服务模式:

简单地说,CDN是一个经策略性部署的整体系统,包括分布式存储、负载均衡、网络请求的重定向和内容管理4个要件,而内容管理和全局的网络流量管理(Traffic Management)是CDN的核心所在。

通过用户就近性和服务器负载的判断,CDN确保内容以一种极为高效的方式为用户的请求提供服务。

举例说明:

国内访问量较高的网站、直播、视频平台,均使用CDN网络加速技术,虽然网站的访问巨大,但无论在什么地方访问都会感觉速度很快。而一般的网站如果服务器在网通,电信用户访问很慢,如果服务器在电信,网通用户访问又很慢。

通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的cache服务器内,通过DNS负载均衡的技术,判断用户来源就近访问cache服务器取得所需的内容,解决Internet网络拥塞状况,提高用户访问网站的响应速度,如同提供了多个分布在各地的加速器,以达到快速、可冗余的为多个网站加速的目的。

CDN服务最初用于确保快速可靠地分发静态内容,这些内容可以缓存,最适合在网速庞大的网络中存储和分发,该网络在几十多个国家的十几个网络中的覆盖CDN网络服务器。由于动态内容必须通过互联网来传输,因此要提供快速的网络体验。如今的CDN可谓是大文件、小文件、点播、直播、动静皆宜!

 

 

主要特点:

1、本地Cache加速,提高了企业站点(尤其含有大量图片和静态页面站点)的访问速度,并大大提高以上性质站点的稳定性

2、镜像服务消除了不同运营商之间互联的瓶颈造成的影响,实现了跨运营商的网络加速,保证不同网络中的用户都能得到良好的访问质量。

3、远程加速 远程访问用户根据DNS负载均衡技术 智能自动选择Cache服务器,选择最快的Cache服务器,加快远程访问的速度

4、带宽优化 自动生成服务器的远程Mirror(镜像)cache服务器,远程用户访问时从cache服务器上读取数据,减少远程访问的带宽、分担网络流量、减轻原站点WEB服务器负载等功能。

5、集群抗攻击 广泛分布的CDN节点加上节点之间的智能冗余机制,可以有效地预防黑客入侵以及降低各种D.D.o.S攻击对网站的影响,同时保证较好的服务质量 。

 

关键技术:

 

内容发布:它借助于建立索引、缓存、流分裂、组播(Multicast)等技术

内容路由:它是整体性的网络负载均衡技术,通过内容路由器中的重定向(DNS)机制,在多个远程POP上均衡用户的请求,以使用户请求得到最近内容源的响应;

内容交换:它根据内容的可用性、服务器的可用性以及用户的背景,在POP的缓存服务器上,利用应用层交换、流分裂、重定向(ICP、WCCP)等技术,智能地平衡负载流量;

性能管理:它通过内部和外部监控系统,获取网络部件的状况信息,测量内容发布的端到端性能(如包丢失、延时、平均带宽、启动时间、帧速率等),保证网络处于最佳的运行状态。

 

适用范围:

一般来说以资讯、内容等为主的网站,具有一定访问体量的网站

例如资讯网站、政府机构网站、行业平台网站、商城等以动态内容为主的网站

例如论坛、博客、交友、SNS、网络游戏、搜索/查询、金融等。提供http下载的网站

例如软件开发商、内容服务提供商、网络游戏运行商、源码下载等有大量流媒体点播应用的网站

例如:拥有视频点播平台的电信运营商、内容服务提供商、体育频道、宽频频道、在线教育、视频博客等

 

Q & A

1.CDN加速是对网站所在服务器加速,还是对其域名加速?

CDN是只对网站的某一个具体的域名加速。如果同一个网站有多个域名,则访客访问加入CDN的域名获得加速效果,访问未加入CDN的域名,或者直接访问IP地址,则无法获得CDN效果。

2.CDN和镜像站点比较有何优势?  

CDN对网站的访客完全透明,不需要访客手动选择要访问的镜像站点,保证了网站对访客的友好性。  
CDN对每个节点都有可用性检查,不合格的节点会第一时间剔出,从而保证了极高的可用率,而镜像站点无法实现这一点。  
CDN部署简单,对原站基本不做任何改动即可生效。

3.CDN和双线机房相比有何优势?

常见的双线机房只能解决网通和电信互相访问慢的问题,其它ISP(譬如教育网,移动网,铁通)互通的问题还是没得到解决。  
而CDN是访问者就近取数据,而CDN的节点遍布各ISP,从而保证了网站到任意ISP的访问速度。另外CDN因为其流量分流到各节点的原理,天然获得抵抗网络攻击的能力。

4.CDN使用后,原来的网站是否需要做修改,做什么修改?

一般而言,网站无需任何修改即可使用CDN获得加速效果。只是对需要判断访客IP程序,才需要做少量修改。

5.为什么我的网站更新后,通过CDN后看到网页还是旧网页,如何解决?  

由于CDN采用各节点缓存的机制,网站的静态网页和图片修改后,如果CDN缓存没有做相应更新,则看到的还是旧的网页。
为了解决这个问题,CDN管理面板中提供了URL推送服务,来通知CDN各节点刷新自己的缓存。  
在URL推送地址栏中,输入具体的网址或者图片地址,则各节点中的缓存内容即被统一删除,并且当即生效。  
如果需要推送的网址和图片太多,可以选择目录推送,输入
http://www.kkk/news 即可以对网站下news目录下所有网页和图片进行了刷新。

6.能不能让CDN不缓存某些即时性要求很高的网页和图片?

只需要使用动态页面,asp,php,jsp等动态技术做成的页面不被CDN缓存,无需每次都要刷新。或者采用一个网站两个域名,一个启用CDN,另外一个域名不用CDN,对即时性要求高的页面和图片放在不用CDN的域名下。

7.网站新增了不少网页和图片,这些需要使用URL推送吗?  

后来增加的网页和图片,不需要使用URL推送,因为它们本来就不存在缓存中。

8.网站用CDN后,有些地区反映无法访问了,怎么办?

CDN启用后,访客不能访问网站有很多种可能,可能是CDN的问题,也可能是源站点出现故障或者源站点被关闭,还可能是访客自己所在的网络出现问题,甚至我们实际故障排除中,还出现过客户自己计算机中毒,导致无法访问网站。  
客户报告故障时,可随时联系我们24小时技术部进行处理。

9.哪些情况不适用于CDN?

备注:此类极端状况不建议您使用CDN服务

 

重绘和重排,以及怎么解决

一个页面由两部分组成:
DOM:描述该页面的结构
render:描述 DOM 节点 (nodes) 在页面上如何呈现

DOM 元素的属性发生变化 ( color) , 浏览器会通知 render 重新描绘相应的元素, 此过程称为 repaint

如果该次变化涉及元素布局 ( width), 浏览器则抛弃原有属性, 重新计算并把结果传递给 render 以重新描绘页面元素, 此过程称为 reflow

这两个过程是很耗费浏览器性能的, IE 系列和 Chrome 渲染页面速度上的差距即可看出渲染引擎计算对应值和呈现并不一定高效, 而每次对元素的操作都会发生 repaints reflow, 因此编写 DOM 交互时如果不注意就会导致页面性能低下.
页面渲染的过程如下:

1.解析HTML代码并生成一个 DOM 树。

2.解析CSS文件,顺序为:浏览器默认样式->自定义样式->页面内的样式。

3.生成一个渲染树(render tree)。这个渲染树和DOM树的不同之处在于,它是受样式影响的。它不包括那些不可见的节点。

4.当渲染树生成之后,浏览器就会在屏幕上出所有渲染树中的节点。

 

不管页面发生了重绘还是重排,它们都会影响性能(最可怕的是重排 ,应尽量避免) 
 

下列情况会发生重排

  • 页面初始渲染
  • 添加/删除可见DOM元素
  • 改变元素位置
  • 改变元素尺寸(宽、高、内外边距、边框等)
  • 改变元素内容(文本或图片等)
  • 改变窗口尺寸

怎么减少重排?说一下我的方法:


 

1.分离读写操作

var curLeft=div.offsetLeft;

var curTop=div.offsetTop;

div.style.left=curLeft+1+'px';

div.style.top=curTop+1+'px';


 

2.样式集中改变 

可以添加一个类,样式都在类中改变

3.可以使用absolute脱离文档流。

4.使用 display:none ,不使用 visibility,也不要改变 它的 z-index

5.能用css3实现的就用css3实现。


 

如何在浏览器中查看页面渲染时间


 

1.打开开发者工具:点击TimeLine 左侧有个小圆点 点击刷新页面会录制整个页面加载出来 时间的分配情况。如下图

 

 

下面具体的说一下这几个过程:点击 Event Log :单独勾选Loading项会显示html css 加载时间。如下图:

 

 

解析完DOM+css之后会生成一个渲染树 Render Tree,就是 dom css 的一一对应关系。

DOM+css= Render Tree 

layout:  重排 ,又叫回流。

paint:重绘 也可以在Event Log里看的到,这里就不附图了。

重排重绘这些步骤都是在cpu中发生的。

最后  compostite Layers阶段,cpu 把生成的 BitMap(位图)传输到GPU,渲染到屏幕。 css3就是在GPU发生的:transform  opacity

GPU发生的属性比较高效。所以css3性能比较高。

小结:

渲染的三个阶段 Layout ,Paint,Composite Layers

修改不同的css属性会触发不同阶段。

触发的阶段越前,渲染的代价越高。

浏览器重绘与重排的性能优化

20161125 21:54:30

阅读数:3152

了解了浏览器渲染原理之后 
我们知道了浏览器听过渲染树计算布局后,就开始绘制页面元素 
但是渲染树并不是一成不变的,在我们的脚本当中 
它是可能改变的

重绘与重排

DOM变化影响了元素的几何属性(宽、高改变等等) 
浏览器此时需要重新计算元素几何属性 
并且页面中其他元素的几何属性可能会受影响 
这样渲染树就发生了改变,也就是重新构造RenderTree渲染树 
这个过程叫做重排(reflow

如果DOM变化仅仅影响的了背景色等等非几何属性 
此时就发生了重绘(repaint而不是重排 
因为布局没有发生改变


不管页面发生了重绘还是重排,它们都会影响性能(重绘还好一些) 
能避免要尽量避免

触发重排

页面布局和元素几何属性的改变就会导致重排 
下列情况会发生重排

  • 页面初始渲染
  • 添加/删除可见DOM元素
  • 改变元素位置
  • 改变元素尺寸(宽、高、内外边距、边框等)
  • 改变元素内容(文本或图片等)
  • 改变窗口尺寸

不同的条件下发生重排的范围及程度会不同 
某些情况甚至会重排整个页面,比如滑动滚动条

浏览器的优化:渲染队列

举个小例子 
比如我们想用js中修改一个div元素的样式 
写下了以下代码

div.style.left = '10px';
div.style.top = '10px';
div.style.width = '20px';
div.style.height = '20px';

我们修改了元素的lefttopwidthheight属性 
满足我们发生重排的条件 
理论上会发生4次重排 
但是实际上只会发生1次重排 
这是因为我们现代的浏览器都有渲染队列的机制 
当我改变了元素的一个样式会导致浏览器发生重排或重绘时 
它会进入一个渲染队列 
然后浏览器继续往下看,如果下面还有样式修改 
那么同样入队 
直到下面没有样式修改 
浏览器会按照渲染队列批量执行来优化重排过程,一并修改样式 
这样就把本该4次的重排优化为1


但是我们现在想要修改样式后在控制台打印

div.style.left = '10px';
console.log(div.offsetLeft);
div.style.top = '10px';
console.log(div.offsetTop);
div.style.width = '20px';
console.log(div.offsetWidth);
div.style.height = '20px';
console.log(div.offsetHeight);

千万不要写这样的代码,因为发生了4次重排 
有同学可能不懂了,不是说浏览器有渲染队列优化机制吗? 
为什么这样写就会发生4次重排 
因为offsetLeft/Top/Width/Height非常叼 
它们会强制刷新队列要求样式修改任务立刻执行 
想一想其实这么做是有道理的 
毕竟浏览器不确定在接下来的代码中你是否还会修改同样的样式 
为了保证获得正确的值,它不得不立刻执行渲染队列触发重排(错的不是我,是这个世界)


以下属性或方法会刷新渲染队列

  • offsetTop、offsetLeft、offsetWidth、offsetHeight
  • clientTop、clientLeft、clientWidth、clientHeight
  • scrollTop、scrollLeft、scrollWidth、scrollHeight
  • getComputedStyle()(IE中currentStyle)

我们在修改样式过程中,要尽量避免使用上面的属性

重绘与重排的性能优化

分离读写操作

了解了原理我们就可以对上面的代码进行优化

div.style.left = '10px';
div.style.top = '10px';
div.style.width = '20px';
div.style.height = '20px';
console.log(div.offsetLeft);
console.log(div.offsetTop);
console.log(div.offsetWidth);
console.log(div.offsetHeight);

这样就仅仅发生1次重排了,原因相信大家已经很清晰了 
把所有的读操作移到所有写操作之后 
效率高多了 
这是其中一种优化的方法

样式集中改变

还是我们最初修改样式的代码

div.style.left = '10px';
div.style.top = '10px';
div.style.width = '20px';
div.style.height = '20px';

虽然现代浏览器有渲染队列的优化机制 
但是古董浏览器效率仍然底下,触发了4次重排 
即便这样,我们仍然可以做出优化 
我们需要cssText属性合并所有样式改变

div.style.cssText = 'left:10px;top:10px;width:20px;height:20px;';

 

这样只需要修改DOM一次一并处理 
仅仅触发了1次重排 
而且只用了一行代码,看起来相对干净一些

不过有一点要注意,cssText会覆盖已有的行间样式 
如果想保留原有行间样式,这样做

div.style.cssText += ';left:10px;';

除了cssText以外,我们还可以通过修改class类名来进行样式修改

div.className = 'new-class';

这种办法可维护性好,还可以帮助我们免除显示性代码 
(有一点点性能影响,改变class需要检查级联样式,不过瑕不掩瑜)

缓存布局信息

我觉得缓存真是万金油,哪种性能优化都少不了它

div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';

这种读操作完就执行写操作造成了2次重排 
缓存可以进行优化

var curLeft = div.offsetLeft;
var curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';

这也相当于是分离读写操作了 
优化为1次重排

元素批量修改

现在我们想要向ul中循环添加大量li 
(如果ul还不存在,最好的办法是先循环添加liul,然后再把ul添加到文档,1次重排)

var ul = document.getElementById('demo');
for(var i = 0; i < 1e5; i++){
    var li = document.createElement('li');
    var text = document.createTextNode(i);
    li.appendChild(text);
    ul.appendChild(li);
}

我可以做出下面的优化

var ul = document.getElementById('demo');
ul.style.display = 'none'; <--
for(var i = 0; i < 1e5; i++){
    var li = document.createElement('li');
    var text = document.createTextNode(i);
    li.appendChild(text);
    ul.appendChild(li);
}
ul.style.display = 'block'; <--
var ul = document.getElementById('demo');
var frg = document.createDocumentFragment(); <--
for(var i = 0; i < 1e5; i++){
    var li = document.createElement('li');
    var text = document.createTextNode(i);
    li.appendChild(text);
    frg.appendChild(li); <--
}
ul.appendChild(frg); <--
var ul = document.getElementById('demo');
var clone = ul.cloneNode(true); <--
for(var i = 0; i < 1e5; i++){
    var li = document.createElement('li');
    var text = document.createTextNode(i);
    li.appendChild(text);
    clone.appendChild(li); <--
}
ul.parentNode.replaceChild(clone,ul); <--

上面的方法减少重绘和重排的原理很简单

  • 元素脱离文档
  • 改变样式
  • 元素回归文档

而改变元素就分别使用了隐藏元素、文档碎片和克隆元素 
上面的方法我认为仅仅是理论上可以优化重排重绘次数 
现代浏览器的优化可能会超过我们的想象

 

Xss和csrf

XSS:跨站脚本攻击,注入攻击的一种。攻击者利用应用程序的动态展示功能,在HTML页面中嵌入恶意代码。当用户浏览该页时,这些嵌入在html的恶意代码就会被执行,用户浏览器被攻击者控制。。。。

1.盗取用户cookie,伪造用户身份
2.控制用户浏览器
3.结合浏览器及其插件漏洞,下载病毒木马到浏览者的计算机运行
4.衍生URL跳转漏洞
5.官网挂钓鱼网站
6.蠕虫攻击
 

CSRF:跨站请求伪造(冒充用户之手,伪造请求)。

-->横向提权(修改个人数据);纵向提权(添加用户);

XSSvsCSRF:XSS 是实现 CSRF 的诸多途径中的一条,但绝对不是唯一的一条。一般习惯上把通过 XSS 来实现的 CSRF 称为 XSRF。

严格意义上来说,CSRF 不能分类为注入攻击,因为 CSRF 的实现途径远远不止 XSS 注入这一条。通过 XSS 来实现 CSRF 易如反掌,但对于设计不佳的网站,一条正常的链接都能造成 CSRF

例如,一论坛网站的发贴是通过 GET 请求访问,点击发贴之后 JS 把发贴内容拼接成目标 URL 并访问: http://example/bbs/create_post.php?title=标题&content=内容 那么,我只需要在论坛中发一帖,包含一链接: http://example/bbs/create_post.php?title=我是脑残&content=哈哈只要有用户点击了这个链接,那么他们的帐户就会在不知情的情况下发布了这一帖子。可能这只是个恶作剧,但是既然发贴的请求可以伪造,那么删帖、转帐、改密码、发邮件全都可以伪造。

总体来说,目前防御 CSRF 的诸多方法还没几个能彻底无解的,只能通过提高攻击门槛尽可能的防御。

针对表单比较可行的解决方案遵循三步:

1.在用户登录时,设置一个CSRF的随机token,同时种植在用户的cookie中,当用户浏览器关闭或者再次登录、退出时,清除token;

2.在表单中,生成一个隐藏域,它的值就是cookie中随机token

3.表单提交后,在web服务器端,判断表单中是token是否和用户cookie中的token一致,如果不一致或者为空,就判断为CSRF攻击。


 

当出现GET请求修改用户数据时,一旦在url中出现了csrftoken,当前页面就不允许出现用户定义的站外链接,否则攻击者可以诱惑用户点击攻击者定义的链接,访问在自己的网站,从refer中,获取url中的csrftoken。

作者:李上天
链接:https://www.zhihu/question/34445731/answer/86381916
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

马三立小品〈逗你玩〉中的小偷就利用xss突破了防盗系统。

防盗系统启动:
妈妈:给我看着衣服
小孩:好的

小偷来

正常工作:
小孩:你是谁?
小偷:我叫张三
小孩:妈妈,有人偷衣服
妈妈:谁?
小孩:张三
小偷被捉

漏洞:
小孩:你是谁?
小偷:我叫逗你玩
小孩:妈妈,有人偷衣服
妈妈:谁?
小孩:逗你玩
妈妈:。。。

csrf是让用户在不知情的情况,冒用其身份发起了一个请求
小偷:你妈妈喊你去买洗衣粉
----------------------------------------------
补充一下,XSS本质是Html注入,和SQL注入差不多。
SQL、Html、人类语言都是指令和数据混在一起,都存在注入风险(程序根据分隔符、标签识别指令和数据,人类则是根据语境、语义和日常经验判断)。
比如注册用户时,用户输入“张三”并提交,服务端会生成“ <p>欢迎新用户,张三</p> ”传给浏览器。如果用户输入"<script>alert('逗你玩')<script>",服务端会生成 “<p>欢迎新用户,<script>alert('逗你玩')<script></p>”,输入内容就会被浏览器识别为指令执行,这就是XSS注入;
小偷也是根据这个原理,输入一个有特殊语义的名字,被其他客户端识别为指令,从而完成了一次漂亮的存储型XSS注入攻击。

 

为什么静态页面会单独存储

在大型网站中,我们发现页面资源经常使用不同的域名进行引用,例如126邮箱的部分js、css、图片存放于http://mimg.127/域名下,京东的部分静态图片存放在http://img11.360buyimg域名下,那这样做究竟有什么好处呢,和性能又有什么关系呢,下面进行具体分析。


 

一、浏览器并发请求数的限制
 

我们进行网站页面访问时的客户端是浏览器,浏览器的很多机制对网站的访问速度有很大的影响(例如浏览器对静态资源的缓存机制),此外浏览器为提升页面显示效率,支持并发获取资源,如下是不同浏览器的版本对并发的支持:


 


 

浏览器对并发请求的数目限制是针对域名的,即针对同一域名(包括二级域名)在同一时间支持的并发请求数量的限制。如果请求数目超出限制,则会阻塞。因此,网站中对一些静态资源,使用不同的一级域名,可以提升浏览器并行请求的数目,加速界面资源的获取速度。
 


 

二、网络请求时cookie传输

当静态资源与主服务在同一域名下(根据业务需要,主服务请求时需要传递cookie信息),每次静态资源的请求,都会发送同域名下的cookie。而对于静态资源,服务器无需对cookie进行任何处理,它们只是在毫无意义的消耗带宽。

假设网站cookie信息有1 KB、网站首页共150个资源时,用户在请求过程中需要发送150 KB的cookie信息,在512 Kbps的常见上行带宽下,需要长达3秒左右才能全部发送完毕。很多情况下cookie的path是在整个一级域名下可用的,如果你把静态资源设置成二级域名,那么它也避免不了cookie。例如如果给 http://126 设置了cookie,那么会感染所有子域名, 请求 http://www.126/logo.gif或者http://image.126/logo.gif 时便会带上讨厌的cookie。

所以对于静态资源使用单独的域名,并设置为无cookie,以减少请求大小,提高网页性能。


 

三、方便分流或缓存

我们知道,当面对大并发访问时,在服务端会有相应的缓存机制,例如我们会在CDN中缓存一些静态资源,以便用户可以通过就近的网络节点获取资源。例如新浪微博在加载资源时,很多就放在了阿里的CDN上:


此外,独立的域名也方便我们在代理服务层做动静分离,以便提升静态请求的处理速度。

在明白动态网页和静态网页之前,首先要明白网站服务器和客户机的概念。

像新浪网战,搜狐网站,这都是网站服务器,里面存储了好多各式各样的网页文件。

你我用的电脑是客户机,我们使用IE浏览器登录到网站上,下载下来网页文件,经过解析就变成了花花绿绿的好看的页面,呈现在我们面前。

静态网页,一般来说是最简单的HTML网页,服务器端和客户端是一样的,而且没有脚本和小程序,所以它不能动。

动态网页包括服务器端动态网页和客户机端动态网页。

所谓服务器端动态网页,是指网页里包含在服务器上运行的脚本和小程序,网页在下载到我们的电脑之前,先要在服务器上运行一下其中的脚本和小程序。比如,我们输入用户名和密码,登录到爱问,爱问在右侧就能显示我们的用户名和积分。这就是服务器端的动态网页。

客户机端动态网页,是指网页里包含在客户机上运行的脚本和小程序。比如,新浪主页会有一些小广告飞来飞去,这就是客户机端动态网页。

简单来讲:静态网页谁看都一样,而且不能动;客户机端动态网页也是谁看都一样,但能动;服务器端动态网页每个人看的都不一样,能动。

F
ontpage
主要是设计静态网页的,设计动态网页的能力很弱。

 

继承

Css3的动画

CSS3 动画

通过 CSS3,我们能够创建动画,这可以在许多网页中取代动画图片、Flash 动画以及 JavaScript

CSS3 动画

CSS3 @keyframes 规则

如需在 CSS3 中创建动画,您需要学习 @keyframes 规则。

@keyframes 规则用于创建动画。在 @keyframes 中规定某项 CSS 样式,就能创建由当前样式逐渐改为新样式的动画效果。

浏览器支持

属性

浏览器支持

@keyframes

     

animation

     

Internet Explorer 10Firefox 以及 Opera 支持 @keyframes 规则和 animation 属性。

Chrome Safari 需要前缀 -webkit-

注释:Internet Explorer 9,以及更早的版本,不支持 @keyframe 规则或 animation 属性。

实例

@keyframes myfirst
{
from {background: red;}
to {background: yellow;}
}
 
@-moz-keyframes myfirst /* Firefox */
{
from {background: red;}
to {background: yellow;}
}
 
@-webkit-keyframes myfirst /* Safari 和 Chrome */
{
from {background: red;}
to {background: yellow;}
}
 
@-o-keyframes myfirst /* Opera */
{
from {background: red;}
to {background: yellow;}
}

CSS3 动画

当您在 @keyframes 中创建动画时,请把它捆绑到某个选择器,否则不会产生动画效果。

通过规定至少以下两项 CSS3 动画属性,即可将动画绑定到选择器:

  • 规定动画的名称
  • 规定动画的时长

实例

"myfirst" 动画捆绑到 div 元素,时长:5 秒:

div
{
animation: myfirst 5s;
-moz-animation: myfirst 5s; /* Firefox */
-webkit-animation: myfirst 5s;     /* Safari 和 Chrome */
-o-animation: myfirst 5s;   /* Opera */
}

亲自试一试

注释:您必须定义动画的名称和时长。如果忽略时长,则动画不会允许,因为默认值是 0

什么是 CSS3 中的动画?

动画是使元素从一种样式逐渐变化为另一种样式的效果。

您可以改变任意多的样式任意多的次数。

请用百分比来规定变化发生的时间,或用关键词 "from" "to",等同于 0% 100%

0% 是动画的开始,100% 是动画的完成。

为了得到最佳的浏览器支持,您应该始终定义 0% 100% 选择器。

实例

当动画为 25% 50% 时改变背景色,然后当动画 100% 完成时再次改变:

@keyframes myfirst
{
0%   {background: red;}
25%  {background: yellow;}
50%  {background: blue;}
100% {background: green;}
}
 
@-moz-keyframes myfirst /* Firefox */
{
0%   {background: red;}
25%  {background: yellow;}
50%  {background: blue;}
100% {background: green;}
}
 
@-webkit-keyframes myfirst /* Safari 和 Chrome */
{
0%   {background: red;}
25%  {background: yellow;}
50%  {background: blue;}
100% {background: green;}
}
 
@-o-keyframes myfirst /* Opera */
{
0%   {background: red;}
25%  {background: yellow;}
50%  {background: blue;}
100% {background: green;}
}

亲自试一试

实例

改变背景色和位置:

@keyframes myfirst
{
0%   {background: red; left:0px; top:0px;}
25%  {background: yellow; left:200px; top:0px;}
50%  {background: blue; left:200px; top:200px;}
75%  {background: green; left:0px; top:200px;}
100% {background: red; left:0px; top:0px;}
}
 
@-moz-keyframes myfirst /* Firefox */
{
0%   {background: red; left:0px; top:0px;}
25%  {background: yellow; left:200px; top:0px;}
50%  {background: blue; left:200px; top:200px;}
75%  {background: green; left:0px; top:200px;}
100% {background: red; left:0px; top:0px;}
}
 
@-webkit-keyframes myfirst /* Safari 和 Chrome */
{
0%   {background: red; left:0px; top:0px;}
25%  {background: yellow; left:200px; top:0px;}
50%  {background: blue; left:200px; top:200px;}
75%  {background: green; left:0px; top:200px;}
100% {background: red; left:0px; top:0px;}
}
 
@-o-keyframes myfirst /* Opera */
{
0%   {background: red; left:0px; top:0px;}
25%  {background: yellow; left:200px; top:0px;}
50%  {background: blue; left:200px; top:200px;}
75%  {background: green; left:0px; top:200px;}
100% {background: red; left:0px; top:0px;}
}

亲自试一试

CSS3 动画属性

下面的表格列出了 @keyframes 规则和所有动画属性:

属性

描述

CSS

@keyframes

规定动画。

3

animation

所有动画属性的简写属性,除了 animation-play-state 属性。

3

animation-name

规定 @keyframes 动画的名称。

3

animation-duration

规定动画完成一个周期所花费的秒或毫秒。默认是 0。

3

animation-timing-function

规定动画的速度曲线。默认是 "ease"。

3

animation-delay

规定动画何时开始。默认是 0。

3

animation-iteration-count

规定动画被播放的次数。默认是 1。

3

animation-direction

规定动画是否在下一周期逆向地播放。默认是 "normal"。

3

animation-play-state

规定动画是否正在运行或暂停。默认是 "running"。

3

animation-fill-mode

规定对象动画时间之外的状态。

3

下面的两个例子设置了所有动画属性:

实例

运行名为 myfirst 的动画,其中设置了所有动画属性:

div
{
animation-name: myfirst;
animation-duration: 5s;
animation-timing-function: linear;
animation-delay: 2s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-play-state: running;
/* Firefox: */
-moz-animation-name: myfirst;
-moz-animation-duration: 5s;
-moz-animation-timing-function: linear;
-moz-animation-delay: 2s;
-moz-animation-iteration-count: infinite;
-moz-animation-direction: alternate;
-moz-animation-play-state: running;
/* Safari 和 Chrome: */
-webkit-animation-name: myfirst;
-webkit-animation-duration: 5s;
-webkit-animation-timing-function: linear;
-webkit-animation-delay: 2s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: alternate;
-webkit-animation-play-state: running;
/* Opera: */
-o-animation-name: myfirst;
-o-animation-duration: 5s;
-o-animation-timing-function: linear;
-o-animation-delay: 2s;
-o-animation-iteration-count: infinite;
-o-animation-direction: alternate;
-o-animation-play-state: running;
}

亲自试一试

实例

与上面的动画相同,但是使用了简写的动画 animation 属性:

div
{
animation: myfirst 5s linear 2s infinite alternate;
/* Firefox: */
-moz-animation: myfirst 5s linear 2s infinite alternate;
/* Safari 和 Chrome: */
-webkit-animation: myfirst 5s linear 2s infinite alternate;
/* Opera: */
-o-animation: myfirst 5s linear 2s infinite alternate;
}

亲自试一试

 

盒模型

字符串,数组api,哪些是在原数组中更改的

  1. concat  
  2. 将两个或多个字符的文本组合起来,返回一个新的字符串。  
  3. var a = "hello";  
  4. var b = ",world";  
  5. var c = a.concat(b);  
  6. alert(c);  
  7. //c = "hello,world"  
  8. indexOf  
  9. 返回字符串中一个子串第一处出现的索引(从左到右搜索)。如果没有匹配项,返回 -1   
  10. var index1 = a.indexOf("l");  
  11. //index1 = 2  
  12. var index2 = a.indexOf("l",3);  
  13. //index2 = 3  
  14. charAt  
  15. 返回指定位置的字符。  
  16. var get_char = a.charAt(0);  
  17. //get_char = "h"  
  18. lastIndexOf  
  19. 返回字符串中一个子串最后一处出现的索引(从右到左搜索),如果没有匹配项,返回 -1   
  20. var index1 = lastIndexOf('l');  
  21. //index1 = 3  
  22. var index2 = lastIndexOf('l',2)  
  23. //index2 = 2  
  24. match  
  25. 检查一个字符串匹配一个正则表达式内容,如果么有匹配返回 null  
  26. var re = new RegExp(/^\w+$/);  
  27. var is_alpha1 = a.match(re);  
  28. //is_alpha1 = "hello"  
  29. var is_alpha2 = b.match(re);  
  30. //is_alpha2 = null  
  31. substring  
  32. 返回字符串的一个子串,传入参数是起始位置和结束位置。  
  33. var sub_string1 = a.substring(1);  
  34. //sub_string1 = "ello"  
  35. var sub_string2 = a.substring(1,4);  
  36. //sub_string2 = "ell"  
  37. substr  
  38. 返回字符串的一个子串,传入参数是起始位置和长度  
  39. var sub_string1 = a.substr(1);  
  40. //sub_string1 = "ello"  
  41. var sub_string2 = a.substr(1,4);  
  42. //sub_string2 = "ello"  
  43. replace  
  44. 用来查找匹配一个正则表达式的字符串,然后使用新字符串代替匹配的字符串。  
  45. var result1 = a.replace(re,"Hello");  
  46. //result1 = "Hello"  
  47. var result2 = b.replace(re,"Hello");  
  48. //result2 = ",world"  
  49. search  
  50. 执行一个正则表达式匹配查找。如果查找成功,返回字符串中匹配的索引值。否则返回 -1   
  51. var index1 = a.search(re);  
  52. //index1 = 0  
  53. var index2 = b.search(re);  
  54. //index2 = -1  
  55. slice  
  56. 提取字符串的一部分,并返回一个新字符串(与 substring 相同)。  
  57. var sub_string1 = a.slice(1);  
  58. //sub_string1 = "ello"  
  59. var sub_string2 = a.slice(1,4);  
  60. //sub_string2 = "ell"  
  61. split  
  62. 通过将字符串划分成子串,将一个字符串做成一个字符串数组。  
  63. var arr1 = a.split("");  
  64. //arr1 = [h,e,l,l,o]  
  65. length  
  66. 返回字符串的长度,所谓字符串的长度是指其包含的字符的个数。  
  67. var len = a.length();  
  68. //len = 5  
  69. toLowerCase  
  70. 将整个字符串转成小写字母。  
  71. var lower_string = a.toLowerCase();  
  72. //lower_string = "hello"  
  73. toUpperCase  
  74. 将整个字符串转成大写字母。  
  75. var upper_string = a.toUpperCase();  
  76. //upper_string = "HELLO"  
  77.   
  78. /* 
  79. ****************************************** 
  80. 字符串函数扩充                                 
  81. ****************************************** 
  82. */  
  83.   
  84. /* 
  85. =========================================== 
  86. //去除左边的空格 
  87. =========================================== 
  88.  
  89. */  
  90. String.prototype.LTrim = function()  
  91. {  
  92. return this.replace(/(^\s*)/g, "");  
  93. }  
  94.   
  95.   
  96. /* 
  97. =========================================== 
  98. //去除右边的空格 
  99. =========================================== 
  100. */  
  101. String.prototype.Rtrim = function()  
  102. {  
  103. return this.replace(/(\s*$)/g, "");  
  104. }  
  105.   
  106. /* 
  107. =========================================== 
  108. //去除前后空格 
  109. =========================================== 
  110. */  
  111. String.prototype.Trim = function()  
  112. {  
  113. return this.replace(/(^\s*)|(\s*$)/g, "");  
  114. }  
  115.   
  116. /* 
  117. =========================================== 
  118. //得到左边的字符串 
  119. =========================================== 
  120. */  
  121. String.prototype.Left = function(len)  
  122. {  
  123.   
  124. if(isNaN(len)||len==null)  
  125. {  
  126. len = this.length;  
  127. }  
  128. else  
  129. {  
  130. if(parseInt(len)<0||parseInt(len)>this.length)  
  131. {  
  132. len = this.length;  
  133. }  
  134. }  
  135.   
  136. return this.substr(0,len);  
  137. }  
  138.   
  139.   
  140. /* 
  141. =========================================== 
  142. //得到右边的字符串 
  143. =========================================== 
  144. */  
  145. String.prototype.Right = function(len)  
  146. {  
  147.   
  148. if(isNaN(len)||len==null)  
  149. {  
  150. len = this.length;  
  151. }  
  152. else  
  153. {  
  154. if(parseInt(len)<0||parseInt(len)>this.length)  
  155. {  
  156. len = this.length;  
  157. }  
  158. }  
  159.   
  160. return this.substring(this.length-len,this.length);  
  161. }  
  162.   
  163.   
  164. /* 
  165. =========================================== 
  166. //得到中间的字符串,注意从0开始 
  167. =========================================== 
  168. */  
  169. String.prototype.Mid = function(start,len)  
  170. {  
  171. return this.substr(start,len);  
  172. }  
  173.   
  174.   
  175. /* 
  176. =========================================== 
  177. //在字符串里查找另一字符串:位置从0开始 
  178. =========================================== 
  179. */  
  180. String.prototype.InStr = function(str)  
  181. {  
  182.   
  183. if(str==null)  
  184. {  
  185. str = "";  
  186. }  
  187.   
  188. return this.indexOf(str);  
  189. }  
  190.   
  191. /* 
  192. =========================================== 
  193. //在字符串里反向查找另一字符串:位置0开始 
  194. =========================================== 
  195. */  
  196. String.prototype.InStrRev = function(str)  
  197. {  
  198.   
  199. if(str==null)  
  200. {  
  201. str = "";  
  202. }  
  203.   
  204. return this.lastIndexOf(str);  
  205. }  
  206.   
  207. /* 
  208. =========================================== 
  209. //计算字符串打印长度 
  210. =========================================== 
  211. */  
  212. String.prototype.LengthW = function()  
  213. {  
  214. return this.replace(/[^\x00-\xff]/g,"**").length;  
  215. }  
  216.   
  217. /* 
  218. =========================================== 
  219. //是否是正确的IP地址 
  220. =========================================== 
  221. */  
  222. String.prototype.isIP = function()  
  223. {  
  224.   
  225. var reSpaceCheck = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;  
  226.   
  227. if (reSpaceCheck.test(this))  
  228. {  
  229. this.match(reSpaceCheck);  
  230. if (RegExp.$1 <= 255 && RegExp.$1 >= 0  
  231. && RegExp.$2 <= 255 && RegExp.$2 >= 0  
  232. && RegExp.$3 <= 255 && RegExp.$3 >= 0  
  233. && RegExp.$4 <= 255 && RegExp.$4 >= 0)  
  234. {  
  235. return true;      
  236. }  
  237. else  
  238. {  
  239. return false;  
  240. }  
  241. }  
  242. else  
  243. {  
  244. return false;  
  245. }  
  246.   
  247. }  
  248.   
  249.   
  250. /* 
  251. =========================================== 
  252. //是否是正确的长日期 
  253. =========================================== 
  254. */  
  255. String.prototype.isLongDate = function()  
  256. {  
  257. var r = this.replace(/(^\s*)|(\s*$)/g, "").match(/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/);  
  258. if(r==null)  
  259. {  
  260. return false;  
  261. }  
  262. var d = new Date(r[1], r[3]-1,r[4],r[5],r[6],r[7]);  
  263. return (d.getFullYear()==r[1]&&(d.getMonth()+1)==r[3]&&d.getDate()==r[4]&&d.getHours()==r[5]&&d.getMinutes()==r[6]&&d.getSeconds()==r[7]);  
  264.   
  265. }  
  266.   
  267. /* 
  268. =========================================== 
  269. //是否是正确的短日期 
  270. =========================================== 
  271. */  
  272. String.prototype.isShortDate = function()  
  273. {  
  274. var r = this.replace(/(^\s*)|(\s*$)/g, "").match(/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/);  
  275. if(r==null)  
  276. {  
  277. return false;  
  278. }  
  279. var d = new Date(r[1], r[3]-1, r[4]);  
  280. return (d.getFullYear()==r[1]&&(d.getMonth()+1)==r[3]&&d.getDate()==r[4]);  
  281. }  
  282.   
  283. /* 
  284. =========================================== 
  285. //是否是正确的日期 
  286. =========================================== 
  287. */  
  288. String.prototype.isDate = function()  
  289. {  
  290. return this.isLongDate()||this.isShortDate();  
  291. }  
  292.   
  293. /* 
  294. =========================================== 
  295. //是否是手机 
  296. =========================================== 
  297. */  
  298. String.prototype.isMobile = function()  
  299. {  
  300. return /^0{0,1}13[0-9]{9}$/.test(this);  
  301. }  
  302.   
  303. /* 
  304. =========================================== 
  305. //是否是邮件 
  306. =========================================== 
  307. */  
  308. String.prototype.isEmail = function()  
  309. {  
  310. return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(this);  
  311. }  
  312.   
  313. /* 
  314. =========================================== 
  315. //是否是邮编(中国) 
  316. =========================================== 
  317. */  
  318.   
  319. String.prototype.isZipCode = function()  
  320. {  
  321. return /^[\\d]{6}$/.test(this);  
  322. }  
  323.   
  324. /* 
  325. =========================================== 
  326. //是否是有汉字 
  327. =========================================== 
  328. */  
  329. String.prototype.existChinese = function()  
  330. {  
  331. //[\u4E00-\u9FA5]為漢字﹐[\uFE30-\uFFA0]為全角符號  
  332. return /^[\x00-\xff]*$/.test(this);  
  333. }  
  334.   
  335. /* 
  336. =========================================== 
  337. //是否是合法的文件名/目录名 
  338. =========================================== 
  339. */  
  340. String.prototype.isFileName = function()  
  341. {  
  342. return !/[\\\/\*\?\|:"<>]/g.test(this);  
  343. }  
  344.   
  345. /* 
  346. =========================================== 
  347. //是否是有效链接 
  348. =========================================== 
  349. */  
  350. String.prototype.isUrl = function()  
  351. {  
  352. return /^http[s]?:\/\/([\w-]+\.)+[\w-]+([\w-./?%&=]*)?$/i.test(this);  
  353. }  
  354.   
  355.   
  356. /* 
  357. =========================================== 
  358. //是否是有效的身份证(中国) 
  359. =========================================== 
  360. */  
  361. String.prototype.isIDCard = function()  
  362. {  
  363. var iSum=0;  
  364. var info="";  
  365. var sId = this;  
  366.   
  367.  var aCity={11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古",21:"辽宁",22:"吉林",23:"黑龙 ",31:"上海",32:"江苏",33:"浙江",34:"安徽",35:"福建",36:"江西",37:"山东",41:"河南",42:" ",43:"湖南",44:"广东",45:"广西",46:"海南",50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏",61:"陕西",62:"甘肃",63:"青海",64:"宁夏",65:"新疆",71:"台湾",81:"香港",82:"澳门",91:"国外"};  
  368.   
  369. if(!/^\d{17}(\d|x)$/i.test(sId))  
  370. {  
  371. return false;  
  372. }  
  373. sId=sId.replace(/x$/i,"a");  
  374. //非法地区  
  375. if(aCity[parseInt(sId.substr(0,2))]==null)  
  376. {  
  377. return false;  
  378. }  
  379.   
  380. var sBirthday=sId.substr(6,4)+"-"+Number(sId.substr(10,2))+"-"+Number(sId.substr(12,2));  
  381.   
  382. var d=new Date(sBirthday.replace(/-/g,"/"))  
  383.   
  384. //非法生日  
  385. if(sBirthday!=(d.getFullYear()+"-"+ (d.getMonth()+1) + "-" + d.getDate()))  
  386. {  
  387. return false;  
  388. }  
  389. for(var i = 17;i>=0;i--)  
  390. {  
  391. iSum += (Math.pow(2,i) % 11) * parseInt(sId.charAt(17 - i),11);  
  392. }  
  393.   
  394. if(iSum%11!=1)  
  395. {  
  396. return false;  
  397. }  
  398. return true;  
  399.   
  400. }  
  401.   
  402. /* 
  403. =========================================== 
  404. //是否是有效的电话号码(中国) 
  405. =========================================== 
  406. */  
  407. String.prototype.isPhoneCall = function()  
  408. {  
  409. return /(^[0-9]{3,4}\-[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$)/.test(this);  
  410. }  
  411.   
  412.   
  413. /* 
  414. =========================================== 
  415. //是否是数字 
  416. =========================================== 
  417. */  
  418. String.prototype.isNumeric = function(flag)  
  419. {  
  420. //验证是否是数字  
  421. if(isNaN(this))  
  422. {  
  423.   
  424. return false;  
  425. }  
  426.   
  427. switch(flag)  
  428. {  
  429.   
  430. case null:        //数字  
  431. case "":  
  432. return true;  
  433. case "+":        //正数  
  434. return                /(^\+?|^\d?)\d*\.?\d+$/.test(this);  
  435. case "-":        //负数  
  436. return                /^-\d*\.?\d+$/.test(this);  
  437. case "i":        //整数  
  438. return                /(^-?|^\+?|\d)\d+$/.test(this);  
  439. case "+i":        //正整数  
  440. return                /(^\d+$)|(^\+?\d+$)/.test(this);                         
  441. case "-i":        //负整数  
  442. return                /^[-]\d+$/.test(this);  
  443. case "f":        //浮点数  
  444. return                /(^-?|^\+?|^\d?)\d*\.\d+$/.test(this);  
  445. case "+f":        //正浮点数  
  446. return                /(^\+?|^\d?)\d*\.\d+$/.test(this);                         
  447. case "-f":        //负浮点数  
  448. return                /^[-]\d*\.\d$/.test(this);                 
  449. default:        //缺省  
  450. return true;                         
  451. }  
  452. }  
  453.   
  454. /* 
  455. =========================================== 
  456. //是否是颜色(#FFFFFF形式) 
  457. =========================================== 
  458. */  
  459. String.prototype.IsColor = function()  
  460. {  
  461. var temp        = this;  
  462. if (temp==""return true;  
  463. if (temp.length!=7) return false;  
  464. return (temp.search(/\#[a-fA-F0-9]{6}/) != -1);  
  465. }  
  466.   
  467. /* 
  468. =========================================== 
  469. //转换成全角 
  470. =========================================== 
  471. */  
  472. String.prototype.toCase = function()  
  473. {  
  474. var tmp = "";  
  475. for(var i=0;i<this.length;i++)  
  476. {  
  477. if(this.charCodeAt(i)>0&&this.charCodeAt(i)<255)  
  478. {  
  479. tmp += String.fromCharCode(this.charCodeAt(i)+65248);  
  480. }  
  481. else  
  482. {  
  483. tmp += String.fromCharCode(this.charCodeAt(i));  
  484. }  
  485. }  
  486. return tmp  
  487. }  
  488.   
  489. /* 
  490. =========================================== 
  491. //对字符串进行Html编码 
  492. =========================================== 
  493. */  
  494. String.prototype.toHtmlEncode = function()  
  495. {  
  496. var str = this;  
  497.   
  498. str=str.replace(/&/g,"&");  
  499. str=str.replace(/</g,"<");  
  500. str=str.replace(/>/g,">");  
  501. str=str.replace(/\'/g,"'");  
  502. str=str.replace(/\"/g,""");  
  503. str=str.replace(/\n/g,"<br>");  
  504. str=str.replace(/\ /g," ");  
  505. str=str.replace(/\t/g,"    ");  
  506.   
  507. return str;  
  508. }  
  509.   
  510. /* 
  511. =========================================== 
  512. //转换成日期 
  513. =========================================== 
  514. */  
  515. String.prototype.toDate = function()  
  516. {  
  517. try  
  518. {  
  519. return new Date(this.replace(/-/g, "\/"));  
  520. }  
  521. catch(e)  
  522. {  
  523. return null;  
  524. }  
  525. }  

Array 对象方法

  • concat()    连接两个或更多的数组,并返回结果。    
  • join()    把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。    
  • pop()    删除并返回数组的最后一个元素    
  • push()    向数组的末尾添加一个或更多元素,并返回新的长度。    
  • reverse()    颠倒数组中元素的顺序。    
  • shift()    删除并返回数组的第一个元素    
  • slice()    从某个已有的数组返回选定的元素    
  • sort()    对数组的元素进行排序    
  • splice()    删除元素,并向数组添加新元素。    
  • toSource()    返回该对象的源代码。    
  • toString()    把数组转换为字符串,并返回结果。    
  • toLocaleString()    把数组转换为本地数组,并返回结果。    
  • unshift()    向数组的开头添加一个或更多元素,并返回新的长度。    
  • valueOf()    返回数组对象的原始值 

改变原数组的:

  1. shift:将第一个元素删除并且返回删除元素,空即为undefined
  2. unshift:向数组开头添加元素,并返回新的长度
  3. pop:删除最后一个并返回删除的元素
  4. push:向数组末尾添加元素,并返回新的长度
  5. reverse:颠倒数组顺序
  6. sort:对数组排序
  7. splice:splice(start,length,item)删,增,替换数组元素,返回被删除数组,无删除则不返回

不改变原数组的:

  1. concat:连接多个数组,返回新的数组
  2. join:将数组中所有元素以参数作为分隔符放入一个字符
  3. slice:slice(start,end),返回选定元素
  4. map,filter,forEach,some,every等不改变原数组

spliceslice的区别: 
splice(i,j,”a”)
删除,添加元素,splice() 方法与 slice() 方法的作用是不同的,splice() 方法会直接对数组进行修改。从i开始删j(包括i),并将”a”插入到i处。 
slice(start,end)
从某个已有的数组返回选定的元素,从start位开始返回到end(包括start不包括end)如果是负数,表示从数组尾部进行计算(同样:包括start不包括end,请注意,该方法并不会修改数组,而是返回一个子数组。

 

 
splice()
的强大(删、增、替换数组的元素)

<span style="font-size:18px;">处理数组的方法很多,javascript splice()算是最强大的了,它可以用于插入、删除或替换数组的元素。下面来一一介绍!  

 

1.删除-用于删除元素,两个参数,第一个参数(要删除第一项的位置),第二个参数(要删除的项数)  

2.插入-向数组指定位置插入任意项元素。三个参数,第一个参数(其实位置),第二个参数(0),第三个参数(插入的项)  

3.替换-向数组指定位置插入任意项元素,同时删除任意数量的项,三个参数。第一个参数(起始位置),第二个参数(删除的项数),第三个参数(插入任意数量的项)  

 

<strong>看下面这段代码就明白了</strong>  

 

</span> 

<span style="font-size:18px;">var lang = ["php","java","javascript"];  

//删除  

var removed = lang.splice(1,1);  

alert(lang); //php,javascript  

alert(removed); //java ,返回删除的项  

//插入  

var insert = lang.splice(0,0,"asp"); //从第0个位置开始插入  

alert(insert); //返回空数组  

alert(lang); //asp,php,javascript  

//替换  

var replace = lang.splice(1,1,"c#","ruby"); //删除一项,插入两项  

alert(lang); //asp,c#,ruby javascript 

alert(replace); //php,返回删除的项 </span> 

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn/cristina_song/article/details/77917404

 

jQuery源码

【深入浅出jQuery】源码浅析--整体架构

最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美。

其结构明晰,高内聚、低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷、渐进增强)优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹。

另外,阅读源码让我接触到了大量底层的知识。对原生JS 、框架设计、代码优化有了全新的认识,接下来将会写一系列关于 jQuery 解析的文章。

我在 github 上关于 jQuery 源码的全文注解,感兴趣的可以围观一下。jQuery v1.10.2 源码注解 

系列第二篇:【深入浅出jQuery】源码浅析2--奇技淫巧

 

网上已经有很多解读 jQuery 源码的文章了,作为系列开篇的第一篇,思前想去起了个【深入浅出jQuery】的标题,资历尚浅,无法对 jQuery 分析的头头是道,但是 jQuery 源码当中确实有着大量巧妙的设计,不同层次水平的阅读者都能有收获,所以打算厚着脸皮将自己从中学到的一些知识点共享出来。打算从整体及分支,分章节剖析。本篇主要讲 jQuery 的整体架构及一些前期准备,先来看看 jQuery 的整体结构:

 

   jQuery 整体架构

 

不同于 jQuery 代码各个模块细节实现的晦涩难懂,jQuery 整体框架的结构十分清晰,按代码行文大致分为如上图所示的模块。

初看 jQuery 源码可能很容易一头雾水,因为 9000 行的代码感觉没有尽头,所以了解作者的行文思路十分重要。

整体而言,我觉得 jQuery 采用的是--的结构,虽然JavaScript有着作用域的提升机制,但是 9000 多行的代码为了相互的关联性,并不代表所有的变量都要定义在最顶部。在 jQuery 中,只有全局都会用到的变量、正则表达式定义在了代码最开头,而每个模块一开始,又会定义一些只在本模块会使用到的变量、正则、方法等。所以在一开始的阅读的过程中会有很多看不懂其作用的变量,正则,方法。

所以,我觉得阅读源码很重要的一点是,摒弃面向过程的思维方式,不要刻意去追求从上至下每一句都要在一开始弄明白。很有可能一开始你在一个奇怪的方法或者变量处卡壳了,很想知道这个方法或变量的作用,然而可能它要到几千行处才被调用到。如果去追求这种逐字逐句弄清楚的方式,很有可能在碰壁几次之后阅读的积极性大受打击。 

道理说了很多,接来下进入真正的正文,对 jQurey 的一些前期准备,小的细节进行分析:

 

   jQuery 闭包结构

1

2

3

4

5

6

7

// 用一个函数域包起来,就是所谓的沙箱

// 在这里边 var 定义的变量,属于这个函数域内的局部变量,避免污染全局

// 把当前沙箱需要的外部变量通过函数参数引入进来

// 只要保证参数对内提供的接口的一致性,你还可以随意替换传进来的这个参数

(function(window, undefined) {

   // jQuery 代码

})(window);

jQuery 具体的实现,都被包含在了一个立即执行函数构造的闭包里面,为了不污染全局作用域,只在后面暴露 $ jQuery 2 个变量给外界,尽量的避开变量冲突。常用的还有另一种写法:

1

2

3

(function(window) {

   // JS代码

})(window, undefined);

比较推崇的的第一种写法,也就是 jQuery 的写法。二者有何不同呢,当我们的代码运行在更早期的环境当中(pre-ES5eg. Internet Explorer 8),undefined 仅是一个变量且它的值是可以被覆盖的。意味着你可以做这样的操作:

1

2

undefined = 42

console.log(undefined) // 42

当使用第一种方式,可以确保你需要的 undefined 确实就是 undefined

另外不得不提出的是,jQuery 在这里有一个针对压缩优化细节,使用第一种方式,在代码压缩的时候,window undefined 都可以压缩为 1 个字母并且确保它们就是 window undefined

1

2

3

4

5

// 压缩策略

// w -> windwow , u -> undefined

(function(w, u) {

 

})(window);

  

   jQuery new 构造

 嘿,回想一下使用 jQuery 的时候,实例化一个 jQuery 对象的方法:

1

2

3

4

5

6

// 无 new 构造

$('#test').text('Test');

 

// 当然也可以使用 new

var test = new $('#test');

test.text('Test');

大部分人使用 jQuery 的时候都是使用第一种无 new 的构造方式,直接 $('') 进行构造,这也是 jQuery 十分便捷的一个地方。当我们使用第一种无 new 构造方式的时候,其本质就是相当于 new jQuery(),那么在 jQuery 内部是如何实现的呢?看看:

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

(function(window, undefined) {

    var

    // ...

    jQuery = function(selector, context) {

        // The jQuery object is actually just the init constructor 'enhanced'

        // 看这里,实例化方法 jQuery() 实际上是调用了其拓展的原型方法 jQuery.fn.init

        return new jQuery.fn.init(selector, context, rootjQuery);

    },

 

    // jQuery.prototype 即是 jQuery 的原型,挂载在上面的方法,即可让所有生成的 jQuery 对象使用

    jQuery.fn = jQuery.prototype = {

        // 实例化化方法,这个方法可以称作 jQuery 对象构造器

        init: function(selector, context, rootjQuery) {

            // ...

        }

    }

    // 这一句很关键,也很绕

    // jQuery 没有使用 new 运算符将 jQuery 实例化,而是直接调用其函数

    // 要实现这样,那么 jQuery 就要看成一个类,且返回一个正确的实例

    // 且实例还要能正确访问 jQuery 类原型上的属性与方法

    // jQuery 的方式是通过原型传递解决问题,把 jQuery 的原型传递给jQuery.prototype.init.prototype

    // 所以通过这个方法生成的实例 this 所指向的仍然是 jQuery.fn,所以能正确访问 jQuery 类原型上的属性与方法

    jQuery.fn.init.prototype = jQuery.fn;

 

})(window);

大部分人初看 jQuery.fn.init.prototype = jQuery.fn 这一句都会被卡主,很是不解。但是这句真的算是 jQuery 的绝妙之处。理解这几句很重要,分点解析一下:

1)首先要明确,使用 $('xxx') 这种实例化方式,其内部调用的是 return new jQuery.fn.init(selector, context, rootjQuery) 这一句话,也就是构造实例是交给了 jQuery.fn.init() 方法去完成。

2)将 jQuery.fn.init prototype 属性设置为 jQuery.fn,那么使用 new jQuery.fn.init() 生成的对象的原型对象就是 jQuery.fn ,所以挂载到 jQuery.fn 上面的函数就相当于挂载到 jQuery.fn.init() 生成的 jQuery 对象上,所有使用 new jQuery.fn.init() 生成的对象也能够访问到 jQuery.fn 上的所有原型方法。

3)也就是实例化方法存在这么一个关系链  

  • jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype ;
  • new jQuery.fn.init() 相当于 new jQuery() ;
  • jQuery() 返回的是 new jQuery.fn.init(),而 var obj = new jQuery(),所以这 2 者是相当的,所以我们可以无 new 实例化 jQuery 对象。

 

   jQuery 方法的重载

jQuery 源码晦涩难读的另一个原因是,使用了大量的方法重载,但是用起来却很方便:

1

2

3

4

5

6

7

8

9

// 获取 title 属性的值

$('#id').attr('title');

// 设置 title 属性的值

$('#id').attr('title','jQuery');

 

// 获取 css 某个属性的值

$('#id').css('title');

// 设置 css 某个属性的值

$('#id').css('width','200px');

方法的重载即是一个方法实现多种功能,经常又是 get 又是 set,虽然阅读起来十分不易,但是从实用性的角度考虑,这也是为什么 jQuery 如此受欢迎的原因,大多数人使用 jQuery() 构造方法使用的最多的就是直接实例化一个 jQuery 对象,但其实在它的内部实现中,有着 9 种不同的方法重载场景:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

// 接受一个字符串,其中包含了用于匹配元素集合的 CSS 选择器

jQuery([selector,[context]])

// 传入单个 DOM

jQuery(element)

// 传入 DOM 数组

jQuery(elementArray)

// 传入 JS 对象

jQuery(object)

// 传入 jQuery 对象

jQuery(jQuery object)

// 传入原始 HTML 的字符串来创建 DOM 元素

jQuery(html,[ownerDocument])

jQuery(html,[attributes])

// 传入空参数

jQuery()

// 绑定一个在 DOM 文档载入完成后执行的函数

jQuery(callback)

所以读源码的时候,很重要的一点是结合 jQuery API 进行阅读,去了解方法重载了多少种功能,同时我想说的是,jQuery 源码有些方法的实现特别长且繁琐,因为 jQuery 本身作为一个通用性特别强的框架,一个方法兼容了许多情况,也允许用户传入各种不同的参数,导致内部处理的逻辑十分复杂,所以当解读一个方法的时候感觉到了明显的困难,尝试着跳出卡壳的那段代码本身,站在更高的维度去思考这些复杂的逻辑是为了处理或兼容什么,是否是重载,为什么要这样写,一定会有不一样的收获。其次,也是因为这个原因,jQuery 源码存在许多兼容低版本的 HACK 或者逻辑十分晦涩繁琐的代码片段,浏览器兼容这样的大坑极其容易让一个前端工程师不能学到编程的精髓,所以不要太执着于一些边角料,即使兼容性很重要,也应该适度学习理解,适可而止。

 

   jQuery.fn.extend  jQuery.extend

extend 方法在 jQuery 中是一个很重要的方法,jQuey 内部用它来扩展静态方法或实例方法,而且我们开发 jQuery 插件开发的时候也会用到它。但是在内部,是存在 jQuery.fn.extend  jQuery.extend 两个 extend 方法的,而区分这两个 extend 方法是理解 jQuery 的很关键的一部分。先看结论:

1jQuery.extend(object) 为扩展 jQuery 类本身,为类添加新的静态方法;

2jQuery.fn.extend(object)  jQuery 对象添加实例方法,也就是通过这个 extend 添加的新方法,实例化的 jQuery 对象都能使用,因为它是挂载在 jQuery.fn 上的方法(上文有提到,jQuery.fn = jQuery.prototype )。 

它们的官方解释是:

1jQuery.extend(): 把两个或者更多的对象合并到第一个当中,

2jQuery.fn.extend():把对象挂载到 jQuery prototype 属性,来扩展一个新的 jQuery 实例方法。

也就是说,使用 jQuery.extend() 拓展的静态方法,我们可以直接使用 $.xxx 进行调用(xxx是拓展的方法名),

而使用 jQuery.fn.extend() 拓展的实例方法,需要使用 $().xxx 调用。

源码解析较长,点击下面可以展开,也可以去这里阅读

+ View Code

需要注意的是这一句 jQuery.extend = jQuery.fn.extend = function() {} ,也就是 jQuery.extend 的实现和 jQuery.fn.extend 的实现共用了同一个方法,但是为什么能够实现不同的功能了,这就要归功于 Javascript 强大(怪异?)的 this 了。

1)在 jQuery.extend() 中,this 的指向是 jQuery 对象(或者说是 jQuery ),所以这里扩展在 jQuery 上;

2)在 jQuery.fn.extend() 中,this 的指向是 fn 对象,前面有提到 jQuery.fn = jQuery.prototype ,也就是这里增加的是原型方法,也就是对象方法。

 

   jQuery 的链式调用及回溯
 

另一个让大家喜爱使用 jQuery 的原因是它的链式调用,这一点的实现其实很简单,只需要在要实现链式调用的方法的返回结果里,返回 this ,就能够实现链式调用了。

当然,除了链式调用,jQuery 甚至还允许回溯,看看:

1

2

// 通过 end() 方法终止在当前链的最新过滤操作,返回上一个对象集合

$('div').eq(0).show().end().eq(1).hide();

当选择了 ('div').eq(0) 之后使用 end() 可以回溯到上一步选中的 jQuery 对象 $('div'),其内部实现其实是依靠添加了 prevObject 这个属性:

jQuery 完整的链式调用、增栈、回溯通过 return this  return this.pushStack() return this.prevObject 实现,看看源码实现:

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

jQuery.fn = jQuery.prototype = {

    // 将一个 DOM 元素集合加入到 jQuery 栈

    // 此方法在 jQuery 的 DOM 操作中被频繁的使用, 如在 parent(), find(), filter() 中

    // pushStack() 方法通过改变一个 jQuery 对象的 prevObject 属性来跟踪链式调用中前一个方法返回的 DOM 结果集合

    // 当我们在链式调用 end() 方法后, 内部就返回当前 jQuery 对象的 prevObject 属性

    pushStack: function(elems) {

        // 构建一个新的jQuery对象,无参的 this.constructor(),只是返回引用this

        // jQuery.merge 把 elems 节点合并到新的 jQuery 对象

        // this.constructor 就是 jQuery 的构造函数 jQuery.fn.init,所以 this.constructor() 返回一个 jQuery 对象

        // 由于 jQuery.merge 函数返回的对象是第二个函数附加到第一个上面,所以 ret 也是一个 jQuery 对象,这里可以解释为什么 pushStack 出入的 DOM 对象也可以用 CSS 方法进行操作

        var ret = jQuery.merge(this.constructor(), elems);

 

        // 给返回的新 jQuery 对象添加属性 prevObject

        // 所以也就是为什么通过 prevObject 能取到上一个合集的引用了

        ret.prevObject = this;

        ret.context = this.context;

 

        // Return the newly-formed element set

        return ret;

    },

    // 回溯链式调用的上一个对象

    end: function() {

        // 回溯的关键是返回 prevObject 属性

        // 而 prevObject 属性保存了上一步操作的 jQuery 对象集合

        return this.prevObject || this.constructor(null);

    },

    // 取当前 jQuery 对象的第 i 个

    eq: function(i) {

        // jQuery 对象集合的长度

        var len = this.length,

            j = +i + (i < 0 ? len : 0);

 

        // 利用 pushStack 返回

        return this.pushStack(j >= 0 && j < len ? [this[j]] : []);

    }, 

}

总的来说,

1end() 方法返回 prevObject 属性,这个属性记录了上一步操作的 jQuery 对象合集;

2)而 prevObject 属性由 pushStack() 方法生成,该方法将一个 DOM 元素集合加入到 jQuery 内部管理的一个栈中,通过改变 jQuery 对象的 prevObject 属性来跟踪链式调用中前一个方法返回的 DOM 结果集合

3)当我们在链式调用 end() 方法后,内部就返回当前 jQuery 对象的 prevObject 属性,完成回溯。

 

   jQuery 正则与细节优化

不得不提 jQuery 在细节优化上做的很好。也存在很多值得学习的小技巧,下一篇将会以 jQuery 中的一些编程技巧为主题行文,这里就不再赘述。

然后想谈谈正则表达式,jQuery 当中用了大量的正则表达式,我觉得如果研读 jQuery ,正则水平一定能够大大提升,如果是个正则小白,我建议在阅读之前先去了解以下几点:

1)了解并尝试使用 Javascript 正则相关 API,包括了 test() replace() match() exec() 的用法;

2)区分上面 4 个方法,哪个是 RegExp 对象方法,哪个是 String 对象方法;

3)了解简单的零宽断言,了解什么是匹配但是不捕获以及匹配并且捕获

 

   jQuery 变量冲突处理

最后想提一提 jQuery 变量的冲突处理,通过一开始保存全局变量的 window.jQuery 以及 windw.$

当需要处理冲突的时候,调用静态方法 noConflict(),让出变量的控制权,源码如下:

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

(function(window, undefined) {

    var

        // Map over jQuery in case of overwrite

        // 设置别名,通过两个私有变量映射了 window 环境下的 jQuery 和 $ 两个对象,以防止变量被强行覆盖

        _jQuery = window.jQuery,

        _$ = window.$;

 

    jQuery.extend({

        // noConflict() 方法让出变量 $ 的 jQuery 控制权,这样其他脚本就可以使用它了

        // 通过全名替代简写的方式来使用 jQuery

        // deep -- 布尔值,指示是否允许彻底将 jQuery 变量还原(移交 $ 引用的同时是否移交 jQuery 对象本身)

        noConflict: function(deep) {

            // 判断全局 $ 变量是否等于 jQuery 变量

            // 如果等于,则重新还原全局变量 $ 为 jQuery 运行之前的变量(存储在内部变量 _$ 中)

            if (window.$ === jQuery) {

                // 此时 jQuery 别名 $ 失效

                window.$ = _$;

            }

            // 当开启深度冲突处理并且全局变量 jQuery 等于内部 jQuery,则把全局 jQuery 还原成之前的状况

            if (deep && window.jQuery === jQuery) {

                // 如果 deep 为 true,此时 jQuery 失效

                window.jQuery = _jQuery;

            }

 

            // 这里返回的是 jQuery 库内部的 jQuery 构造函数(new jQuery.fn.init())

            // 像使用 $ 一样尽情使用它吧

            return jQuery;

        }

    })

}(window)

画了一幅简单的流程图帮助理解:

 

那么让出了这两个符号之后,是否就不能在我们的代码中使用 jQuery 或者呢 $ 呢?莫慌,还是可以使用的:

1

2

3

4

5

6

7

8

9

// 让出 jQuery 、$ 的控制权不代表不能使用 jQuery 和 $ ,方法如下:

var query = jQuery.noConflict(true);

 

(function($) {

 

// 插件或其他形式的代码,也可以将参数设为 jQuery

})(query);

 

//  ... 其他用 $ 作为别名的库的代码

 

   结束语

jQuery 整体架构的一些解析就到这里,下一篇将会剖析一下 jQuery 中的一些优化小技巧,一些对编程有所提高的地方。

原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

如果本文对你有帮助,请点下推荐,写文章不容易。

系列第二篇:【深入浅出jQuery】源码浅析2--奇技淫巧

最后,我在 github 上关于 jQuery 源码的全文注解,感兴趣的可以围观一下,给颗星星。jQuery v1.10.2 源码注解 

 

前端优化

作者:斯迪
链接:https://www.zhihu/question/21658448/answer/18903129
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

不知道是哪位大牛的文章,转过9来回答。
前端是庞大的,包括 HTML、 CSS、 Javascript、Image 、Flash等等各种各样的资源。前端优化是复杂的,针对方方面面的资源都有不同的方式。那么,前端优化的目的是什么 ?
  1. 从用户角度而言,优化能够让页面加载得更快、对用户的操作响应得更及时,能够给用户提供更为友好的体验。
  2. 从服务商角度而言,优化能够减少页面请求数、或者减小请求所占带宽,能够节省可观的资源。
  总之,恰当的优化不仅能够改善站点的用户体验并且能够节省相当的资源利用。
  前端优化的途径有很多,按粒度大致可以分为两类,第一类是页面级别的优化,例如 HTTP请求数、脚本的无阻塞加载、内联脚本的位置优化等 ;第二类则是代码级别的优化,例如 Javascript中的DOM 操作优化、CSS选择符优化、图片优化以及 HTML结构优化等等。另外,本着提高投入产出比的目的,后文提到的各种优化策略大致按照投入产出比从大到小的顺序排列。
  一、页面级优化
  1. 减少 HTTP请求数
  这条策略基本上所有前端人都知道,而且也是最重要最有效的。都说要减少 HTTP请求,那请求多了到底会怎么样呢 ?首先,每个请求都是有成本的,既包含时间成本也包含资源成本。一个完整的请求都需要经过 DNS寻址、与服务器建立连接、发送数据、等待服务器响应、接收数据这样一个 “漫长” 而复杂的过程。时间成本就是用户需要看到或者 “感受” 到这个资源是必须要等待这个过程结束的,资源上由于每个请求都需要携带数据,因此每个请求都需要占用带宽。另外,由于浏览器进行并发请求的请求数是有上限的 (具体参见此处 ),因此请求数多了以后,浏览器需要分批进行请求,因此会增加用户的等待时间,会给用户造成站点速度慢这样一个印象,即使可能用户能看到的第一屏的资源都已经请求完了,但是浏览器的进度条会一直存在。
  减少 HTTP请求数的主要途径包括:
  (1). 从设计实现层面简化页面
  如果你的页面像百度首页一样简单,那么接下来的规则基本上都用不着了。保持页面简洁、减少资源的使用时最直接的。如果不是这样,你的页面需要华丽的皮肤,则继续阅读下面的内容。
  (2). 合理设置 HTTP缓存
  缓存的力量是强大的,恰当的缓存设置可以大大的减少 HTTP请求。以有啊首页为例,当浏览器没有缓存的时候访问一共会发出 78个请求,共 600多 K数据 (如图 1.1),而当第二次访问即浏览器已缓存之后访问则仅有 10个请求,共 20多 K数据 (如图 1.2)。 (这里需要说明的是,如果直接 F5刷新页面的话效果是不一样的,这种情况下请求数还是一样,不过被缓存资源的请求服务器是 304响应,只有 Header没有Body ,可以节省带宽 )
  怎样才算合理设置 ?原则很简单,能缓存越多越好,能缓存越久越好。例如,很少变化的图片资源可以直接通过 HTTP Header中的Expires设置一个很长的过期头 ;变化不频繁而又可能会变的资源可以使用 Last-Modifed来做请求验证。尽可能的让资源能够在缓存中待得更久。关于 HTTP缓存的具体设置和原理此处就不再详述了,有兴趣的可以参考下列文章:
HTTP1.1协议中关于缓存策略的描述
Fiddler HTTP Performance中关于缓存的介绍
  (3). 资源合并与压缩
  如果可以的话,尽可能的将外部的脚本、样式进行合并,多个合为一个。另外, CSS、 Javascript、Image 都可以用相应的工具进行压缩,压缩后往往能省下不少空间。
  (4). CSS Sprites
  合并 CSS图片,减少请求数的又一个好办法。
  (5). Inline Images
  使用 data: URL scheme的方式将图片嵌入到页面或 CSS中,如果不考虑资源管理上的问题的话,不失为一个好办法。如果是嵌入页面的话换来的是增大了页面的体积,而且无法利用浏览器缓存。使用在 CSS中的图片则更为理想一些。
  (6). Lazy Load Images(自己对这一块的内容还是不了解)
  这条策略实际上并不一定能减少 HTTP请求数,但是却能在某些条件下或者页面刚加载时减少 HTTP请求数。对于图片而言,在页面刚加载的时候可以只加载第一屏,当用户继续往后滚屏的时候才加载后续的图片。这样一来,假如用户只对第一屏的内容感兴趣时,那剩余的图片请求就都节省了。 有啊首页 曾经的做法是在加载的时候把第一屏之后的图片地址缓存在 Textarea标签中,待用户往下滚屏的时候才 “惰性” 加载。

  2. 将外部脚本置底(将脚本内容在页面信息内容加载后再加载)
  前文有谈到,浏览器是可以并发请求的,这一特点使得其能够更快的加载资源,然而外链脚本在加载时却会阻塞其他资源,例如在脚本加载完成之前,它后面的图片、样式以及其他脚本都处于阻塞状态,直到脚本加载完成后才会开始加载。如果将脚本放在比较靠前的位置,则会影响整个页面的加载速度从而影响用户体验。解决这一问题的方法有很多,在 这里有比较详细的介绍 (这里是译文和 更详细的例子 ),而最简单可依赖的方法就是将脚本尽可能的往后挪,减少对并发下载的影响。
  3. 异步执行 inline脚本(其实原理和上面是一样,保证脚本在页面内容后面加载。)
  inline脚本对性能的影响与外部脚本相比,是有过之而无不及。首页,与外部脚本一样, inline脚本在执行的时候一样会阻塞并发请求,除此之外,由于浏览器在页面处理方面是单线程的,当 inline脚本在页面渲染之前执行时,页面的渲染工作则会被推迟。简而言之, inline脚本在执行的时候,页面处于空白状态。鉴于以上两点原因,建议将执行时间较长的 inline脚本异步执行,异步的方式有很多种,例如使用 script元素的defer 属性(存在兼容性问题和其他一些问题,例如不能使用 document.write)、使用setTimeout ,此外,在HTML5中引入了 Web Workers的机制,恰恰可以解决此类问题。

  4. Lazy Load Javascript(只有在需要加载的时候加载,在一般情况下并不加载信息内容。)
  随着 Javascript框架的流行,越来越多的站点也使用起了框架。不过,一个框架往往包括了很多的功能实现,这些功能并不是每一个页面都需要的,如果下载了不需要的脚本则算得上是一种资源浪费 -既浪费了带宽又浪费了执行花费的时间。目前的做法大概有两种,一种是为那些流量特别大的页面专门定制一个专用的 mini版框架,另一种则是 Lazy Load。YUI 则使用了第二种方式,在 YUI的实现中,最初只加载核心模块,其他模块可以等到需要使用的时候才加载。

  5. 将 CSS放在 HEAD中
  如果将 CSS放在其他地方比如 BODY中,则浏览器有可能还未下载和解析到 CSS就已经开始渲染页面了,这就导致页面由无 CSS状态跳转到 CSS状态,用户体验比较糟糕。除此之外,有些浏览器会在 CSS下载完成后才开始渲染页面,如果 CSS放在靠下的位置则会导致浏览器将渲染时间推迟。
  6. 异步请求 Callback(就是将一些行为样式提取出来,慢慢的加载信息的内容)
  在某些页面中可能存在这样一种需求,需要使用 script标签来异步的请求数据。类似:
  Javascript:
/*Callback 函数*/
function myCallback(info){
//do something here
}
  HTML:

  cb返回的内容 :
myCallback('Hello world!');
像以上这种方式直接在页面上写 <script>对页面的性能也是有影响的,即增加了页面首次加载的负担,推迟了 DOMLoaded和window.onload 事件的触发时机。如果时效性允许的话,可以考虑在 DOMLoaded事件触发的时候加载,或者使用 setTimeout方式来灵活的控制加载的时机。
  7. 减少不必要的 HTTP跳转
  对于以目录形式访问的 HTTP链接,很多人都会忽略链接最后是否带 ’/',假如你的服务器对此是区别对待的话,那么你也需要注意,这其中很可能隐藏了 301跳转,增加了多余请求。具体参见下图,其中第一个链接是以无 ’/'结尾的方式访问的,于是服务器有了一次跳转。
  8. 避免重复的资源请求
  这种情况主要是由于疏忽或页面由多个模块拼接而成,然后每个模块中请求了同样的资源时,会导致资源的重复请求

  二、代码级优化
  1. Javascript
  (1). DOM
  DOM操作应该是脚本中最耗性能的一类操作,例如增加、修改、删除 DOM元素或者对 DOM集合进行操作。如果脚本中包含了大量的 DOM操作则需要注意以下几点:
  a. HTML Collection(HTML收集器,返回的是一个数组内容信息)
  在脚本中 document.images、document.forms 、getElementsByTagName()返回的都是 HTMLCollection类型的集合,在平时使用的时候大多将它作为数组来使用,因为它有 length属性,也可以使用索引访问每一个元素。不过在访问性能上则比数组要差很多,原因是这个集合并不是一个静态的结果,它表示的仅仅是一个特定的查询,每次访问该集合时都会重新执行这个查询从而更新查询结果。所谓的 “访问集合” 包括读取集合的 length属性、访问集合中的元素。
  因此,当你需要遍历 HTML Collection的时候,尽量将它转为数组后再访问,以提高性能。即使不转换为数组,也请尽可能少的访问它,例如在遍历的时候可以将 length属性、成员保存到局部变量后再使用局部变量。
  b. Reflow & Repaint
  除了上面一点之外, DOM操作还需要考虑浏览器的 Reflow和Repaint ,因为这些都是需要消耗资源的,具体的可以参加以下文章:
如何减少浏览器的repaint和reflow?
Understanding Internet Explorer Rendering Behaviour
Notes on HTML Reflow

  (2). 慎用 with
with(obj){ p = 1}; 代码块的行为实际上是修改了代码块中的 执行环境 ,将obj放在了其作用域链的最前端,在 with代码块中访问非局部变量是都是先从 obj上开始查找,如果没有再依次按作用域链向上查找,因此使用 with相当于增加了作用域链长度。而每次查找作用域链都是要消耗时间的,过长的作用域链会导致查找性能下降。
  因此,除非你能肯定在 with代码中只访问 obj中的属性,否则慎用 with,替代的可以使用局部变量缓存需要访问的属性。
  (3). 避免使用 eval和 Function
  每次 eval 或 Function 构造函数作用于字符串表示的源代码时,脚本引擎都需要将源代码转换成可执行代码。这是很消耗资源的操作 —— 通常比简单的函数调用慢 100倍以上。
  eval 函数效率特别低,由于事先无法知晓传给 eval 的字符串中的内容,eval在其上下文中解释要处理的代码,也就是说编译器无法优化上下文,因此只能有浏览器在运行时解释代码。这对性能影响很大。
  Function 构造函数比 eval略好,因为使用此代码不会影响周围代码 ;但其速度仍很慢。
  此外,使用 eval和 Function也不利于Javascript 压缩工具执行压缩。
  (4). 减少作用域链查找(这方面设计到一些内容的相关问题)
  前文谈到了作用域链查找问题,这一点在循环中是尤其需要注意的问题。如果在循环中需要访问非本作用域下的变量时请在遍历之前用局部变量缓存该变量,并在遍历结束后再重写那个变量,这一点对全局变量尤其重要,因为全局变量处于作用域链的最顶端,访问时的查找次数是最多的。
  低效率的写法:
// 全局变量
var globalVar = 1;
function myCallback(info){
for( var i = 100000; i--;){
//每次访问 globalVar 都需要查找到作用域链最顶端,本例中需要访问 100000 次
globalVar += i;
}
}
  更高效的写法:
// 全局变量
var globalVar = 1;
function myCallback(info){
//局部变量缓存全局变量
var localVar = globalVar;
for( var i = 100000; i--;){
//访问局部变量是最快的
localVar += i;
}
//本例中只需要访问 2次全局变量
在函数中只需要将 globalVar中内容的值赋给localVar 中区
globalVar = localVar;
}
  此外,要减少作用域链查找还应该减少闭包的使用。
  (5). 数据访问
  Javascript中的数据访问包括直接量 (字符串、正则表达式 )、变量、对象属性以及数组,其中对直接量和局部变量的访问是最快的,对对象属性以及数组的访问需要更大的开销。当出现以下情况时,建议将数据放入局部变量:
  a. 对任何对象属性的访问超过 1次
  b. 对任何数组成员的访问次数超过 1次
  另外,还应当尽可能的减少对对象以及数组深度查找。
  (6). 字符串拼接
  在 Javascript中使用"+" 号来拼接字符串效率是比较低的,因为每次运行都会开辟新的内存并生成新的字符串变量,然后将拼接结果赋值给新变量。与之相比更为高效的做法是使用数组的 join方法,即将需要拼接的字符串放在数组中最后调用其 join方法得到结果。不过由于使用数组也有一定的开销,因此当需要拼接的字符串较多的时候可以考虑用此方法。

  关于 Javascript优化的更详细介绍请参考:
Write Efficient Javascript(PPT)
Efficient JavaScript
  2. CSS选择符
  在大多数人的观念中,都觉得浏览器对 CSS选择符的解析式从左往右进行的,例如
#toc A { color: #444; }
  这样一个选择符,如果是从右往左解析则效率会很高,因为第一个 ID选择基本上就把查找的范围限定了,但实际上浏览器对选择符的解析是从右往左进行的。如上面的选择符,浏览器必须遍历查找每一个 A标签的祖先节点,效率并不像之前想象的那样高。根据浏览器的这一行为特点,在写选择符的时候需要注意很多事项,有人已经一一列举了, 详情参考此处。

  3. HTML
  对 HTML本身的优化现如今也越来越多的受人关注了,详情可以参见这篇 总结性文章 。

  4. Image压缩
  图片压缩是个技术活,不过现如今这方面的工具也非常多,压缩之后往往能带来不错的效果,具体的压缩原理以及方法在《 Even Faster Web Sites》第10 章有很详细的介绍,有兴趣的可以去看看。
  总结
  本文从页面级以及代码级两个粒度对前端优化的各种方式做了一个总结,这些方法基本上都是前端开发人员在开发的过程中可以借鉴和实践的,除此之外,完整的前端优化还应该包括很多其他的途径,例如 CDN、 Gzip、多域名、无 Cookie服务器等等,由于对于开发人员的可操作性并不强大,在此也就不多叙述了,详细的可以参考 Yahoo和Google 的这些“金科玉律

 

Html语义化

一些常见html5语义化标签

20161026 20:45:17

阅读数:21134

            我们知道,创建结构清晰的页面可以建立良好的语义化基础,也降低了使用css的难度,下面总结了一些常用的语义化标签,有空慢慢更新,欢迎大家补充

 

         语义化HTML:用最恰当的HTML元素标记的内容。

      
        
优点:1 提升可访问性;

                    2 SEO

                    3 结构清晰,利于维护;


 

          (html5旧的行内元素都被归类为短语内容


 

           通用容器:div——块级通用容器;span——短语内容无语义容器。

           如果语义不合适,也不要霸王硬上弓,=。。 =老实的用div吧。
 


 

        < title></title>:简短、描述性、唯一(提升搜索引擎排名)。

         搜索引擎会将title作为判断页面主要内容的指标,有效的title应该包含几个与页面内容密切相关的关键字,建议将title核心内容放在前60个字符中。


 

         <hn></hn>:h1~h6分级标题,用于创建页面信息的层级关系。

         对于搜索引擎而言,如果标题与搜索词匹配,这些标题就会被赋予很高的权重,尤其是h1。


 

         <header></header>:页眉通常包括网站标志、主导航、全站链接以及搜索框。

        也适合对页面内部一组介绍性或导航性内容进行标记。


 

         <nav></nav>:标记导航,仅对文档中重要的链接群使用。

         html5规范不推荐对辅助性页脚链接使用nav,除非页脚再次显示顶级全局导航、或者包含招聘信息等重要链接。


 

         <main></main>:页面主要内容,一个页面只能使用一次。如果是web应用,则包围其主要功能。


 

         <article></article>:包含像报纸一样的内容= =||是这么理解的,表示文档、页面、应用或一个独立的容器。

         article可以嵌套article,只要里面的article与外面的是部分与整体的关系。


 

         <section></section>:具有相似主题的一组内容,比如网站的主页可以分成介绍、新闻条目、联系信息等条块。

         如果只是为了添加样式,请用div!


 

         <aside></aside>:指定附注栏,包括引述、侧栏、指向文章的一组链接、广告、友情链接、相关产品列表等。

          如果放在main内,应该与所在内容密切相关。


 

         <footer></footer>:页脚,只有当父级是body时,才是整个页面的页脚。

         
 

         <small></small>:指定细则,输入免责声明、注解、署名、版权。

         只适用于短语,不要用来标记“使用条款”、“隐私政策”等长的法律声明。


 

         <strong></strong>:表示内容重要性。

         <em></em>:标记内容着重点(大量用于提升段落文本语义)。

         <mark></mark>:突出显示文本(yellow),提醒读者。
 

         在HTML5中em是表示强调的唯一元素,而strong则表示重要程度。

           <b></b>:出于实用目的提醒读者的一块文字,不传达任何额外的重要性

            <i></i>:不同于其他文字的文字= =|||这个翻译真的是······


 

        <figure></figure>:创建图(默认有40px左右margin)。

        <figcaption></figcaption>:figure的标题,必须是figure内嵌的第一个或者最后一个元素。


 

        <cite></cite>:指明引用或者参考,如图书的标题,歌曲、电影、等的名称,演唱会、音乐会、规范、报纸、或法律文件等。

        只用于参考源本身,而不是从中引述。

        <blockquoto></blockquoto>:引述文本,默认新的一行显示。

        <q></q>:短的引述(跨浏览器问题,尽量避免使用)。

         可以对blockquoto和q元素使用cite属性(不是cite元素!),对搜索引擎自动化工具有用。cite=“URL”引述来源地址。


 

        <time></time>:标记时间。datetime属性遵循特定格式,如果忽略此属性,文本内容必须是合法的日期或者时间格式。     
        
不再相关的时间用s标签。


 

        <abbr></abbr>:解释缩写词。使用title属性可提供全称,只在第一次出现时使用就ok。

        abbr[title]{ border-bottom:1px dotted #000; }


 

        <dfn></dfn>:定义术语元素,与定义必须紧挨着,可以在描述列表dl元素中使用。


 

        <address></address>:作者、相关人士或组织的联系信息(电子邮件地址、指向联系信息页的链接)。

        如果提供整个页面的作者联系信息,一般放在页面级footer里。不能包含文档或者文档等其他内容。


 

        <del></del>:移除的内容。

        <ins></ins>:添加的内容。

        少有的既可以包围块级,又可以包围短语内容的元素。


 

        <code></code>:标记代码。包含示例代码或者文件名 (< &lt;  > &gt;)

        <pre></pre>:预格式化文本。保留文本固有的换行和空格。


 

        
        
<meter></meter>:表示分数的值或者已知范围的测量结果。如投票结果。

        例如:<meter value="0.2" title=”Miles“>20%completed</meter>


 

        <progress></progress>:完成进度。可通过js动态更新value。

作者:顾轶灵
链接:https://www.zhihu/question/20455165/answer/15176745
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

什么是语义化?其实简单说来就是让机器可以读懂内容。

先随便扯扯。对于当前的 Web 而言,HTML 是联系大多数 Web 资源的纽带,也是内容的载体。在 Web 被刚刚设计出来的时候,Tim Berners-Lee 可能不会想到它现在会达到的规模以及深入到我们生活的那么多方面。也许起初的想法很简单:用来发布 Web 内容和资源的索引,方便人们查看。

但是随着 Web 规模的不断扩大,信息量之大已经不在人肉处理的范围之内了。这个时候人们开始用机器来处理 Web 上发布的各种内容,搜索引擎就诞生了。再后来,人们又设计了各种智能程序来对索引好的内容作各种处理和挖掘。所以让机器能够更好地读懂 Web 上发布的各种内容就变得越来越重要。

其实 HTML 在刚开始设计出来的时候就是带有一定的「语义」的,包括段落、表格、图片、标题等等,但这些更多地只是方便浏览器等 UA 对它们作合适的处理。但逐渐地,机器也要借助 HTML 提供的语义以及自然语言处理的手段来「读懂」它们从网上获取的 HTML 文档,但它们无法读懂例如「红色的文字」或者是深度嵌套的表格布局中内容的含义,因为太多已有的内容都是专门为了可视化的浏览器设计的。面对这种情况,出现了两种观点:

  1. 我们可以让机器的理解能力越来越接近人类,人能看懂、听懂的东西,机器也能理解;
  2. 我们应该在发布内容的时候,就用机器可读的、被广泛认可的语义信息来描述内容,来降低机器处理 Web 内容的难度(HTML 本身就已经是朝这个方向迈出的一小步了)。

&lt;img data-rawheight="382" data-rawwidth="670" src="https://pic3.zhimg/50/01b4d93c152d2a9c2db734065be0f3f5_hd.jpg" class="origin_image zh-lightbox-thumb" width="670" data-original="https://pic3.zhimg/01b4d93c152d2a9c2db734065be0f3f5_r.jpg"&gt; 我画的这个图,意思是说,内容的语义表达能力和 AI 的智能程度决定了机器分析处理 Web 内容能力的高低。上面观点 1 的方向是朝着人类水平的人工智能努力,而观点 2 的方向正是万维网创始人 Tim Berners-Lee 爵士提出的美好愿景:语义网。语义网我就不多说了,简单来说就是让一切内容和包括对关系的描述都成为 Web 上的资源,都可以由唯一的 URI 定义,语义明确、机器可读。显然,两条路都的终极目标都很遥远,第一条路技术上难以实现,而第二条路实施起来障碍太多。

我认为我们当前能够看得见摸得着的 Web 语义化,其实就是在往第二条路的方向上,迈出的一小步,即对已经有的被广泛认可的 HTML 标准做改进。我们刚开始意识到,我们必须回归内容本身,将内容本身的语义合理地表述出来,再为不同的用户代理设计不同的样式描述,也就是我们说的内容与样式分离。这样我们在提供内容的时候,首先要做的就是将内容本身进行合理的描述,暂时不用考虑它的最终呈现会是什么样子。

HTML 规范其实一直在往语义化的方向上努力,许多元素、属性在设计的时候,就已经考虑了如何让各种用户代理甚至网络爬虫更好地理解 HTML 文档。HTML5 更是在之前规范的基础上,将所有表现层(presentational)的语义描述都进行了修改或者删除,增加了不少可以表达更丰富语义的元素。为什么这样的语义元素是有意义的?因为它们被广泛认可。所谓语义本身就是对符号的一种共识,被认可的程度越高、范围越广,人们就越可以依赖它实现各种各样的功能。

HTML5 并非 Web 语义唯一倚仗的规范,除了 W3C 和 WHATWG 外,还有其它的组织在为扩展、标准化 Web 语义做着贡献。只要有浏览器厂商、搜索引擎原意支持,它们的规范一样可以成为通用的基础设施。例如 microformats 社区以及 http://Schema 上都有对 HTML 以及 Microdata(http://www.w3/TR/html5/microdata.html) 规范的扩展词汇表,Google、Bing、Yahoo! 等搜索引擎以及各个主流浏览器都不同程度地接纳了其中定义的语义扩展,并应用在了生产中。

下面举两个 Google 应用扩展语义的例子。
Google 的搜索结果,可以根据 microformats 的 hCard 语法从抓取的页面识别出人物信息:
&lt;img data-rawheight="263" data-rawwidth="616" src="https://pic1.zhimg/50/f8ba9082973b5a7abcbfa969c02e3ce7_hd.jpg" class="origin_image zh-lightbox-thumb" width="616" data-original="https://pic1.zhimg/f8ba9082973b5a7abcbfa969c02e3ce7_r.jpg"&gt;
也可通过网页内嵌的 Microdata 数据读取作品评分等信息:
&lt;img data-rawheight="135" data-rawwidth="497" src="https://pic2.zhimg/50/3c5b54fb608597a098c13bac9a1b922c_hd.jpg" class="origin_image zh-lightbox-thumb" width="497" data-original="https://pic2.zhimg/3c5b54fb608597a098c13bac9a1b922c_r.jpg"&gt; 关于 HTML5 的各个元素语义的描述,我之前做过一份 slides,上面提到的例子都是那里面的,也可以参考一下:Semantic HTML(http://justineo.github/slideshows/semantic-html/)。

1、什么是HTML语义化?

<基本上都是围绕着几个主要的标签,像标题(H1~H6)、列表(li)、强调(strong em)等等>

  根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地解析。

2、为什么要语义化?

  • 为了在没有CSS的情况下,页面也能呈现出很好地内容结构、代码结构:为了裸奔时好看;
  • 用户体验:例如titlealt用于解释名词或解释图片信息、label标签的活用;
  • 有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;
  • 方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;
  • 便于团队开发和维护,语义化更具可读性,是下一步吧网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化。

3、写HTML代码时应注意什么?

  • 尽可能少的使用无语义的标签divspan
  • 在语义不明显时,既可以使用div或者p时,尽量用p, 因为p在默认情况下有上下间距,对兼容特殊终端有利;
  • 不要使用纯样式标签,如:bfontu等,改用css设置。
  • 需要强调的文本,可以包含在strong或者em标签中(浏览器预设样式,能用CSS指定就不用他们),strong默认样式是加粗(不要用b),em是斜体(不用i);
  • 使用表格时,标题要用caption,表头用thead,主体部分用tbody包围,尾部用tfoot包围。表头和一般单元格要区分开,表头用th,单元格用td
  • 表单域要用fieldset标签包起来,并用legend标签说明表单的用途;
  • 每个input标签对应的说明文本都需要使用label标签,并且通过为input设置id属性,在lable标签中设置for=someld来让说明文本和相对应的input关联起来。

 4HTML5新增了哪些语义标签

HTML 5出来之前,我们用div来表示页面章节,但是这些div都没有实际意义。(即使我们用css样式的idclass形容这块内容的意义)。这些标签只是我们提供给浏览器的指令,只是定义一个网页的某些部分。但现在,那些之前没意义的标签因为因为html5的出现消失了,这就是我们平时说的语义

看下图没有用div标签来布局

 

 

 

html5的布局

嗯,如上图那个页面结构没有一个div,都是采用html5语义标签(用哪些标签,关键取决于你的设计目标)。

但是也不要因为html5新标签的出现,而随意用之,错误的使用肯定会事与愿违。所以有些地方还是要用div的,就是因为div没有任何意义的元素,他只是一个标签,仅仅是用来构建外观和结构。因此是最适合做容器的标签。

W3C定义了这些语义标签,不可能完全符合我们有时的设计目标,就像制定出来的法律不可能流传100年都不改变,更何况它才制定没多久,不可能这些语义标签对所以设计目标的适应。只是一定程度上的通用,我们的目标是让爬虫读懂重要的东西就够了。

结论:不能因为有了HTML 5标签就弃用了div,每个事物都有它的独有作用的。

节点元素标签因使用的地方不同,我将他们分为:节元素标签、文本元素标签、分组元素标签分开来讲解HTML5中新增加的语义化标签和使用总结。

 

Nodejs怎么连接mongodb,express框架


Nodejs Express 连接Mongodb

20170217 17:36:39

阅读数:1365

安装MongoDB

自行下载安装 
下载mongodb

设置环境变量

mongodb  安装目录的 E:\Program Files\MongoDB\Server\3.4\bin 写入环境变量

启动服务

控制台 输入 mongodb --dbpath E:\MongoDB\data   这后面的路径便是数据集合的路径 
服务启动成功提示

 

MongoDB监听的是27017端口,打开浏览器输入http://127.0.0.1:27017,则会看到如下提示:
It looks like you are trying to access MongoDB over HTTP on the native driver port.

如果嫌每次输入命令打开服务麻烦的话可以 写成一个批处理文件 .bat 文件, 写上代码

start mongod --dbpath E:\MongoDB\data  
  • 1

安装模块

npm install mongoose --save 
  • 1

使用MongoDB

连接

app.js 文件中

// app.js
 
var mongoose = require('mongoose');            
 
mongoose.connect('mongodb://localhost/blog')     //连接本地数据库blog 
 
var db = mongoose.connection;
 
// 连接成功
db.on('open', function(){
    console.log('MongoDB Connection Successed');
});
// 连接失败
db.on('error', function(){
    console.log('MongoDB Connection Error');
});

连接成功后接下来写一个 登录注册

添加登录注册页面

views模块下添加 login.html register.html

<!-- login.html -->
 
<h1>登录页面</h1>
   <div>
        <form action="/login" method="post">
            <p>
                <label for="username">用户名</label>
                <input type="text" id="username" name="username" placeholder="用户名">
            </p>
            <p>
                <label for="password">密码 : </label>
                <input type="text" id="password" name="password" placeholder="密码">
            </p>
            <p>
                <input type="submit" value="登录">
            </p>
        </form>
    </div>
<!-- register.html -->
<h1>注册页面</h1>
    <a href="/login"> 去登录 </a>
    <div>
        <form action="/register" method="post">
            <p>
                <label for="username">用户名</label>
                <input type="text" id="username" name="username" placeholder="用户名">
            </p>
            <p>
                <label for="password">密码 :</label>
                <input type="text" id="password" name="password" placeholder="密码">
            </p>
            <p>
                <label for="age">年龄 :</label>
                <input type="text" id="age" name="age" placeholder="年龄">
            </p>
            <p>
                <label for="address">地址 :</label>
                <input type="text" id="address" name="address" placeholder="地址">
            </p>
            <p>
                <input type="submit" value="注册">
            </p>
        </form>
    </div>

新增Models 模块

在根路径下新建 Models 文件夹。 添加 users.js

// Models/users.js
 
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
 
// 声明一个数据集 对象
var userSchema = new Schema({
    username: {
        type: String,
        unique: true
    },
    password: {
        type: String
    },
    age: Number,
    address: String,
    createAt: {
        type: Date,
        default : Date.now()
    }
});
// 将数据模型暴露出去
module.exports = mongoose.model('users', userSchema);

编写路由

// routes/index.js
 
var express = require('express');
var router = express.Router();
var User = require('../models/users');
 
router.get('/login', function (req, res) {
    res.render('login');
});
router.get('/register', function (req, res) {
    res.render('register');
});
 
// 这里的业务逻辑将写在 两个post 路由里 
router.post('/login', function (req, res) {
 
});
router.post('/register', function (req, res) {
 
});

这里我们需要安装一个模块 body-parser 用来解析post请求的参数

npm install body-parser --save
  • 1
// app.js 
 
var bodyParser = require('body-parser')
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false}));

这样我们就可以通过 request.body 来拿到post 请求过来的 数据了

先写一个注册的

// routes/index.js
 
router.post('/register', function (req, res) {
 
    // 获取用户提交的信息
    var postData = {
        username: req.body.username,
        password: req.body.password,
        age: req.body.age,
        address: req.body.address
    };
    // 查询是否被注册
    User.findOne({username: postData.username}, function (err, data) {
        if (data) {
            res.send('用户名已被注册');
        } else {
            // 保存到数据库
            User.create(postData, function (err, data) {
                if (err) throw err;
                console.log('注册成功');
                res.redirect('/userList');      // 重定向到所用用户列表
            })
        }
    });
});
 
// 获取所有用户列表
router.get('/userList', function (req, res) {
    var userList = User.find({}, function (err, data) {
        if (err) throw  err;
        res.send(data)
    });
});

上面通过 mongoose api 对数据库进行操作

Mongoose Api

然后就是验证登录的了

router.post('/login', function (req, res) {
    var postData = {
        username: req.body.username,
        password: req.body.password
    };
    User.findOne({
        username: postData.username,
        password: postData.password
    }, function (err, data) {
        if(err) throw err;
        if(data){
            res.send('登录成功');
        }else{
            res.send('账号或密码错误')
        }
    } )
});

到这里就基本完成了 Express Mongodb 的连接,插入,查询。

ps : 参考文档 Mongoose Api

  1.  

 

盒子塌陷:本应该在父盒子内部的元素跑到了外部

原因:父盒子没有设置足够大小,尤其是父盒子高度为auto时,而且没有其他非浮动元素,父盒子的高度就会直接塌陷为0

解决办法:清除浮动3种方式

            把盒子大小写死

给父盒子添加浮动/overflow属性/最下方引入清除浮动块

更多推荐

综合一

本文发布于:2023-04-21 04:16:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/11f6f6e555b497a1fc7079dfa2b42f51.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!

  • 92351文章数
  • 23537阅读数
  • 0评论数