2015年6月

JavaScript语言核心之对象转换为原始值

对象到布尔值


  对象到布尔值的转换非常简单,所有的对象(包括数组和函数)都转换为true。对于包装对象亦是如此:new Boolean(false)是一个对象而不是原始值,它将转换为true
  

对象到字符串和对象到数字


它们的转换是通过调用待转换对象的一个方法来完成的。一个麻烦的事实是,`Javascript`对象有两个不同的方法来执行转换,并且接下来要讨论的特殊场景更加复杂。值得注意的是,这里提到的字符串和数字的转换规则只是用于本地对象(native object)。宿主随想(例如,有Web浏览器定义的对象)根据各自的算法可以转换成字符串和数字。
所有的对象继承了两个转换方法。

第一个是toString()


  • 它的作用是返回一个反应这个对象的字符串。默认的toString()方法并不会返回一个有趣的值(在例6-4中我们发现它非常有用):
({x:1, y:2}).toString()     // "[object Object]"

很多类定义了更多特定版本的toString()方法。例如,

  • 数组类(Array class)的的toString()方法将每个数组元素转换为一个字符串,并在元素之间添加逗号后合并成结果字符串;
  • 函数类(Function class)的toString()方法返回这个函数的实现定义的表示方式。实际上,这里的实现方式是通常是将用户定义的函数转换为Javascript源代码字符串
  • 日期类(Date class)定义的toString()方法返回了一个可读的(可被JavaScript解析的)的日期和时间字符串;
  • RegExp类(RegExp class)定义的toString()方法将RegExp对象转换为表示正则表达式直接量的字符串:
[1,2,3].toString()                  // => "1,2,3"
(function(x) { f(x); }).toString()  // =>"function(x) {\n f(x);\n}"
/\d+/g.toString()                   // "/\d+/g"
new Date(2010,0,1).toString()       // "Fri Jan 01 2010 00:00:00 GMT-0800 (PST)"

另一个转换对象的函数是valueOf()


  • 这个方法的任务并未详细定义:如果存在任意原始值,它将默认将对象转换为表示它的原始值。
  • 对象是复合值,而且大多数对象无法真正的表示为一个原始值,因此默认的valueOf()方法简单的返回对象本身,而不是返回一个原始值。
  • 数组、函数和正则表达式简单的继承了这个默认方法,调用这些类型的实例valueOf()方法会返回它的一个内部表示:1970年1月1日一来的毫秒数
var d = new Date(2010, 0, 1)    // 2010年1月1日(太平洋时间)
d.valueOf()                     // 1262332800000

通过使用我们刚刚讲解过的toString()valueOf()方法,就可以做到对象到字符串和对象到数字的转换了。但需要注意的是,在某些特殊的场景中,JavaScript执行了完全不同的对象到原始值的转换。这些特殊场景在最后会讲到。

对象到字符串的转换过程


  • 如果对象具有toString()方法,则调用这个方法。如果它返回一个原始值,JavaScript将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串的结果。需要注意的是,原始值到字符串的转换
  • 如果对象没有toString()方法,或者这个方法并不返回一个原始值,那么JavaScript会调用valueOf()方法。如果存在这个方法,则JavaScript调用它。如果返回值是原始值,JavaScript将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串结果。
  • 否则,JavaScript无法从toString()valueOf()获得一个原始值,因此这时它将抛出一个类型错误异常。

对象到数字的转换过程


  • 和转换字符串的过程类似,只是它会首先尝试使用valueOf()方法
  • 如果对象具有valueOf()方法,侯着返回一个原始值,则JavaScript将这个原始值转换为数字(如果需要的话)并返回这个数字
  • 否则,如果对象具有toString()方法,后者返回一个原始值,则JavaScript将其转换并返回
  • 否则,JavaScript抛出一个类型错误的异常。

对象转换为数字的细节解释了为什么空数组会被转换为数字0以及为什么具有单个元素的数组同样会转换成一个数字。数组继承了默认的valueOf()方法,这个方法返回一个对象而不是一个原始值,因此,数组到数字的转换则调用toString()方法。空数组转换成为空字符串,空字符串转换为数字0。含有一个元素的数组转换为字符串的结果和这个元素转换字符串的结果一样。如果数组只包含一个数组元素,这个数字转换为字符串,再转换为数字。

JavaScript中的 "+" 运算符可以进行数学加法和字符串链接操作。如果他的其中一个操作数是对象,则JavaScript将使用特殊的方法将对象转换为原始值,而不是使用其他的算术运算符的方法执行对象到数字的转化, "==" 相等运算符与此类似。如果将对象和一个原始值比较,则转换将会遵守对象到原始值的转换方式进行。

"+""==" 应用的对象到原始值的转换包含日期对象的一种特殊情形。日期类是JavaScript语言核心中唯一的预先定义类型,它定义了有意义的向字符串和数字类型的转换。对于所有非日期的对象来说,对象到原始值的转换基本上是对象到数字的转换(首先调用valueOf()),日期对象则使用对象到字符串的转换模式,然而,这里的转换和上文讲述的完全一致: 通过valueOf()toString()返回的原始值将被直接使用,而不会被强制转换为数字或字符串。

"==" 一样,"<" 运算符以及其他关系运算符也会做对象到原始值的转换,但要除去日期对象的特殊情形: 任何对象都会首先尝试调用valueOf(),然后调用toString()不管得到的原始值是否直接使用,它都不会进一步被转换为数字或字符串。

"+""==""!=" 和关系运算符是唯一执行这种特殊的字符串到原始值的转换方式的运算符。其他运算符到特定类型的转换都很明确,而且对日期对象来讲也没有特殊情况。例如 -(减号)运算符把它的两个操作数都转换为数字。下面的代码展示了日期对象和 "+""-""==" 以及 ">" 的运算结果:

var now = new Date();       // 创建一个日期对象
typeof (now + 1)            // => "string": "+"将日期转换为字符串
typeof (now - 1)            // => "number": "-"使用对象到数字的转换
now == now.toString()       // => true: 隐式的和显式的字符串转换
now > (now - 1)             // => true: ">"将日期转换为数字

全文主要摘自《JavaScript权威指南》第3.8.3节

PHP的DES加密和RSA签名(兼容java)

主要用于php对接java的接口
rsa签名用SHA1WithRSA算法

<?php
/**
 * DES加密/解密,RSA加密/验签
 * @author jiangwei<jw90098@gmail.com>
 * @version $Id: Crypt.class.php  $
 */

class Crypt
{

    // DES加密
    public function encrypt($str, $key)  {  
        $block = mcrypt_get_block_size('des', 'ecb');  
        $pad = $block - (strlen($str) % $block);  
        $str .= str_repeat(chr($pad), $pad);  
        $str = mcrypt_encrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);  
        return base64_encode($str);  
    }  

    // DES解密
    public function decrypt($str, $key) {  
        $str = base64_decode($str);  
        $str = mcrypt_decrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);  
        $block = mcrypt_get_block_size('des', 'ecb');  
        $pad = ord($str[($len = strlen($str)) - 1]);  
        return substr($str, 0, strlen($str) - $pad);  
    }  


    // RSA签名(SHA1WithRSA算法)
    public function sign($content, $rsaPrivateKeyPem) {
            $priKey = file_get_contents($rsaPrivateKeyPem);
            $res = openssl_get_privatekey($priKey);
            openssl_sign($content, $sign, $res);
            openssl_free_key($res);
            $sign = base64_encode($sign);
            return $sign;
     }

     // RSA验签
     public function verify($data, $sign, $publicRsaPath)  {
        //读取公钥文件
        $pubKey = file_get_contents($publicRsaPath);
        //转换为openssl格式密钥
        $res = openssl_get_publickey($pubKey);
        //调用openssl内置方法验签,返回bool值
        $result = (bool)openssl_verify($data, base64_decode($sign), $res);
        //释放资源
        openssl_free_key($res);
        //返回资源是否成功
        return $result;
    }
}

php7 废除了 mcrypt_encrypt, 改用 openssl_encrypt

class DES{
    public static function encrypt($str,$key){
        $str = self::pkcs5_pad($str, 8);
        if (strlen($str) % 8) {
            $str = str_pad($str,
                strlen($str) + 8 - strlen($str) % 8, "\0");
        }
        $sign = openssl_encrypt (
            $str,
            'DES-EDE3' ,
            $key,
            OPENSSL_RAW_DATA | OPENSSL_NO_PADDING ,
            ''
        );

        return strtoupper(bin2hex($sign));
    }

    private static function pkcs5_pad($text, $blocksize) {
        $pad = $blocksize - (strlen($text) % $blocksize);
        return $text . str_repeat(chr($pad), $pad);
    }
}

对比示例 java php