NiYingfeng 的博客

记录技术、生活与思考

0%

对于一种语言来讲,正则无疑是其中很重要的内容,由于正则对于新手来说并不是那么简单,它是较为复杂的模块。所以我们可以看到很多草率的正则表达式。所以很多情况我们在性能方面遇到的瓶颈问题都是由于并不理想的正则表达式引起的。 首先我们需要了解下正则表达式在运行过程中的工作原理

  1. 编译:当创建一个正则表达式时,浏览器会验证该模式,然后将其转化为一个原生的代码程序,用于执行匹配工作。
  2. 设置起始位置:确认目标字符串起始的搜索位子,是由字符串的起始搜索位子或者正则表达式中的lastIndex属性决定的。
  3. 匹配每个正则表达式字元:正则表达式会逐个检查文本和正则表达式模式,当摸一个匹配失败的时候会试着回溯到之前尝试匹配的位子上然后尝试其他匹配路径。
  4. 匹配成功或者失败:如果正则表达式的所有可能路径都没有匹配到,那么会退回到第二步来从下个字符来进行匹配。

对于正则性能理解的关键在于理解回溯的概念。 每当正则表达式在匹配过程中,回溯是基础的组成部分。很大程度上也是正则表达式是否优越性的判定条件。但是一旦失控,就会产生巨大的系统资源消耗,对于整体的性能有着很大的影响。 每当正则表达式扫描字符串的时候,它从左到右来进行逐个测试组成部分,对每一个量词与分支都决定下一次走向,如有必要会记住其他的选着,以备返回的时候使用。如果当前匹配成功,正则表达式会继续扫描模式,如果不成功那么将回 到上一次最近的一个决策点,从另一个分支或者量词来重新进行匹配,直到成功。如果所有的匹配项都尝试已经没有匹配到,那么返回正则表达式不匹配的结果。 实例: /h(ello|appy) hippo/.test(“hello there , happy hippo .”);

  1. 提取 h 进行匹配。
  2. 提取 ello 进行匹配。
  3. 提取 hippo进行匹配(匹配失败)。
  4. 回到上一个决策点, h 之后的位子,提取 appy(匹配失败)。
  5. 从第二个字符开始重新匹配整个表达式, 匹配 h (往后一个一个字符匹配)。
  6. 匹配 ello (匹配失败)。
  7. 匹配 appy。
  8. 匹配 hippo(整体匹配成功)。

实例:

1
2
3
4
```
var str = "<p>p1</p><div>div1</div><p>p2</p>";
/<p>.*<\/p>/i.test(str);//由于会有贪婪匹配,所以会匹配到整个字符串
/<p>.*?<\/p>/i.test(str);//非贪婪匹配,则会匹配 <p>p1</p>
1
2
3

对于不了解贪婪匹配与非贪婪匹配的可以谷歌下。 然后是想一下回溯失控,

/[\s\S]\*?[\s\S]\*?
```

this 关键词与面向对象编程有密切的关系,一直以来感觉 this 这东西很玄乎,很难把握其根本,从而导致了经常性的对 this 关键词进行对象查找的时候引发一些问题或者BUG。 其实当我们理顺思路,对于 this 的判断还是很简单的。 this 在 javascript 中只会存在于函数中(如在全局作用域中,则指向 Global 对象,即浏览器中的 window 对象),其只有4中函数调用方式: 1.Function Invocation Pattern(纯粹的函数调用) 当在全局中生命一个 function 并且调用它,那么函数中的 this 指向 window。

1
2
3
4
5
6
function a(){
this.b = "c";
console.log(this === window);// true
}
a();
console.log(b);// "c"

2.Method Invocation Pattern(作为方法调用) 当作为一个方法调用的时候,即某一被调用函数被作为某个对象的属性,this指向调用该方法的对象。

1
2
3
4
5
6
7
var a ={};
a.b = function(){
this.x = 1;
console.log(this === a);
}
a.b();// true
a.x; // 1

3.Constructor Pattern(构造函数式调用) 使用 new 操作符来进行函数的调用,this 指向新创建的对象。

1
2
3
4
5
function a(){
this.x = 1;
}
var b = new a();
b.x;// 1

4.Apply Pattern(apply 调用) 使用内置的 call 和 apply 来进行调用,那函数内部的 this 将指向其第一个参数。

1
2
3
4
5
6
function a(){
this.x = 1;
}
var b = {}
a.apply(b);
b.x;// 1

当我们明白对于 this 的4中其函数调用方式,便可以很明白的 this 指向的对象。 如果想要深入的了解js中this的信息的 可以看大叔的www.cnblogs.com/tomxu/archive/2012/01/17/2310479.html

首先上一一个简单的 new 操作符实例

1
2
3
4
5
6
7
8
9
var Person = function(name){
this.name = name;
this.say = function(){
return "I am " + this.name;
};
}

var nyf = new Person("nyf");
nyf.say();

简单来说,上述例子中,以 new 操作符调用构造函数的时候,函数内部发生以下变化:

  1. 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
  2. 属性和方法被加入到 this 引用的对象中。
  3. 新创建的对象由 this 所引用,并且最后隐式的返回 this 。

以上情况在 new 操作符调用下,后台就相当于

1
2
3
4
5
6
7
8
var Person = function(name){
//var this = {};
this.name = name;
this.say = function(){
return "I am " + this.name;
};
//return this;
}

对于以上的讲述不知道有没有讲清楚。

1
var obj = new Base();

相当于运行以下代码

1
2
3
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);

对于ES5中添加了 Object.create(),

1
2
3
4
5
6
7
if(typeof Object.create !== "function"){
Object.create = function(o){
function F(){};
F.prototype = o;
return new F();
}
}

遇到Array.prototype.slice也是在jQuery中,其toArray()就是使用的Array.prototype.slice.call来进行的处理。 那到底他的用途是什么呢? 其实很简单,将像arguments那种的类数组对象转换为数组的形式。

1
Array.prototype.slice.call(arguments,0);

具体可以看以下代码

1
2
3
4
5
6
7
8
9
10
11
function curry(){
alert('arguments:'+arguments);
alert('typeof arguments:'+typeof arguments);
alert('arguments instanceof Array:'+(arguments instanceof Array));
var args = Array.prototype.slice.call(arguments,0);
alert('args:'+args);
alert('typeof args:'+typeof args);
alert('args instanceof Array:'+(args instanceof Array));
}

curry("s","a","d");

从这里可以一目了然的看到起作用是很明显的,我们很多时候希望在函数中处理arguments,使其转换为数组形式更为简便明了。 还有一个问题就是在谷歌,火狐等浏览器下

1
Array.prototype.slice.call("abcd",0);

也会转变为数组,在IE下就会有误,为空。这个可能需要从原理上来解决。比较JS解析器是不一样的,目前我也没有什么具体答案。

对于数字的从大到小排序,我们应该依旧记得,刚刚学习编程语言是那种经典的算法-冒泡法。那属于一种简单的但是并不高效的算法。 今天来说一下另一种简单的算法-快速排序。快速排序的思想是,将数字头作为base数,进行判断排序后将小于base数的置于base数左侧,大于base数的置于base数右侧,再以现在的base数作基准,将左右2侧的子数组同样处理。 第一步方法为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function division(arr,l,r){
var base = arr[l];
while(l<r){
while(l<r&&arr[r]>=base){
r--;
}
arr[l] = arr[r];

while(l<r&&arr[l]<=base){
l++;
}
arr[r] = arr[l];
}
arr[l] = base;
return l;
}

第二步为迭代循环:

1
2
3
4
5
6
7
function list(arr,l,r){
if(l<r){
var i = division(arr,l,r);
arguments.callee(arr,l,i-1);
arguments.callee(arr,i+1,r);
}
}

使用它:

1
2
var arr = [92,23,45,22,53,74,24,7];
list(arr,0,7);

这里是在原数组进行处理的。

最近遇到一个很常见的JS在IE下的兼容性问题,其实也很简单,主要由于IE6下调试工具较少不好发现导致花费了挺多的时间。 首先说一下我遇见的关于getElementById的小小兼容性问题吧,都知道 document.getElementById 是获取DOM节点中指定id的节点,但是在IE6下,会把某些标签中(并不是所有标签)的name也当做 getElementById 可获取的元素,有时真会发生影响不到的坑。 我是在获取相应id节点后再插入一个div,没想到在head的标签内竟然将其name属性设置了可这个ID一样的名字。真是妹的我去了!!!IE6中只是看到该div不显示,真不容易发现其错误。关键是标签内无内容,弹出其innerHTML还未空。呵呵~ 下面是一些有意思的代码: 下面代码在IE6下会获取正常的DOM节点:

1
2
3
4
5
6
7
8
9
10
11
<body>
<p name="abc" id="cba">
这是第1个div
</p>
<div id="abc">
这是第2个div
</div>
<script language=javascript>
alert(document.getElementById("abc").id);
</script>
</body>

而下面代码就会有问题:

1
2
3
4
5
6
7
8
9
10
11
<body>
<a name="abc" id="cba" href="http://www.baidu.com">
这是第1个div
</a>
<div id="abc">
这是第2个div
</div>
<script language=javascript>
alert(document.getElementById("abc").id);
</script>
</body>

所以,对于IE6下 getElementById方法出现BUG也是针对于相关标签的。包括 meta标签 a标签 form标签以及一些相关表单元素。 主要解决方法是 注意整体的name使用,不要将name与id值混淆使用,这个是最优方式。 还有就是方法判断,这是司徒正南给的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var getElementById = function(id){
var el = document.getElementById(id);
if(!+"\v1"){
if(el && el.attributes['id'].value === id){
return el
}else{
var els = document.all[id],n = els.length;
for(var i=0;i<n;i++){
if(els[i].attributes['id'].value === id){
return els[i]
}
}
}
}
return el;
}

有时我们需要动态生成效果,那么就需要对页面的css进行各种处理,进而达到一些样式的改变。如动画,拖放等效果。所以使用JS正确的来对页面样式修改是灰常重要的。

1.修改标签的class属性值

直接在css中定义多种css类型 然后在事件中对DOM对象的 class属性进行切换,是最简单可行的一种方式。也是目前使用最多的方法。 当然最简单的就是使用

1
2
3
4
5
```
<script type="text/javascript">
var obj = document.getElementById("div");
obj.className = "otherclass";
</script>
1
2
3

非标准ECMAScript来进行修改其class的值。 还有就是使用ES标准来进行修改,就是使用DOM的setAttribute方法。但是他有一个兼容性问题。

1
2
3
4
5
<script type="text/javascript">
var obj = document.getElementById("div");
obj.setAttribute("className","otherclass");//IE下使用className
obj.setAttribute("class","otherclass");//FF下的方式 所以要注意
</script>
1
2
3
4
5

一个简单的小问题,但也需要注意。
### 2.添加行内样式进行覆盖
直接使用 dom_obj.style.*** = "***"; 来进行对其样式的覆盖。由于行内样式优先级最高,所以能覆盖其他节点的样式。 该方法也是极为常用的,唯一需要注意的就是对于样式名的大小写问题。如:border-left 应该为 borderLeft 使用该方法我们可能需要用到计算当前样式值的方法。这里也具有兼容性问题。 currentStyle只有IE支持。取得当前应用的样式。 getComputedStyle支持FF,Opera,Safari,Chrome等浏览器。取得最终应用的样式。

1
2
3
4
5
6
7
8
<script type="text/javascript">
var obj = document.getElementById("div");
objh=document.defaultView.getComputedStyle(obj,null).height;
//或者
objh=window.getComputedStyle(obj,null)[height];
//IE下 需要
objh=obj.currentStyle[height];
</script>
1
2
3

下面是一个解决兼容性方法

1
2
3
4
5
6
7
8
9
10
11
function getStyle(element,property) {
var value = element.style[camelize(property)];
if(!value) {
if(document.defaultView && document.defaultView.getComputedStyle) {
value = document.defaultView.getComputedStyle(element).getPropertyValue(property);
} else if(element.currentStyle) {
value = element.currentStyle[camelize(property)];
}
}
return value;
}
1
2
3

其实 setAttribute方法 是有3个参数的。

1
object . setAttribute ( sName , vValue , iFlags )
1
2
3
4
5
6
7
8
9
10

参数: sName : 必选项。字符串(String)。指定属性的名称。 vValue : 必选项。要赋给属性的值。可以是任何需要的变量类型。 iFlags : 可选项。整数值(Integer)。0 | 1 0 : 当属性被设置的时候,对象任何已有的同名属性设置都会被覆盖,而不会考虑它们的大小写。 1 : 默认值。执行严格考虑字母大小写的属性设置。假如此方法的 iFlags 参数设置为 1 ,则执行 iFlags 参数设置为 0 的 getAttribute 方法时,满足 sAttrName 指定的特性名称不一定能被找到。
### 3.修改样式表
获取文档样式表的lists document.styleSheets[0];//获取第一个样式表 W3C坚持使用cssRules[],而微软坚持rules[]。 document.styleSheets[0].cssRules[0];//W3C 获取第一个样式表的第一个样式信息 document.styleSheets[0].rules[0];//IE 获取第一个样式表的第一个样式信息 更多信息请查询 document.styleSheets 的相关信息。
### W3C DOM2样式规则

### CSSStyleSheet对象

CSSStyleSheet对象表示的是所有CSS样式表,包括外部样式表和使用标签指定的嵌入式样式表。 CSSStyleSheet同样构建于其他的DOM2 CSS对象基础之 上,而CSSStyleRule对象表示的则样式表中的每条规则。 通过document.stylesheets属性可以取得文档中CSSStyleSheet对象的列表,其中每个对象有下列属性

1
2
3
4
5
6
7
8
9
10
type        始终为text/css
disabled      相应样式表是应于还是禁用于当前文档
href        样式表相对于当前文档的URL
title        分组样式标签
media       样式应用的目标设备类型(screen、print)
ownerRule     只读CSSRule对象,若样式用@import导入,表示其父规则
cssRules      只读cssRuleList列表对象,包含样式表中所有CSSRule对象

insertRule(rule,index)    添加新的样式声明
deleteRule(index)      从样式表中移除规则
1
2
3
4
5

### CSSStyleRule对象

每个CSSStyleSheet对象内部包含着一组CSSStyleRule对象。这些对象分别对应着类似下面这样一条规则:

1
2
3
4
5
body{
font:lucida,verdana,sans-serif;
background:#c7600f;
color:#1a3800;
}
1
2
3

CSSStyleRule对象具有下列属性:

1
2
3
4
5
6
type        继承自CSSRule对象的一个属性,以0~6中的一个数字表示规则类型
cssText       以字符串形式表示的当前状态下的全部规则
parentStyleSheet   引用父CSSStyleRule对象
parentRule      如果规则位于另一规则中,该属性引用另一个CSSRule对象
selectorText     包含规则的选择符
style        与HTMLElement.style相似,是CSSStyleDeclaration对象的一个实例
1
2
3
4
5

### CSSStyleDeclaration对象

表示一个元素的style属性,与CSSStyleRule对象类似,CSSStyleDeclaration具有下面属性: cssText    以字符串形式表示的全部规则 parentRule   将引用CSSStyleRule对象

1
2
3
getPropertyValue(propertyName)      CSS样式属性值
removeProperty(propertyName)       从声明中移除属性
setProperty(propertyName,value,priority)   设置CSS属性值

```

CSS hack是基于浏览器的不同,如IE,FF等,各个浏览器对于CSS的解析不同,就会导致页面产生一些差异,是我们的设计在不同浏览器上得到不同的效果。 这个时候我们就需要针对不同的浏览器去写不同的CSS,让它能够同时兼容不同的浏览器,能在不同的浏览器中也能得到我们想要的页面效果。 CSS hack大致有3种表现形式。CSS内部样式hack,选择器hack以及HTML头部引用(if IE)hack。 先来看看简单的CSS内部样式hack使用表:(括号中的 S 代表标准模式 Q 代表混杂模式) 上面列表中很清楚的标出了各个hack对于版本的适用性,hack通常的用法就是以 适用性少的来覆盖适用性多的。(IE6 对于 !important 可以查看一些资料,并不是所说的那么简单) 如:(均以标准模式进行说明)

1
2
3
4
5
6
7
8
9
10
#test 
{
width:300px;
height:300px;
background-color:blue; /*firefox*/
background-color:red\9; /*all ie*/
background-color:yellow\0; /*ie8*/
+background-color:pink; /*ie7*/
_background-color:orange; /*ie6*/
}

在该css中 :

  • background-color:blue; 为标准的语句,是适用与所有的浏览器。
  • background-color:red\9; 为适用与所有的IE浏览器。故而在所有的IE浏览器中会覆盖background-color:blue;的效果。
  • background-color:yellow\0; 为适用与IE8的浏览器。
  • +background-color:pink; 为适用与IE6和IE7的浏览器(与 * 一样)。
  • _background-color:orange; 为适用与IE6的浏览器。

所以 一层层的适用,一层层的覆盖。从而达到了我们想要的,在不同浏览器下实现不同效果的目的。当然这不是真正的目的,CSS hack最多的还是用于在个别浏览器与其他浏览器有一定偏差时来进行CSS样式的改善,完善网站的美观性。以及代码的兼容性问题。 对于CSS选择器hack则较为简单: 1. IE6以及IE6以下版本浏览器 * html .demo {color: green;} 2. 仅仅IE7浏览器 *:first-child+html .demo {color: green;} 3. 除IE6之外的所有浏览器(IE7-9, Firefox,Safari,Opera) html>body .demo {color: green;} 4. IE8-9,Firefox,Safari,Opear html>/**/body .demo {color: green;} 5. IE9+ :root .demo {color: red;} 6. Firefox浏览器 @-moz-document url-prefix() { .demo { color: red; }} 7. Webkit内核浏览器(Safari和Google Chrome) @media screen and (-webkit-min-device-pixel-ratio:0) {.demo { color: red; }} 8. Opera浏览器 @media all and (-webkit-min-device-pixel-ratio:10000), not all and (-webkit-min-device- pixel-ratio:0) {head~body .demo { color: red; }} 9. iPhone / mobile webkit @media screen and (max-device-width: 480px) { .demo { color: red } } 最后一种就是较为官方的 IF IE的头部判断的hack方法。

  1. 条件注释的基本结构和HTML的注释()是一样的。因此IE以外的浏览器将会把它们看作是普通的注释而完全忽略它们。
  2. IE将会根据if条件来判断是否如解析普通的页面内容一样解析条件注释里的内容。
  3. 条件注释使用的是HTML的注释结构,因此他们只能使用在HTML文件里,而不能在CSS文件中使用。

对于判别符号

  • lte:就是Less than or equal to的简写,也就是小于或等于的意思。
  • lt :就是Less than的简写,也就是小于的意思。
  • gte:就是Greater than or equal to的简写,也就是大于或等于的意思。
  • gt :就是Greater than的简写,也就是大于的意思。
  • ! :就是不等于的意思,跟java script 里的不等于判断符相同