风为人世在,在世人为风。

巧用XSS为实际需求服务

昨天早上和JerryQu骑车上班的途中聊天,他这几天遇到一个特殊的需求。

页面中调用一个通过CMS发布的callback,callback返回一段字符串内容,然后页面拿到内容后直接innerHTML塞到某个ID里面去。本身这是个很简单的需求。

但是现在需求复杂了,希望callback返回内容中有一段脚本,用来操作页面的DOM。不想改变页面的原因是,要走整套上线流程,非常麻烦,你们懂的。

也就是本事返回的内容是“这是返回的内容”,现在变成“这是返回的内容<script>这里增加一些脚本操作页面</script>”,但是这样直接innerHTML进去的话是不被执行的。

一种解决方案是,将script标签变成iframe,嵌套一个新的页面(这个页面也是通过CMS发布,所以也很方便),然后iframe的页面用来操作父页面的DOM(当然是在同一个域下)。

后来想到了一种解决方案。利用XSS经常用的方式,插入一个img标签,设置src为一个不存在的URL,然后再onerror事件里操作页面的DOM,如:

返回内容为“这是返回的内容<img src=”h” onerror=”这里的脚本用来操作页面DOM”>”。

经测试,一切OK。

按字节截取字符串

在JS中,由于中文和英文是同等对待的,但有时候我们希望是一个中文按两个字节算,这就出现了按字节截取字符串的功能。下面列举了 2种实现方式。

循环检测

这种实现方式来自于Tangram,具体实现如下:

  1. baidu.string.getByteLength = function (source) {
  2.    return String(source).replace(/[^\x00-\xff]/g, "ci").length;
  3.    };
  4. /*
  5. * Tangram
  6. * Copyright 2009 Baidu Inc. All rights reserved.
  7. *
  8. * path: baidu/string/subByte.js
  9. * author: dron, erik
  10. * version: 1.1.0
  11. * date: 2009/11/30
  12. */
  13. /**
  14. * 对目标字符串按gbk编码截取字节长度
  15. *
  16. * @param {string} source 目标字符串
  17. * @param {number} length 需要截取的字节长度
  18. * @return {string} 字符串截取结果
  19. */
  20. baidu.string.subByte = function (source, length) {
  21.    source = String(source);
  22.    var getLen = baidu.string.getByteLength, i, len, current, next, currentLen, nextLen;
  23.    if (length < 0 || getLen(source) <= length) {
  24.       return source;
  25.       }
  26.    len = source.length;
  27.    for (i = Math.floor(length / 2) - 1; i < len; i++) {
  28.       current = next || source.substr(0, i);
  29.       currentLen = nextLen || getLen(current);
  30.       if (currentLen == length) {
  31.          return current;
  32.          }
  33.       else {
  34.          next = source.substr(0, i + 1);
  35.          nextLen = getLen(next);
  36.          if (nextLen > length) {
  37.             return current;
  38.             }
  39.          }
  40.       }
  41.    return source;
  42.    };

baidu.string是字符串常见操作的对象。

正则替换

这种方式的实现原理是先将中文替换成中文加个空格,这样变相的将一个中文变成了2个字节,然后在这个基础上截取,截取完成后在将中文加空格变成中文。

  1. baidu.string.subByte1 = function(source, length){
  2.     return (source+'').substr(0,length).replace(/([^\x00-\xff])/g,'$1 ').substr(0,length).replace(/([^\x00-\xff]) /g,'$1');
  3. }

这种实现方式不管是从代码量上还是从效率上都要比第一种高很多,这里有个测试案例

js动态创建类和实例化

在js中,创建一个类和实例化该类一般方式是:

  1. var cls = function(){}
  2. cls.prototype = {
  3. attr:'',
  4. method:function(){}
  5. }
  6. var clsInstance = new cls;

这种方式简单明了,但如果类很多的话就比较痛苦了,并且代码看起来不够优化。

动态创建类

动态创建类实际上类似于一种代理的模式,代码如下:

  1. var Fath = function(methods){
  2.     var cls = function(){
  3.         return new fn(arguments);
  4.     },
  5.     fn = function(args){
  6.         return this.init && this.init.apply && this.init.apply(this,args);
  7.     };
  8.     fn.prototype = cls.prototype = methods || {};
  9.     try{
  10.         return cls;
  11.     }finally{
  12.         cls = null;
  13.     }
  14. }

创建一个类:
var TestClass = Fath(methods) //这里的methods是方法或者属性集合,是一个静态对象
实例化该类:
var testInstance = TestClass(params) //这里的params是传进去的形参
通过这种方式后,一个好处就是实例化类的时候不用再使用new了,当然使用new也是可以的,作用的等价的。避免了到处是new和prototype的好处。
性能上在1K数量级上没有很大的区别。

select节点clone全解析

在开发ns-log项目中,统计分类有复制的功能。由于之前的统计分类中的数据是通过JS赋值进去的,之后用户可能又进行了修改,发现进行节点克隆时,出现了 无法复制select下拉框值的怪异现象。本文对这个怪异现象进行解析和给出解决办法。

问题现状

使用节点的cloneNode(true/false)进行克隆时,目前是下面的表现情况:

  1. select为设置初始值或者初始值是第一个option。
    表现:各大浏览器都没什么问题。
  2. select初始值不是在第一个option。
    表现:IE下无法克隆,其他内核的浏览器没什么问题。
  3. select的值被用户或者JS修改。
    表现:各个浏览器均无法克隆到真确的值。值结果跟第二条结果相同。

继续阅读 »

javascript中toInt的几种方法

在javascript中,如果要将一个字符串转变成数字,一般是通过parseInt这个函数进行。但如果对输入串有很高确定性的话,其实可以用更简单的方法。如:只是将字符串“123”变成数字123。下面给出具体的说明。

parseInt函数

parseInt函数是专门用来处理将字符串变成整型的。具体请见:ECMA-262 P114。

  1. 支持八进制和十六进制,如:’0111′,’0×111′。
  2. 支持非正数。如:’-111′。
  3. 支持数字后还有字符串,如:’111abc’。
  4. 支持第二个参数,是传递的转换进制,数值为2到36。如:parseInt(’111′,2),即将111转换为二进制。
  5. 忽略前面的空白字符,如:\n,\t,\r。
  6. 如果无法将字符串转换为一个数值,则返回NaN。

继续阅读 »

javascript数组唯一化实现方式

到目前为止,javascript中array还没有内置的unique方法,本来这篇文章很早就写了,但由于之前的虚拟主机忘记续费导致数据丢了,前几天JerryQu问了我这个问题,觉得可能还有其他人要,这里在写出来,备大家参考。

实现方式

这里给出2中实现方式。一种是大家应该都知道的indexOf检测的方式,另一种是结合lastIndexOf和splice实现方式。

//首先给Array对象原型上添加indexOf和lastIndexOf方法.(如果没有的话)
if(!Array.prototype.indexOf){
    
Array.prototype.indexOf = function(element, index){
        
var length = this.length;
        
if(index == null){
            
index = 0;
        
}else{
            
index = +index || 0;
            
if(index < 0) index+= length;
            
if(index < 0) index = 0;
        
}
        
for(var current;index<length;index++){
            
current = this[index];
            
if(current === element) return index;
        
}
        
return -1;
    
}
}
if(!Array.prototype.lastIndexOf){
    
Array.prototype.lastIndexOf = function(element, index){
        
var length = this.length;
        
if(index == null){
            
index = length - 1;
        
}else{
            
index = +index || 0;
            
if(index < 0) index+= length;
            
if(index < 0) index = -1;
            
else if(index >= length) index = length - 1;
        
}
        
for(var current;index>=0;index--){
            
current = this[index];
            
if(current === element) return index;
        
}
        
return -1;
    
}
}
//很常见的实现方式
var arrayUnique1 = function(arr){
    
for(var i=0,len=arr.length,result=[],item;i<len ;i++){
        
item = arr[i];
        
if(result.indexOf(item) < 0) {
            
result[result.length] = item;
        
}
    
}
    
return result;
}
//通过lastIndexOf和splice方法实现方式
var arrayUnique2 = function(arr){
    
var length = arr.length;
    
while(--length){
                
//如果在前面已经出现,则将该位置的元素删除
        
if(arr.lastIndexOf(arr[length],length-1) > -1) {
            
arr.splice(length,1);
        
}
    
}
    
return arr;   
}
<
/len>

继续阅读 »

javascript中关于try,finally控制语句的使用

几乎每个脚本语言都有try,catch,finally控制语句。try,catch控制语句主要是对有异常的程序控制,这里不在详细描述。主要讲述下try,finally的妙用。

在正文之前,给出2个已有的两个应用(2篇文章都是在51JS中),如下:

1、try finally 妙用,防止内存泄漏

2、月影发的“某人发给我的邪恶代码”,可以看#16楼 lifesinger的回复。

继续阅读 »