数据类型
基本数据类型
- 表示空:Undefined,Null
- 基础三大件:Number,String,Boolean
- 两个新类型:Symbol,BigInt(用来表示大于 253 - 1 的整数)
常见引用类型
- 普通对象 Object
- 数组对象 Array
- 正则对象 RegExp
- 函数 Function
Js包装类型
什么是包装类型
在 JavaScript 中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript 会在后台隐式地将基本类型的值转换为对象,如:
const a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"
包装类型与基本类型的类型转换
基本类型转包装类型
- 使用Object函数显示转换
var a = 'abc'
Object(a) // String {"abc"}
包装类型转基本类型
- 使用valueOf方法将包装类型倒转成基本类型
var a = 'abc'
var b = Object(a)
var c = b.valueOf() // 'abc'
类型转换
JavaScript 的类型转换的结果总是得到string、number和boolean类型的一种
显式类型转换
string 转 number
- Number(string)
-
- parseInt,parseFloat
const a = 18
// 注意不需要加new 否则含义变成了创建实例
const b = String(18) // '18'
const c = Number(b) // 18
const a = '18'
const b = +a //18
const a = '18px'
const b = parseInt(a) // 18
// Number不允许传入非数字字符
const c = Number(a) // NaN
// 对于+操作符,还有一个特殊的作用,可以将日期对象转换为number
var date = new Date( "Mon, 1 Mar 2020 08:53:06" )
+date // 1583013186000
number 转 string
- String(number)
- toString()
const a = 18
const b = String(18) // '18'
const a = 18
const b = a.toString() // '18'
任意值转换成boolean
- Boolean(any)
- !!
const a = '123'
const b = undefined
const c = 0
Boolean(a) // true
Boolean(b) // false
Boolean(c) // false
!!a // true
!!b // false
!!c // false
隐式类型转换
ToPrimitive
ToPrimitive是 JavaScript 中每个值隐含的自带的方法,用来将值 (无论是基本类型值还是对象)转换为基本类型值。如果值为基本类型,则直接返回值本身;如果值为对象
/**
* @obj 需要转换的对象
* @type 期望的结果类型,type的值为number或者string
*/
ToPrimitive(obj,type)
- 当type为number时规则如下:
- 调用obj的valueOf方法,如果为原始值,则返回,否则下一步;
- 调用obj的toString方法,后续同上;
- 抛出TypeError 异常。
- 当type为string时规则如下:
- 调用obj的toString方法,如果为原始值,则返回,否则下一步;
- 调用obj的valueOf方法,后续同上;
- 抛出TypeError 异常
可以看出两者的主要区别在于调用toString和valueOf的先后顺序。默认情况下:
- 如果对象为 Date 对象,则type默认为string;
- 其他情况下,type默认为number。
总结上面的规则,对于 Date 以外的对象,转换为基本类型的大概规则可以概括为一个函数:
- var objToNumber = value => Number(value.valueOf().toString())
- objToNumber([]) === 0
- objToNumber({}) === NaN
使用操作符的转换
严格上来讲,使用+、-、*、/以及==、>、<其实是一种隐式转换,因为这些操作符只能操作基本数据类型,所以在进行这些运算前的第一步就是将两边的值用ToPrimitive转换成基本类型,再进行操作,以下以对象为例进行说明
- 案例一
var a = {}
a > 2 // false
其对比过程如下
a.valueOf() // {}, 上面提到过,ToPrimitive默认type为number,所以先valueOf,结果还是个对象,下一步
a.toString() // "[object Object]",现在是一个字符串了
Number(a.toString()) // NaN,根据上面 < 和 > 操作符的规则,要转换成数字
NaN > 2 //false,得出比较结果
- 案例二
var a = {name:'Jack'}
var b = {age: 18}
a + b // "[object Object][object Object]"
运算过程如下
a.valueOf() // {},上面提到过,ToPrimitive默认type为number,所以先valueOf,结果还是个对象,下一步
a.toString() // "[object Object]"
b.valueOf() // 同理
b.toString() // "[object Object]"
a + b // "[object Object][object Object]"
判断一个数据的类型
typeof
- typeof 可以检测出 number、string、boolean、undefined 和 function 的类型,但是当被检测的值为数组、对象或者 null 类型时,结果均为 object,无法准确判断它们的类型
- 使用typeof判断null的方法
var a = null;
(!a && typeof a === "object"); // true
instanceof
- instanceof 可用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性,返回boolean类型的值,instanceof有以下两个限制
- 不能检测字面声明的基本变量的类型,如:
instanceof Number === false
- 由于 instanceof 会遍历原型链,所以只要是在原型链上的构造函数都会返回 true
- 不能检测字面声明的基本变量的类型,如:
isArray
- isArray 用于检测检测是否是数组:Array.isArray
Object.prototype.toString.call
- 在任何值上调用Object.prototype.toString方法,都会返回一个 [object NativeConstructorName]格式的字符串。每个类在内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的构造函数名
- 使用Object.prototype.toString.call,目前这是最为可靠的检测类型的方法
// JavaScript 中并没有Null()和Undefined构造器,此处为其内部的特殊处理
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
// 注意对基本类型而言,是没有构造函数的,此处之所以能进行判断,是因为发生了隐式类型转换,经基本数据类型转换为了包装类型
Object.prototype.toString.call(“abc”);// "[object String]"
Object.prototype.toString.call(123);// "[object Number]"
Object.prototype.toString.call(true);// "[object Boolean]"
// 函数类型
function fn(){}
Object.prototype.toString.call(fn); // "[object Function]"
// 数组类型
var arr = [1,2,3];
Object.prototype.toString.call(arr); // "[object Array]"
检测对象是否拥有属性
- '属性名' in 对象
console.log('name' in cat); // false or true
数据遍历
- 对象属性的遍历:for-in
- for-in只遍历可枚举属性,包括原型链上的可枚举属性
- for-in会以任意顺序遍历对象的可枚举属性
- for-in用于遍历数组时,得到的是数组的下标,如果数组中存在键值对,则得到的是键值对的键
for (var p in cat) {
console.log(p); // 输出属性的名称
console.log(cat[p]); // 访问对应的属性的值
}
// 遍历数组
let iterable = [3, 5, 7];
iterable.foo = 'hello';
for(let o in iterable){
console.log(o, iterable[o]);
}
// 输出结果为:
0, 3
1, 5
2, 7
foo, hello
- 数组value的遍历:for-of
- for-of会在可迭代对象上(包括:Array,Map,Set,String,TypedArray,arguments对象等等)上创建一个迭代循环,调用自定义的迭代钩子([Symbol.iterator])
- for-of不可以遍历普通对象
- for-of遍历可迭代对象定义要迭代的数据,其准守的是可迭代协议,此类型的对象都具有一个[Symbol.iterat]属性,其值为一个函数
let iterable = [3, 5, 7];
iterable.foo = 'hello';
for (let i of iterable) {
console.log(i); // 3, 5, 7
}
json字符串与javascript对象的转换
JSON.parse()
- 用于将一个 JSON 字符串转换为 JavaScript 对象
- 参数
- text:必需,一个有效的 JSON 字符串
- reviver: 可选,一个转换结果的函数,将为对象的每个成员调用此函数
- 使用示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h2>使用可选参数,回调函数</h2>
<p id="demo"></p>
<script>
var obj1 = JSON.parse('{"p": 5}', function(k, v) {
if (k === '') { return v; }
return v * 2;
});
console.log(obj1);
// 运行结果:
// 控制台输出:{p: 10}
JSON.parse('{"1": 1, "2": 2, "3": {"4": 4, "5": {"6": 6}}}', function(k, v) {
document.write( k );// 输出当前属性,最后一个为 ""
document.write("<br>");
return v; // 返回修改的值
});
// 运行结果:
// 页面展示:1 2 4 6 5 3
// 控制台输出:{1: 1, 2: 2, 3: {4: 4, 5: {6: 6}}}
</script>
</body>
</html>
JSON.stringify()
- 用于将 JavaScript 值(通常为对象或数组)转换为 JSON 字符串
- 参数
- value:必需,要转换的 JavaScript 值(通常为对象或数组)
- replacer:可选,用于转换结果的函数或数组
- 如果 replacer 为函数,则 JSON.stringify 将调用该函数,并传入每个成员的键和值。最终转换结果使用返回值而不是原始值。如果此函数返回 undefined,则排除成员。根对象的键是一个空字符串:""
- 如果 replacer 是一个数组,则仅转换该数组中具有键值的成员。成员的转换顺序与键在数组中的顺序一样
- space:可选,文本添加缩进、空格和换行符,如果 space 是一个数字,则返回值文本在每个级别缩进指定数目的空格,如果 space 大于 10,则文本缩进 10 个空格。space 也可以使用非数字,如:\t
- 使用示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<p id="demo"></p>
<script>
var str = {"name":"菜鸟教程", "site":"http://www.runoob.com"}
var str_pretty2 = JSON.stringify(str, null, 4) //使用四个空格缩进
document.write( "使用参数情况:" );
document.write( "<br>" );
document.write("<pre>" + str_pretty2 + "</pre>" ); // pre 用于格式化输出
// 运行结果:
// 使用参数情况:
// {
// "name": "菜鸟教程",
// "site": "http://www.runoob.com"
// }
</script>
</body>
</html>
Js事件监听
监听事件的两种方式
- 注册监听器
语法:
element.addEventListener(event, function, useCapture)
参数
- event:事件名字符串,不要使用 "on" 前缀
- function:事件触发时执行的函数
- useCapture:事件是否在捕获或冒泡阶段执行,可选值:true(事件句柄在捕获阶段执行)/false(默认,事件句柄在冒泡阶段执行)
- 绑定事件
语法:element.onXXX = function()
- 二者区别
使用addEventListener可以在一个事件上注册多个监听器,且不会发生覆盖,而使用onXXX的方式定义在后面的事件回调方法会覆盖前面的回调方法,最终只有一个会被执行
- 注意
在ie浏览器中,需要使用attachEvent代替addEventListener
补充内容(事件响应顺序)
- mousedown -> focus > mouseup > click
- 参考内容
js操作dom自定义属性
获取自定义属性值
- var value = domObj.dataset.attrName;
- var value = domObj.getAttribute("data-attr-name");
- 注意
- 可直接使用domObj.dataset获取dataset数据集,dataset拥有数组的部分特性,但不是数组,不能用forEach方式遍历
var dom = document.getElementById("myDiv");
var dataset = dom.dataset;
var str = "";
for (var item in dataset) {
str += item + " ";
}
var name = dom.dataset.name;
var name1 = dom.getAttribute("data-name");
设置自定义属性值
- domObj.dataset.attrName = value;
- dom.setAttribute("data-attrName", value");
- 注意
- 使用domObj.dataset设置自定义属性时,驼峰命名的属性将会被转换为以'-'分割的属性名
- 基于以上原因,如果使用domObj.dataset设置自定义属性,但使用domObj.getAttribute()获取自定义属性值时,需要将自定义属性名转换为"-"形式的属性名来获取,而直接使用domObj.dataset获取时不需要进行转换
- 使用domObj.setAttribute设置自定义属性时,data后面的部分会被全部转换为小写字符,在使用domObj.getAttribute获取值时,使用大写和小写的形式均可获取到值
var dom = document.getElementById("myDiv");
dom.dataset.age = 13;
dom.setAttribute("data-name", "tom");
jquery获取自定义属性值
- var value = $dom.data("attr-name");
- var value = $dom.attr("data-attr-name");
jquery设置自定义属性值
- $dom.data("attr-name", value);
- $dom.attr("attr-name", value);
- 注意
- 在使用$.data()方法设置dom结点中本身不具有的属性时,设置后并不会直接在dom上体现,而是jquery直接将属性和值进行了缓存
- 在使用$.data()方法设置和获取自定义属性的值时,使用驼峰命名和使用"-"命名都可以混用,但大小写敏感
- 在jquery1.6后引入了$.prop()的相关方法,该方法主要用于设置checked,selected等值为true/false相关的特性
判断dom节点的包含关系
- node.contains(otherNode)
- 用于判断是否包含otherNode节点
- 判断otherNode是否是node的后代节点
- 如果otherNode是node的后代节点或者是node节点本身,则返回true,否则返回false
setTimeout
参数和返回值
- 参数
- 必需。要调用一个代码串,也可以是一个函数
- 可选。执行或调用 code/function 需要等待的时间,以毫秒计。默认为 0
- 可选。 传给执行函数的其他参数(IE9 及其更早版本不支持该参数)
- 返回值
- 返回一个 ID(数字),可以将这个ID传递给 clearTimeout() 来取消执行
setTimeout(code, milliseconds, param1, param2, ...)
setTimeout(function, milliseconds, param1, param2, ...)
错误用法
function showName() {
console.log("my name is 猪小明")
}
// 使用以下写法时,showName方法将会立即调用
setTimeout(showName(), 1000)
// 第一个参数必须是一个代码串或者是一个函数,因此可以使用以下三种写法
// 传入一个函数,以下两种写法效果相同
setTimeout(showName, 1000)
setTimeout(function () {
showName()
}, 1000)
// 传入一个代码串
setTimeout('showName()', 1000)
设置延迟执行时间为0
- 问题引出
var fuc = [1,2,3];
for(var i in fuc){
setTimeout(function(){console.log('定时器输出结果', fuc[i])},0);
console.log(fuc[i]);
}
// 代码输出结果
// 1
// 2
// 3
// 定时器输出结果 3
// 定时器输出结果 3
// 定时器输出结果 3
- 原因分析
这是事件循环机制,因为js是单线程的,是基于事件循环的。而setTimeout函数是异步的,异步的事件会加入一个队列,会等到当前同步的任务执行完毕后,再执行setTimeout队列的任务。所以,通过设置任务在延迟0毫秒后执行,事件本身并没有延迟,但是能改变任务执行的先后顺序,改变它所调用的函数的优先级,使之异步执行
- 可能会遇到的问题及处理方法
<input type="text" name="" onkeydown="changeFunc(this)">
<div id="showBox"></div>
<script type="text/javascript">
function changeFunc (event) {
document.getElementById("showBox").innerHTML = event.value
}
</script>
// 在以上方法中,input中的最后一个字符无法在div中显示,可使用以下方式修订
// 方式一:将写入div标签的操作放在定时任务中进行
setTimeout(function() {document.getElementById("showBox").innerHTML = event.value})
// 方式二:将keydown改为keyup,这种改法与setTimeout内容无法,此处不再介绍
js关键词
delete
- 只能删除属性,不能删除方法和原型链上的属性,也不能删除变量
function fun() {
this.name = "zhangsan";
this.say = function() {
alert(this.name);
}
}
var obj = new fun();
alert(obj.name); // 张三
delete obj.name;
alert(obj.name); // undefined
this
- 参考文档
- javascript中this关键字指向的是它所属的对象
- this所属的对象由其使用的位置决定
- 在方法中,this指向的是它所有者对象
- 单独使用的情况下,this指向的是全局对象
- 在函数中,非严格模式下,this指向的是全局对象,严格模式下是undefined
- 在事件中,this指向的是接收事件的元素
- 构造函数中,this直接指向new之后返回的对象
- window.setTimeout()和window.setInterval()默认的是this是window对象
- 使用call,apply,bind方法可以将this引用到任何对象
注意:上述的方法和函数的区别是,方法是指某一特定对象的函数,示例代码如下:
// 在函数内部定义属性
function test() {
this.x = 1;
alert(this.x);
}
// 此方法直接调用和使用new 调用时this的效果是不一样的
// 直接调用时,this.x相当于全局变量,即this代表window,其效果与在函
// 数外通过var声明一个名为x的变量,然后再函数内部改变x的值效果一样
test();
var t = new test();
// 此时this指向当前调用的对象,即t
alert(t.x);
new
// 使用new关键字调用函数时内部的执行步骤
// 1,创建一个空对象
// 2,把构造函数的prototype属性,作为空对象的原型
// 3,this赋值为这个空对象
// 4,执行函数
// 5,如果函数没有返回值,则返回this(返回之前的那个空对象)
super
// 1,作为父类构造函数调用
// 2,作为对象的方式调用
// 2.1,非静态方法中访问super->父类原型
// 2.2,静态方法中,访问super -> 父类
// 注意:
// 1,使用super调用父类时,父类中的的this,始终是子类的this
Object.defineProperty()
描述
- Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象,该方法允许精确地添加或修改对象的属性
Object.defineProperty(obj, prop, descriptor)
// obj 要定义属性的对象
// prop 要定义或修改的属性的名称或 Symbol
// descriptor 要定义或修改的属性描述符
// 返回值 被传递给函数的对象
属性描述符
- 数据描述符,是一个具有值的属性,该值可以是可写的,也可以是不可写的
- 存取描述符,是由 getter 函数和 setter 函数所描述的属性
- 一个描述符只能是这两者其中之一;不能同时是两者
- 如果一个描述符不具有 value、writable、get 和 set 中的任意一个键,那么它将被认为是一个数据描述符
- 如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常
属性描述符键值
- 共享描述符
- configurable,默认值为false,当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变(包括被重新定义),同时该属性也能从对应的对象上被删除
- enumerable,默认值为false,当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中(属性会被for...in 或 Object.keys 方法枚举到)
- 数据描述符特有键值
- value,默认为 undefined,表示该属性对应的值,可以是任何有效的 JavaScript 值(数值,对象,函数等)
- writable,默认为 false,当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变
- 存取描述符特有属性
- get,默认为 undefined,属性的 getter 函数,当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象),该函数的返回值会被用作属性的值
- set,默认为 undefined,属性的 setter 函数,当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象
var o = {};
o.a = 1;
// 等同于:
Object.defineProperty(o, "a", {
value: 1,
writable: true,
configurable: true,
enumerable: true
});
// 另一方面,
Object.defineProperty(o, "a", { value : 1 });
// 等同于:
Object.defineProperty(o, "a", {
value: 1,
writable: false,
configurable: false,
enumerable: false
});
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this, 'temperature', {
get: function() {
console.log('get!');
return temperature;
},
set: function(value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function() { return archive; };
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]
注意:在 get 和 set 方法内部,this 指向被访问和修改属性的对象
function myclass() {
}
Object.defineProperty(myclass.prototype, "x", {
get() {
return this.stored_x;
},
set(x) {
this.stored_x = x;
}
});
var a = new myclass();
var b = new myclass();
a.x = 1;
console.log(b.x); // undefined
扩展延申
- 相关联的方法
- Object.seal(obj):封闭一个对象,返回值为与传入的参数相同的对象,阻止添加新属性并将所有现有属性标记为不可配置,当前属性的值只要原来是可写的就可以改变
- Object.freeze(obj):冻结一个对象,返回值为与传入的参数相同的对象,一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改
- Object.seal(obj)与Object.freeze(obj)都是对对象的浅操作,当对象的属性也是一个对象时,则属性对应的对象不受封闭和冻结的影响
- Object.seal(obj)与Object.freeze(obj)区别:使用Object.freeze()冻结的对象中的现有属性值是不可变的。用Object.seal()密封的对象可以改变其现有属性值
正则表达式
常用元数据
- \b 代表边界
- \B 代表非边界
- \d 代表整数
- \D 代表非整数
- \w 代表单词字符,等价于[A-Za-z0-9_]
- \W 代表非单词字符
- \s 代表空白字符
- \S 代表非空白字符
- ^n 代表任何开头为 n 的字符串
- n$ 代表任何结尾为 n 的字符串
常用限定符(常用量词)
- *:出现零次或多次
- ?:出现一次或零次
- +:出现一次或多次
- :出现n次
- {n,}:至少出现n次
- {n,m}:出现n次至m次
正则匹配模式
- 贪心模式:正则表达式匹配时,默认采用贪心模式,即尽量多地匹配字符串
- 非贪心模式:在量词后面加上一个?字符即表示非贪心模式,也就是说?跟在字符后面就是量词,跟在量词后面就是开启非贪心模式
相同字符的不同含义
- ?
- 在字符后面表示量词
- 在量词后面表示非贪心模式
- ^
- 在正则表达式开头时,表示匹配字符串开始的位置,如:/^23/
- 当其出现在字符组开头时,表示非 (排除),如:/[^123]/
常用方法
RegExp.prototype.test()
test是JavaScript中正则表达式对象的一个方法,用来检测正则表达式对象与传入的字符串是否匹配,若匹配返回true,若不匹配返回false,由于test方法的返回值只是一个boolean值,所以括号在test方法中唯一的作用就是分组
/123{2}/.test('123123') // false
/(123){2}/.test('123123') // true
String.prototype.match()
match方法是字符串的方法,传入参数为正则表达式,返回字符串匹配正则表达式的结果。括号在match方法中有两个作用
- 分组
- 捕获,捕获的意思是将用户指定的匹配到的子字符串暂存并返回给用户
当传入的正则表达式没有使用g标志时,其返回一个数组,数组第一个值为第一个完整匹配,后续的值分别为括号捕获的所有值,且此数组含有以下三个属性
- groups,命名捕获组
- index,匹配结果的开始下标
- input,传入的原始字符串
const result1 = '123123'.match(/123{2}/) // null
const result2 = '123123'.match(/(123){2}/) // ["123123", "123", index: 0, input: "123123", groups: undefined]
console.log(result2.index) // 0
console.log(result2.input) // 123123
console.log(result2.groups) // undefined
对比这两个匹配返回的结果,可以证明括号起到了分组的作用。再看第二句,返回数组的第一个值为正则匹配到的第一个子字符串,第二个值为括号捕获的值。
虽然第二句用括号引用了捕获组,但是result2.groups的值依然为undefined,这是因为第二句中的捕获组为匿名捕获组,而result2.groups只返回命名捕获组的值,命名捕获组的用法是:(?<name>...)
const result = 'a123a123'.match(/a(?<first>\d)(?<second>\d)/) // ["a12", "1", "2", index: 0, input: "a123a123", groups: {…}]
console.log(result.index) // 0
console.log(result.input) // a123a123
console.log(result.groups) // {first: "1", second: "2"}
在match方法中,当传入的正则表达式有 g 标志时,将返回所有与正则表达式匹配的结果,忽略捕获,如:
const result = 'a123a123'.match(/a(?<first>\d)(?<second>\d)/g) // ["a12", "a12"]
RegExp.prototype.exec
exec方法是正则表达式的方法,传入参数为字符串,返回字符串匹配正则表达式的结果。当正则表达式没有g标志时,其返回值与String.prototype.match()没有g标志时返回的结果一样:
'123123'.match(/(123){2}/) // ["123123", "123", index: 0, input: "123123", groups: undefined]
/(123){2}/.exec('123123') // ["123123", "123", index: 0, input: "123123", groups: undefined]
当正则表达式有 g 标志时,可以多次执行 exec 方法来查找同一个字符串中的成功匹配。如:
var html = "123123";
var tag = /(12)3/g
var match, arr = []
do {
if (match) arr.push(match)
match = tag.exec(html)
} while (match)
console.log(arr[0]) // ["123", "12", index: 0, input: "123123", groups: undefined]
console.log(arr[1]) // ["123", "12", index: 3, input: "123123", groups: undefined]
console.log(arr[2]) // undefined
使用场景总结
- 当只是想检测字符串和正则表达式是否匹配时,使用test方法
- 当不仅想检测两者是否匹配,还想知道是哪些子字符串匹配,或者想要在非global模式下捕获子字符串时,用match方法
- 当既想在global模式下匹配字符串,又想捕获子字符串时,就是用exec方法
经典案例
正则表达式中的引用
使用正则表达式支持以下三种格式的日期
2016-06-12
2016/06/12
2016.06.12
答案
/\d{4}(-|\/|\.)\d{2}\1\d{2}/
// 注意答案中使用到了反向引用,第一个分隔符用括号括住来进行捕获,然后答案中d{2}和d{2}之间的\1,代表之前匹配到的第一个字符,这样就实现了两个字符统一的效果
注意:/\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/
是错误答案,因为/\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/.test("2016-06/12")
结果也会返回true
写一个函数,将驼峰字符串转换成-分割字符串
function conversion(str) {
return str.replace(/([A-Z])/g, '-$1').toLowerCase()
}
// $1类似于前面提到的\1,代表了前面捕获到的值
给数字加上千分位分隔符
- 使用toLocaleString方法
const num = 1234567
num.toLocaleString() // 1,234,567
- 使用正则表达式
‘1234567’.replace(/(?=(\B\d{3})+$)/g, ‘,’) // 1,234,567
// ?= 表示断言,匹配任何其后紧接指定字符串 n 的字符串
// \B 表示排除字符串的开头
escape,encodeURI和encodeURIComponent
escape
- escape方法已经被废弃,其作用是对字符串(string)进行编码
encodeURI
- encodeURI用来处理整个 URI,它不会对下列字符编码ASCII字母 数字 ~!@#$&*()=:/,;?+'(完整URI必备字符)
encodeURI("http://www.cnblogs.com/season-huang/some other thing");
// http://www.cnblogs.com/season-huang/some%20other%20thing
encodeURIComponent
- encodeURIComponent通常只用它来转义URI的参数,它不会对下列字符编码ASCII字母 数字 ~!*()'
encodeURIComponent("http://www.cnblogs.com/season-huang/some other thing");
// http%3A%2F%2Fwww.cnblogs.com%2Fseason-huang%2Fsome%20other%20thing