JavaScript常用操作,常用类

算术运算符

重点关注 算数,赋值,逻辑运算符,三目运算符

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>运算符</title>
</head>
<body>
运算符
</body>
<script>
// 算术运算符
// + | - | * | / | % | ++ | --
console.log(5 / 2); // 2.5
// 取整
console.log('%d', 5 / 2); // "2"
var num = parseInt(5 / 2); // 2
console.log(num);

// 取模(求余)
console.log(5 % 2); // 1
// 任何一个自然数对 n 取余, 结果为 [0, n-1]

// 自增|自减 ++|--
// ++就是自增1, --就是自减1
var num = 10
console.log(num++); // 10
console.log(++num); // 12
console.log(num); // 12
// ++在变量后(num++), 先将变量的值拿去使用,再自身自增1
// ++再变量前(++num), 先将变量自身自增1, 再将结果拿去使用
// 总结: 不管++在前在后,运算结束后,变量自身值一定自增1

// res = ++num <==> num++; res = num
// res = num++ <==> res = num; ++num

</script>
<script>
// 赋值运算符
// = | += | -= | *= | /= | %=
var x = 10; // 将10的值赋值给变量x
y = x; // 将变量x的值传递给变量y
console.log(y); // 10

x += 10; // x = x + 10, 运算方式由右至左, 将x+10的结果重新复制给x
console.log(y); // 10, y的值虽然来源于x, 但y值只由自身控制

// x /= 10 == x = x / 10
</script>
<script>
// 比较运算符, 结果为Boolean类型
// == | ===
console.log("5" == 5); // true, 只做值比较
console.log("5" === 5); // false, 比较值及类型

// != | !==
console.log("5" != 5); // false, 只做值比较
console.log("5" !== 5); // true, 比较值及类型

</script>
<script>
// 逻辑运算符, 运算结果通常为Boolean(可以不是)
// 或 | 与 | 非 <==> || | && | !

// &&(与)
var a = 10;
var b = 20;
var c = "20";
var res = a < b && b == c; // true
console.log(res)
// 总结&&: 全真为真, 有假则假
// 总结||: 全假则假, 有真则真
// 总结!: 真则假, 假则真

// 逻辑运算符的结果本质上为表达式值
// 表达式: 由数字,变量,运算符组成的合法式子
res = a < b && c;
console.log(res);

res = (a = 1 || b == c);
console.log(res);

// 针对 && | ||
// 疑问: 逻辑运算符结果可能为逻辑运算符之前表达式的值,也可能是之后表达式的值
// 当逻辑运算符出现 短路现象 , 就是之前表达式的值, 否则(正常情形下), 就是之后表达式的值

// &&, 前一个表达式为假时, 整个式子的结果已经确定为假, 后表达式不会被执行, 就是被短路了
var num = 10;
res = false && num++;
console.log(res, num); // null, 10
res = null && ++num;
console.log(res, num); // null, 10

// ||, 前一个表达式为真时, 整个式子的结果已经确定为真, 后表达式不会被执行, 就是被短路了
res = -10 || ++num;
console.log(res, num); // -10, 10

// 特殊小技巧 => 类似于if分支来使用 ***
/* if a > b:
print(a)
*/
var a = 100;
a > b && console.log("大值a:", a);


</script>
<script>
// 三目运算符
// 语法: 条件表达式 ? 表达式1 : 表达式2
var a = 10, b = 20;
var res = a < b ? a : b; // 取小值
console.log(res);
res = a < b ? b : a; // 取大值
console.log(res);

// 类似于if...esle...
a < b ? console.log("表达式结果为true") : console.log("表达式结果为false")


</script>
<script>
let abc = 10;
// let abc = 20; // 在es6语法下,有变量的重复定义规则, 不允许在同一作用域下,出现变量的重复定义
{
let abc = 20; // 可以编译运行通过
}

// ES6新增
let [a1, b1, c1] = [1, 2, 3];
// a1=1,b2=2,c3=3

let [a2, ...b2] = [1, 2, 3];
// a2=1,b2=[2,3]

let {key: a3} = {key: 10};
// a3=10

let [a4, b4, c4] = 'xyz';
// a4='x',b4='y',c4='z'

console.log("end")
</script>
</html> 

程序的三大结构

程序本质分为三大结构: 顺序结构 | 分支结构 if|switch | 循环结构 for|while|do...while
根据程序代码执行的方式 划分为 三大结构

// 逻辑运算符 => 类似于 if单分支结构
// 三目运算符 => 类似于 if...else分支结构,见上面的代码

分支结构

if 基础语法

if (条件表达式) {
代码块;
}

当条件表达式结果为true,会执行代码块;反之不执行
条件表达式可以为普通表达式
0、undefined、null、""、NaN为假,其他均为真

if (1) {
var a = 10;
let b = 20;
console.log("d:%d只能在块级作用域中访问", b);
}
console.log("a:%d在块级作用域内外都可以访问", a);

if 复杂语法(三元,逻辑运算符,省略大括号,一个小技巧)

一、使用常见的三元操作符
if (foo) bar(); else baz(); ==> foo?bar():baz();
if (!foo) bar(); else baz(); ==> foo?baz():bar();
if (foo) return bar(); else return baz(); ==> return foo?bar():baz();
对于以上使用三元操作符来优化if语句你肯定不会陌生,或许你经常使用它。

二、使用and(&&)和or(||)运算符
if (foo) bar(); ==> foo&&bar();
if (!foo) bar(); ==> foo||bar();
老实说,我并没有这样去写过代码,这种写法我在学习《鸟哥的 Linux 私房菜》时看到过,但我并没想到在js中实现它。

三、省略大括号{}
if (foo) return bar(); else something(); ==> {if(foo)return bar();something()}
这种写法你我都很熟悉,但我建议在代码优化的时候这样做,或者交给UglifyJS帮你去解决。毕竟少一个大括号,代码的可阅读性并不高。
写到这里,我想到jQuery之父在《精通 JavaScript》中的一个获取HTML元素属性的方法。
function getAttr(el, attrName){
var attr = {'for':'htmlFor', 'class':'className'}[attrName] || attrName;
};
如果我们不这样写,可能我们需借助于两个if语句来进行处理,而上面的代码不仅简洁有效,而且可阅读性强。
仔细想想,好些时候我们都能找到解决问题的有效途径,但关键在于我们是否用心去寻找一种更好的途径

【javascript技巧】if(x==null)简写 
if(x==null)或if (typeof (x) == 'undefined')可以简写为if(!x),未验证。
反之if(x)表示x非空 

双分支

if (表达式1) {
代码块1;
} else {
代码块2;
}

多分支

if (表达式1) {
} else if (表达式2) {
}
else if (表达式2) {
} else {
}

if 嵌套

if (表达式1) {
if (表达式2) {
}...
}...

if 与 if直接可以随意嵌套

*/
var salary = prompt("请输入所发工资:");
if (salary > 0) {
console.log("工资已发, 打算还账!");
salary -= 100000;
if (salary > 0 ) {
console.log("拯救世界...");
} else if (salary == 0) {
console.log("家里蹲, 峡谷见");
} else {
console.log("借钱, 填窟窿, 谁来拯救我...");
console.log("借%d元钱", -salary);
}
} else {
console.log("拿我刀来, 允许你跑49m");
}

switch语句

switch (表达式) {
case 值1: 代码块1; break;
case 值2: 代码块2; break;
...
default: 代码块3;
}

 1.表达式可以为 整数表达式 或 字符串表达式
 2.值可以为 整数 或 字符串
 3.break可以省略
 4.default为默认代码块,需要出现在所有case最下方,在所有case均未被匹配时执行
switch()中的表达式结果为 整型 或 字符串, case的值要与其对应

运用实例

例1
var num = prompt("请输入一个自然数: "); // 输入接收的默认为字符串类型数据
var num = +num;
switch (num) {
case "0": console.log("用户输入的是数字0"); break;
case "1": console.log("用户输入的是数字1"); break;
case 0: console.log("change, 用户输入的是数字0"); break;
case 1: console.log("change, 用户输入的是数字1"); break;
default: console.log("用户输入的是数字非0和1");
}

例2
var month = +prompt("请输入月份");
switch (month) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
console.log("%d月天数为31天", month); break;
case 4: case 6: case 9: case 11:
console.log("%d月天数为30天", month); break;
case 2:
console.log("%d月天数为28天", month);
}

循环结构

for循环

for (循环变量①; 条件表达式②; 循环变量增量③) {
代码块④;
}
// 1.循环变量可以在外、在内声明
// 2.执行逻辑 ① ②④③ ... ②④③ ②,入口为①,出口为②,②④③个数为[0, n]

for (var i = 0; i < 5; i++) {
console.log("我最棒, 我最帅, 我是天下第一!");
} 

所有for循环可以解决的问题, 都可以由while来解决
while循环可以解决不明确循环次数的循环需求

while循环

while (条件表达式) {
代码块;
}

var count = 0;
while (count < 5) {
console.log("我最棒, 我最帅, 我是天下第一!");
count++;
}

do...while循环

do {
代码块;
} while (条件表达式);

// 无论条件是否满足, 都需要执行一次循环体 (循环体只是要被执行一次)
var num = 0;
do {
console.log("我最棒, 我最帅, 我是天下第一!");
num++;
} while (num < 5); // 当条件满足时, 返回循环体

for...in循环

obj = {"name": "zero", "age": 8}
for (k in obj) {
console.log(k, obj[k])
}

用于遍历对象:遍历的结果为key,通过[]语法访问对应的value

for...of循环

iter = ['a', 'b', 'c'];
for (i of iter) {
console.log(iter[i])
}

用于遍历可迭代对象:遍历结果为index,通过[]语法访问对应的value
ES6新增,可迭代对象有 字符串、数组、Map、Set、Anguments、NodeList等

break,continue关键词

break:结束本层循环
continue:结束本次循环进入下一次循环

异常处理

try {
易错代码块;
} catch (err) {
异常处理代码块;
} finally {
必须逻辑代码块;
}

err为存储错误信息的变量finally分支在异常出现与否都会被执行

throw "自定义异常"必要的时候抛出自定义异常,要结合对应的try...catch使用

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>异常处理</title>
</head>
<body>
异常处理
</body>
<script>
    // 了解
    let num = 10;
    try {
        console.log(num);  // try...catch捕获的是runtime时的异常
        let num = 20;
    } catch (e) {
        console.log(e)  // catch为处理异常的分支
    } finally {
        console.log('无论是否出现异常,该分支都会被执行')
    }
</script>
<script>
    console.log(num)
</script>
</html>

函数初级

函数的定义

ES5

function 函数名 (参数列表) {
函数体;
}
var 函数名 = function (参数列表) {
函数体;
}

ES6

let 函数名 = (参数列表) => {
函数体;
}

函数相关运用实例

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>函数</title>
</head>
<body>
函数
</body>
<script>
    // 什么函数: 具有特定功能的代码块

    // 函数与方法: 调用方式的不同 函数通过函数名 | 方法通过调用者.语法调用

    // 如何定义函数:
    /*
    function 函数名(参数列表) {
        函数体;
        (函数体可以包含函数的返回值)
    }
    */

    // 函数的调用: 函数名(参数列表)
    //      函数的调用()一定不可以省略, 参数列表看情况(不管需不需要,均可以传或不传)
    // 函数的分类:
    // 无参函数:
    function fn1() {
        console.log("无参函数")
    }
    fn1();
    // 有参函数:
    function fn2(a, b) {
        console.log("a,b的和:", a + b)
    }
    fn2(10, 20);
    // 匿名函数:
    var fn3 = function () {
        // 匿名函数虽然没有名字, 但会开辟内存空间, 所以当然可以用一个变量来指向这个内存空间
        console.log("没有直接定义名字的函数");
    };
    fn3();  // 系统不好在()()之间添加;作为语句结束,需要添加分号时一定需要手动添加
    fn4 = fn3;
    fn4();

    // 匿名函数的自调用
    (function () {
        // 定义一个匿名函数, 至少需要使用一次, 使用一次的方式就叫做 匿名函数的自调用
        // 如果匿名函数不存在任何使用, 编译就无法通过
        // 匿名函数的自调用:
        //      1.将整个匿名函数作为一个整体, 用()将其包裹
        //      2.并完成函数的调用, 添加 (参数列表)
        console.log(" 匿名函数的自调用");
    })();

    // 函数的参数:
    function func1() {
        console.log("无参");
    }
    // 均可以调用
    func1();
    func1(10, 20);

    function func2(a, b) {
        console.log(">>>", a + b);
    }
    func2()
    func2(10)
    func2(10, 20)
    func2(10, 20, 30)

    // 默认值参数
    function func3(a, b=20, c, d=40) {  // 定义在函数声明中的参数为形参
        console.log("***", a + b + c + d);
    }
    var temp = 1000;
    func3(10, 100, temp)  // 函数调用传入的实际值,或拥有实际值的变量为实参

    // 函数的返回值:
    // js的函数只能返回一个值, 这个值可以为任意类型(如果想返回多个值,将多个值放到数组或对象中)
    let func4 = () => {
        // return 1000, 8888, 6666;  // 这种情况返回的是最后一个值
        return [1000, 8888, 6666];
    };
    console.log(func4())

    // 函数的嵌套(定义 | 调用)
</script>

<!-- 一个人写的js -->
<script>
    // 为什么要出现匿名函数的自调用
    (function () {  // 为了生成一个局部作用域
        var num = 10;
    })();

    function abc() {
        var abc = 20;
        console.log(abc)
    }
</script>
<!-- 另一个人写的js -->
<script>
    // console.log(num);
    abc()
</script>

<script>
    // 函数的定义
    (function () {
        // 匿名函数定义并调用
    })()
    
    // ES5
    function fun1() {
        
    }
    var fun2 = function () {

    };
    // ES6
    let fun3 = () => {
        
    }

    // 函数的调用
    // 函数名(参数列表)
</script>
<script>
    // 函数的参数:
    // 1.实参与形参个数可以不匹配,随意规定
    // 2.形参可以设置默认值(并非为py中的关键字参数)
    // 3.实参对形参进行传值时,完全采用位置匹配(eg:第n个实参一定将值传递给第n个形参)
</script>
<script>
    // 函数的返回值:
    // 1.函数的返回值有return来明确,没有明确,则相当于返回undefined
    // 2.函数只能返回一个值
    // 3.函数的返回值就是函数的执行结果,也就是函数值
</script>
</html>

函数闭包

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>闭包</title>
</head>
<body>
闭包
</body>
<script>
    // 了解知识点
    // 闭包: 局部的函数(被一个函数包裹的函数)
    // 为什么使用闭包:
    // 1.一个函数要使用另一个函数的局部变量
    // 2.闭包会持久化包裹自身的函数的局部变量
    // 3.解决循环绑定

    // 函数的嵌套定义
    function outer() {
        var num = 10;
        function inner() {
            // 1.在inner函数中,使用了outer的局部变量num
            return num;
        }
        return inner;
    }
    var innerFn = outer();
    // 2.借助闭包,将局部变量num的生命周期提升了
    var num = innerFn();
    console.log(num);


</script>
</html>

JS常用类

Number

常用数字

整数:10
小数:3.14
科学计数法:1e5 | 1e-5
正负无穷:Infinity | -Infinity

常用进制

二进制:0b1010
八进制:012
十进制:10
十六进制:0xA

NaN

非数字类型,通过isNaN()进行判断 

常用常量

最大值:MAX_VALUE(1.7976931348623157e+308)
最小值:MIN_VALUE(5e-324)
正负无穷:NEGATIVE_INFINITY | POSITIVE_INFINITY(Infinity | -Infinity)

常用实例方法

toExponential(n) => 3.14.toExponential(1) => 1.3e+1 (先科学记数,再确定精度,n为小数精度)
toFixed(n) => 3.14.toFixed(1) => 3.1 (先确定精度,再普通记数,n为小数精度)
toPrecision(n) => 13.14.toPrecision(1|2) => 1e+1|13 (先确定精度,再记数,n为位数进度)
toString() =>

时间

创建并获取时间

var date = new Date();

时间戳

date.getTime();

获取时间

年:date.getFullYear()
月:date.getMonth() + 1
日:date.getDate()
星期:date.getDay()
小时:date.getHours()
分钟:date.getMinutes()
秒:date.getSeconds()
毫秒:date.getMilliseconds()

常见格式时间

getUTCFullYear()
getUTCDate()
getUTCHours()

字符串

常用字符串

'string' | "string" | 'my name is "zero"' | "I'm boy" | "I "love" you"

常用属性

length:字符串长度

常用方法

chartAt(n):指定索引字符,同[n]
concat(str):将目标字符串拼接到指定字符串之后
indexOf(str):指定字符串第一次出现的位置
lastIndexOf(str):指定字符串最一次出现的位置
replace(re, str):将正则匹配到的字符串替换为指定字符串
substr(n, m):从索引n开始,截取m个字符长度(m省略代表截取到最后)
substring(n, m):从索引n开始,截取到索引m(m省略代表截取到最后)
slice(n, m):同substring(n, m)
split(re):以指定正则将字符串拆分为数组
toUpperCase():转换为大写
toLowerCase():转换为小写
trim():去除首尾空白字符

数组

常见数组

[1, 2, 3] | ['1', '2', '3'] | [1, '2', true]

常用属性

length:数组元素个数

常用基础方法

concat(arr):将目标数组拼接到指定数组之后
indexOf(ele):指定元素第一次出现的位置
lastIndexOf(ele):指定元素最一次出现的位置
reverse():反转数组
includes(ele, n):从索引n开始往后,元素ele是否在数组中,做全等匹配,索引从头开始n可以省略(in只做值匹配)
fill(ele):以指定元素填充整个数组
slice(n, m):从索引n开始,截取到索引m(m省略代表截取到最后)
join(str):以指定字符串连接成字符串

增删改方法

push(ele):从尾加
unshift(ele):从头加

pop():从尾删
shift():从头删

splice详细用法

splice(begin, length, ...eles):完成增删改
// begin开始索引
// length操作长度
// 新元素们(可以省略)
splice(begin,length,....eles):完成增删改

newArr.splice(1,2,666,888);//从索引第一位开始 操作两个长度,替换为666 888
从头删除
newArr.splice(0,1);//从索引0开始 操作1长度 替换位省略,则就是删除操作   
从尾删除
newArr.splice(newArr.length-1,1);// 删掉末尾最后一个数
从头添加
newArr.splice(0,0,115);
从尾添加
newArr.splice(newArr.length,0,999);

回调函数方法

filter(function(value, index){ return true | false}):过滤器
every(function(value, index){ return 条件表达式; }):全部满足条件
some(function(value, index){ return 条件表达式; }):部分满足条件
reduce(function(prev,value,index){ return prev * value; }):累积
sort(function(o, n){ return o > n }):正逆向排序

Math

常用常量

E:返回算术常量 e,即自然对数的底数(约等于2.718)
LN2:返回 2 的自然对数(约等于0.693)
LN10:返回 10 的自然对数(约等于2.302)
LOG2E:返回以 2 为底的 e 的对数(约等于 1.4426950408889634)
LOG10E:返回以 10 为底的 e 的对数(约等于0.434)
PI:返回圆周率(约等于3.14159)

常用方法

abs(x):返回 x 的绝对值
ceil(x):向上取整
floor(x):向下取整
max(...n):求最大值
min(...n):求最小值
pow(x,y):返回 x 的 y 次幂
random():返回 0 ~ 1 之间的随机数
round(x):四舍五入

随机数运用实例

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>随机数</title>
</head>
<body>
随机数
</body>
<script>
    var randomNum = Math.random();
    // 随机数的取值范围: [0, 1)
    console.log(randomNum);

    // 要产生[n, m]之间的正整数
    var r1 = parseInt(Math.random() * 11) + 5;  // [5, 15]
    var r2 = parseInt(Math.random() * 21) + 7;  // [7, 27]
    // var r3 = parseInt(Math.random() * (m - n + 1)) + n;  // [n, m]

    function rFn(n, m) {
        return parseInt(Math.random() * (m - n + 1)) + n;
    }
    for (var i = 0; i < 20; i++) {
        console.log(rFn(3, 19))
    }

</script>
</html>

正则

正则对象的创建和声明的两种方法

// 构造函数
var re = new RegExp('^\w', 'igm');
// 字面量
var re = /^w/igm;   i,g,m的意思如下
注:使用“//”来创建正则对象,是推荐的风格。但有的时候在js中使用“//”来创建正则对象时会报错,这个时候就可以作用new来进行创建。

修饰符

i:不区分大小写
g:全文匹配
m:多行匹配

正则方法

test():匹配目标字符串,结果为true|false
exec():匹配目标字符串,结果为第一条结果所有信息的数组

字符串方法

match(re):匹配指定正则,结果为数组(可全文匹配)
search(re):匹配指定正则,结果为匹配的索引,反之-1
replace(re, newStr):匹配指定正则,替换匹配的结果(可全文匹配)
split(re, n):按正则进行拆分,n的值可以决定结果的数组长度(可选参数)

① boolean reg.test(str)

test()用于检查指定的字符串是否存在,如果存在的话就返回true,否则返回false

var reg = /d+/;
var str = “32343”;
alert(reg.test(str));
输出结果:true

② string[] reg.exec(str)
exec()函数返回的是源字符串中与正则表达式相匹配的整个子串和正则中的各个分组相匹配的子串组合在一起的一个数组,即这个数组(group)存放的是匹配组中各个组得到的匹配串,各个元素之间用逗号分隔,比如下面的例子中strArr中存放的是{"John Smith","John","Smith"}。第0个元素是整个串,因为第0个组代表的是整个正则表达式

var reg = /(w+)s(w+)/;
var str  = "John Smith";
var strArr = reg.exec(str);
for(var i=0; i< strArr.length; i++){
       document.write("第"+i+"组:"+ strArr[i]+"<br/>");
}
输出结果:
第0组:John Smith
第1组:John
第2组:Smith

③ string[] str.match(reg)
match()返回匹配得到的数组。在正则表达式后面加个g(golable全局匹配),那么match()函数就能得到将正则表达式每次匹配的结果都放在一个数组里面,最后将这个数组返回。如果在正则表达式最后没有g的话,那么match()这个函数就只能返回第一次匹配得到的结果,然后将其存放在数组里面返回

var reg = /(d)(w+)/g;//如果没有最后的g,则只会得到一次匹配,即第0组
var str  = "1a,213,skk,2_j,ca2t,3dfs,3,Cat,dsfsdfs";
var strArr = str.match(reg);
for(var i=0; i< strArr.length; i++){
       document.write("第"+i+"组:"+ strArr[i]+"<br/>");
}
输出结果:
第0组:1a
第1组:213
第2组:2_j
第3组:2t
第4组:3dfs
注:如果正则为:var reg = /(d)(w+)/;的话,则输出的结果为:第0组:1a

④ int reg.search(str)
search()返回匹配串的位置,从0开始计数的话,就是返回匹配串第一个字符的标号,类似于indexof()

var str = "3,Cat,cat,asfsdfs";
var reg = /aw{3}/;
document.write(str.search(reg));
输出结果:10

⑤ string str.replace(reg,str2);
replace()函数的第一个参数可以是普通字符串,也可以是正则表达式。它将匹配到的子串替换为str2,然后将替换后的结果返回。
如果正则表达式的最后含有g(golable全局匹配)的话,那么它将遍历整个字符串str,将能够匹配的子串全部替换。

var str = "123123,213,12312,312,3,Cat,cat,dsfsdfs";
var reg = /cat/gi;//如果没有g的话,就只会替换第一次匹配的子串
var newstr = str.replace(reg,"#####");
document.write(newstr);
输出结果:123123,213,12312,312,3,#####,#####,dsfsdfs
如果正则表达式为var reg = /cat/i;的话,输出结果为:123123,213,12312,312,3,#####,cat,dsfsdfs

⑥ stting[] str.split(reg)
split()函数的参数可以为普通字符串,也可以为正则表达式。它是将源字符串str以参数reg进行分割,然后将分割后得到的每个子串存放在数组里面返回。

var str = "121#cat###345##mmm";
var reg = /#/;
str = str.replace(/#+/g,"#");
var strArr = str.split(reg);
for(var i=0; i<strArr.length; i++){
       document.write("第"+i+"个:"+strArr[i]+"<br/>");
}
输出结果:
第0个:121
第1个:cat
第2个:345
第3个:mmm

$1...$9 引用(匹配)得到的分组子串,如果它(们)存在的话。注意:是没有$0的,$1是引用第一个分组匹配的子串

var reg = /(w+)s(w+)/;
var str  = "John Smith";
var str = str.replace(reg, "$2,$1");
document.write(str);
输出结果:Smith,John