express
- cnpm install express --save
- cnpm install nodemon --save ----------------------- 更改js后,无需重新node......
const express = require('express');
const app = express();
// 静态资源
// http://localhost:3000/public/1.html能访问到静态资源
app.use('/public', express.static('./public/'));
// 路由
app.get(function (req, res, next) { // 不写第一个参数路径时,相当于'/'
console.log('1');
next();
res.send('ni hao');
});
app.get('/', function(req, res, next){ // next可以继续往下匹配
console.log('1');
next();
res.send('ni hao');
});
app.get('/', function(rea,res){
console.log('2')
})
app.get('/teacher/:id', function(req,res){
res.send('teacher: ' + req.params.id + '没有next时,get方法,该路由匹配后,下面的路由就不会再匹配');
});
app.use('/teacher', function(req,res){
res.send('app.use能匹配/teacher/下的子文件夹,而app.get post ...等不能')
})
app.use('/admin', function (req, res, next) {
// GET 'http://www.example.com/admin/new'
console.log(req.originalUrl); // '/admin/new'
console.log(req.baseUrl); // '/admin'
console.log(req.path); // '/new'
next();
});
app.get(/^\/student\/(\d{9,9})$/, function(req,res) { //可以使用正则
res.send('student:' + req.params[0]);
})
app.use(function(req,res){ // 都不匹配,就是404页面
res.send('404')
})
app.listen(3000);
(一) JSONP
(1) 同源
所谓同源指的是三个相同
- 协议
- 域名
- 端口 --------------( http默认端口80,https默认端口443 )
(2) 如果是非同源,受到的限制的三种行为?
- 无法读取非同源网页的 Cookie,LocalStorage,IndexDB
- 无法接触非同源网页的 DOM
- 无法向非同源地址发送 AJAX 请求 ( 可以发送,当浏览器会决绝接受响应 )
(3) jsonp -- ( JSON with Padding )
- JSONP(JSON with Padding)是数据格式JSON的一种“使用模式”
- 凡是拥有 ”src” 这个属性的标签都拥有跨域的能力,如
<script>、<img>、<iframe>
- jsonp只能发送get请求
- 原理:
jsonp协议的一个要点就是允许用户传递一个callback 参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数 据了。 - script标签的src属性格式:
script标签的src属性格式
例如:
http://freegeoip.net/json/?callback=foo
- 服务端返回一个函数,包裹住json:
JSONP看起来与JSON差不多,只不过是被包含在函数调用中的JSON
服务端返回一个函数,包裹住json
例如:
foo({ “name”: “Nicholas” });
注意:
这里的foo要和script中的src中的http://freegeoip.net/json/?callback=foo中的foo保持一致
- 客户端完整请求
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script>
// 动态插入 script 标签到 html 中
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.setAttribute('src', src);
document.getElementsByTagName('head')[0].appendChild(script);
}
// 获取 jsonp 文件
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
// 执行本地的 js 逻辑,这个要跟获取到的 jsonp 文件的函数要一致
function foo(data) {
console.log('Your public IP address is: ' + data.ip);
};
</script>
</head>
<body>
</body>
</html>
https://segmentfault.com/a/1190000012967320
(二) Element对象
Element对象对应的是网页的HTML元素,每一个html元素在DOM树上会转化成Element节点对象
- 元素节点的 ( nodeType ) 属性都是 ( 1 )
- Element.id ---------------------- 获取元素节点的id属性 (getElementById,getAttribute() 等)
- Element.tagname ------------- 获取元素的大写标签名 (nodeName等)
- Element.draggable ----------- 元素节点是否可以被拖动,返回boolean,可读写
- Element.lang ------------------- 返回当前元素的语言设置。该属性可读写。
- Element.title -------------------- 用来读写当前元素的 HTML 属性title。该属性通常用来指定,鼠标悬浮时弹出的文字提示框。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript">
window.onload = function() {
var x = document.querySelector('p'); ---------------------- 获取p元素节点
var xx = document.getElementById('p'); -------------------- 获取p元素节点
console.log(x,xx);
var y = x.id; -------------------------------------------- 获取id属性节点的属性值
var yy = x.getAttribute('id'); ---------------------------- 获取id属性节点的属性值
console.log(y, yy)
var z = x.tagName; ---------------------------- 获取元素节点的标签名
var zz = x.nodeName; -------------------------- 获取元素节点的标签名
console.log(z,zz)
x.draggable = false; -------------------------- 元素节点是否可拖动
x.lang="zh-cn"; ------------------------------- 返回当前元素的语言设置。该属性可读写。
x.title = "hover时,element.title作为提示内容,pc上有效"; ----- hover时提示文字,pc有效
}
</script>
</head>
<body>
<p id="p">p元素节点</p>
</body>
</html>
- Element.attributes ------------ 返回一个类似数组的对象,成员是当前元素节点的所有属性节点
- className属性 --------------- 用来读写当前元素节点的class属性。它的值是一个字符串,每个class之间用空格分割。
- classList属性------------------- 返回一个类似数组的对象,当前元素节点的每个class就是这个对象的一个成员。
// HTML 代码 <div class="one two three" id="myDiv"></div>
var div = document.getElementById('myDiv');
div.className --------------------------- element.className返回class属性值 组成的字符串
// "one two three"
div.classList --------------------------- class属性值组成的类数组对象
// {
// 0: "one"
// 1: "two"
// 2: "three"
// length: 3
// }
- classList对象有下列方法:
add():增加一个 class。
remove():移除一个 class。
contains():检查当前元素是否包含某个 class。
toggle():将某个 class 移入或移出当前元素。
item():返回指定索引位置的 class。
toString():将 class 的列表转为字符串。
-------------------------
var div = document.getElementById('myDiv');
div.classList.add('myCssClass');
div.classList.add('foo', 'bar');
div.classList.remove('myCssClass');
div.classList.toggle('myCssClass'); // 如果 myCssClass 不存在就加入,否则移除
div.classList.contains('myCssClass'); // 返回 true 或者 false
div.classList.item(0); // 返回第一个 Class
div.classList.toString();
Element.innerHTML ---------- 所有子节点
- Element.innerHTML属性返回一个 ( 字符串 ) ,等同于该元素包含的所有 HTML 代码。
- 该属性可读写,常用来设置某个节点的内容。
- 它能改写所有元素节点的内容,包括<HTML>和<body>元素。
- 如果将innerHTML属性设为空,等于删除所有它包含的所有节点。
- 注意:
读取属性值的时候,如果文本节点包含&、小于号(<)和大于号(>),innerHTML属性会将它们转为实体形式&、<、>
- 如果想得到原文,建议使用element.textContent属性。
- 写入的时候,如果插入的文本包含 HTML 标签,会被解析成为节点对象插入 DOM。注意,如果文本之中含有<script>标签,虽然可以生成script节点,但是插入的代码不会执行。
Element.outerHTML ---------- 包括元素本身和所有子节点
Element.outerHTML属性返回一个字符串,表示当前元素节点的所有 HTML 代码,包括该元素本身和所有子元素。
- outerHTML属性是可读写的,对它进行赋值,等于替换掉当前元素。
// HTML 代码如下
// <div id="container"><div id="d">Hello</div></div>
var container = document.getElementById('container');
var d = document.getElementById('d');
container.firstChild.nodeName // "DIV"
d.nodeName // "DIV"
d.outerHTML = '<p>Hello</p>'; ------------------------- outerHTML可读写
container.firstChild.nodeName // "P"
d.nodeName // "DIV"
注意:
上面代码中,变量d代表子节点,它的outerHTML属性重新赋值以后,内层的div元素就不存在了,被p元素替换了。
但是,变量d依然指向原来的div元素,这表示被替换的DIV元素还存在于内存中。!!!!!!!!!!!!!!!
- 注意,如果一个节点没有父节点,设置outerHTML属性会报错。
Element.clientHeight
Element.clientWidth
- Element.clientHeight属性返回一个整数值,表示元素节点的 CSS 高度(单位像素)
- 只对
块级元素
生效,对于行内元素返回0。 - 如果块级元素没有设置 CSS 高度,则返回
实际高度
。 - 除了元素本身的高度,它还包括
padding
部分,但是不包括border、margin。 - 如果有
水平滚动条
,还要减去水平滚动条的高度。 - 这个值始终是
整数
,如果是小数会被四舍五入。
document.documentElement ----------------------- 的clientHeight属性,返回当前视口的高度(即浏览器窗口的高度),等同于window.innerHeight属性减去水平滚动条的高度(如果有的话)。
document.body ----------------------------------------- 的高度则是网页的实际高度。
一般来说,document.body.clientHeight大于document.documentElement.clientHeight。
Element.clientLeft
Element.clientTop
- Element.clientLeft属性等于元素节点左边框(left border)的宽度(单位像素),不包括左侧的padding和margin。
- 如果没有设置左边框,或者是行内元素(display: inline),该属性返回0。
- 该属性总是返回整数值,如果是小数,会四舍五入。
- Element.clientTop属性等于网页元素顶部边框的宽度(单位像素),其他特点都与clientTop相同。
Element.scrollHeight ------------ 当前元素的总高度
Element.scrollWidth
-
Element.scrollHeight
属性返回一个整数值
(小数会四舍五入),表示当前元素的总高度(单位像素)
,包括溢出容器
、当前不可见的部分
。 - 它包括padding,但是不包括border、margin以及水平滚动条的高度(如果有水平滚动条的话)
- 还包括伪元素(::before或::after)的高度。
- Element.scrollWidth属性表示当前元素的总宽度(单位像素),其他地方都与scrollHeight属性类似。
- 这两个属性只读。
整张网页的总高度可以从document.documentElement或document.body上读取。
Element.scrollLeft
Element.scrollTop
- Element.scrollLeft属性表示当前元素的
水平滚动条向右侧滚动的像素数量
- Element.scrollTop属性表示当前元素的
垂直滚动条向下滚动的像素数量
- 对于那些没有滚动条的网页元素,这两个属性总是等于0
- 这两个属性都可读写,设置该属性的值,会导致浏览器将当前元素自动滚动到相应的位置。
Element.offsetHeight
Element.offsetWidth
- Element.offsetHeight属性返回一个整数,表示元素的 CSS 垂直高度(单位像素)
- 包括元素本身的高度、padding 和 border,以及水平滚动条的高度(如果存在滚动条)
- Element.offsetWidth属性表示元素的 CSS 水平宽度(单位像素),其他都与Element.offsetHeight一致。
Element.offsetLeft
Element.offsetTop
- Element.offsetLeft返回当前元素左上角相对于Element.offsetParent节点的水平位移
- Element.offsetTop返回垂直位移,单位为像素。通常,这两个值是指相对于父节点的位移
滚动到顶部案列 vue
<template>
<div id="app">
<div class="top" v-if="buttonShow" v-on:click="goTop">回到顶部</div>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
buttonShow: false,
}
},
mounted() {
document.addEventListener('scroll', this.goScroll) ----- 页面加载完成,监听scroll事件
},
methods: {
goScroll: function() {
const currentTop = document.documentElement.scrollTop || document.body.scrollTop;
const viewPort = document.documentElement.clientHeight || document.body.clientHeight;
console.log(currentTop, viewPort)
if (currentTop > viewPort/2) { ------------------------- 滚动的距离和释口距离比较
this.buttonShow = true
} else {
this.buttonShow = false;
}
},
goTop: function() {
console.log('aa');
let currentTop = document.documentElement.scrollTop || document.body.scrollTop;
const totalTime = 2000; ---------------------- 总时间
const frequent = 200; -------------------------- 频率,多长时间滚动一次
const speed = currentTop/2000; ----------------- 滚动的速度
const stepDistance = speed * frequent; --------- 一次滚动的距离
let timer = setInterval(()=> {
if (currentTop<=0) { ------------------------- 距离小于0时,停止滚动
window.clearInterval(timer)
return;
}
currentTop = currentTop - stepDistance; ------ 当前距离 = 初始距离 - 一次滚动的距离
document.documentElement.scrollTop = currentTop; -------- 设置当前距离滚动顶部的距离
}, 20) ----------------------------------------- 20毫秒执行一次以上操作
}
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.top {
background: yellow;
padding:20px 40px;
position: fixed;
bottom: 100px;
right: 10px;
}
</style>
滚动到顶部案列 react
import React,{Component} from 'react';
export default class toTOP extends Component {
state = {
buttonShow: false
}
componentWillMount() {
window.addEventListener('scroll',this.onScroll) // 监听滚动事件
}
onScroll = () => {
var currentTop = document.documentElement.scrollTop || document.body.scrollTop; // 顶部到最顶部的距离
var viewPortHeight = document.documentElement.clientHeight || document.body.clientHeight; // 可视高度
if ( currentTop > viewPortHeight) { // 大于显示按钮
this.setState({
buttonShow:true
})
} else {
this.setState({ // 小于隐藏按钮
buttonShow: false
})
}
}
goTop = () => {
var currentTop = document.documentElement.scrollTop || document.body.scrollTop;
var totalTimes = 200;
var speed = currentTop/totalTimes ;
var StepTime = 10;
var setpDistance = speed * StepTime;
var timer = window.setInterval(()=>{ // var itmer = setInterval()也可以,不要window
if ( currentTop <=0 ) {
window.clearInterval(timer);
return;
}
currentTop = currentTop - setpDistance;
document.documentElement.scrollTop = currentTop;
document.body.scrollTop = currentTop;
},StepTime)
}
render() {
return (
<div >
<div>
回到顶部测试
</div>
<div
ref="button"
onClick={this.goTop}
style={
this.state.buttonShow
?
{
display:'inline-block',
border:'1px solid red',
background:'yellow',
padding:'10px 30px',
position:'fixed',
bottom:'60px',
right:'20px'
}
:
{
display:'none',
border:'1px solid red',
background:'yellow',
padding:'10px 30px',
position:'fixed',
bottom:'60px',
right:'20px'
}
}>
回到顶部
</div>
<div style={{padding:'20px 160px'}}>
年参演电视剧《与青春有关的日子》,开始在影视圈崭露头角[1] 。2005年拍摄古装剧《锦衣卫》。2007年主演赵宝刚导演的青春剧《奋斗》;[2] 同年,主演首部电影《走着瞧》。2008年主演滕华涛执导的电视剧《蜗居》,饰演80后城市青年小贝。[1] 2009年,在电影《海洋天堂》中扮演自闭症患者王大福;同年参演抗战题材的电视剧《雪豹》[4] 。2011年,主演的电视剧《裸婚时代》在各大卫视播出;[5] 2011年-2012年连续2年获得北京大学生电影节[6-7] 最受大学生欢迎男演员奖。2012年,凭借电影《失恋33天》获得第31届大众电影百花奖最佳男主角奖;[8] 同年成立自己经营的北京君竹影视文化有限公司,并导演第一部影视作品《小爸爸》。2013年2月,主演的电影《西游·降魔篇》在全国上映。[9]
2014年3月28日,主演的中韩合资文艺爱情片《我在路上最爱你》在全国上映。2014年12月18日,在姜文执导的动作喜剧片《一步之遥》中扮演武七一角。[10] 2016年,主演电视剧《少帅》,饰演张学良[11] ;主演电视剧《剃刀边缘》[12] 。7月15日导演的电影《陆垚知马俐》上映。[13]
演艺事业外,文章也参与公益慈善事业,2010年成立大福自闭症关爱基金。
2017年9月16日,凭借《陆垚知马俐》获得第31届中国电影金鸡奖导演处女作奖。[14]
关于你。就是因为我的害怕,我亲眼看你走向她。我喜欢你是事实,你有女朋友也是事实。我以为我不说出口就会保持这样的朋友关系,却还是她赶了个巧,那应该是个寒假,你有女朋友了,我还是听说,我那么爱,却还是无果。于是我和她之间就莫名其妙的就多少有了敌人的感觉,或许就是别人口中的那样,世界上完全不相干的两个女人,会因为一个男人要么很友好,要么是仇恨。关于她我做不到友好,但也不是仇恨,只是你选择了她,我就希望她好好爱你,照顾你,连我的份也一起爱了。自爱上你的那天起,思念便成了戒不掉的瘾。你的一言一笑,一颦一蹙,无不牵动我的心,百千尘思,唯念一缕;万千红颜,唯恋一人。我愿意一生漂泊浪迹在你的故事里,甘愿为你鞍前马后,马首是瞻,即使你从未给我一句承诺,即使你从未给我半分爱情,依然无悔无怨。
关于你。一场高考,考散了我们,毕业了会不会就是终生最后一见,很高兴,我们不是。各奔东西了,你们继续上了大学,值得欣慰的是,你们也是异地,这样不能算是我心机,只能说是恰巧,你们的安排恰合我意。后来也有听说,她从她的城市去看你,而那时的我能说什么呢。她是真心爱你,这是事实。我也曾和闺蜜说过,一生至少该有一次,为了某个人而忘了自己,不求有结果,不求同行,不求曾经拥有,甚至不求你爱我,只求在我最美的年华里,遇到你。今生遇见你,我觉得是幸福的,尽管这幸福交杂着万般痛苦。我也曾幻想着悄悄地去到你的学校,在某个阳光明媚的下午,在你去教室的路上和你来场偶遇,精心准备的偶遇,。可是我还来不及去和你偶遇,你们就毕了业。爱是种很玄的东西,说不清,道不明,剪不断,理还乱。世上,有种爱明知没有结果,却依然坚守原地,不舍离去,哪怕握不住你的一丝余温,依然选择默默为你守候。一路来去,心门只为你独开,山城只为你独驻,白天只为你旖旎,黑夜只为你流连。因为爱你,哪怕心入住荒岛,还是会以最深情的眼神,看着你幸福。
</div>
</div>
)
}
}
语句
语句 statement 是为了完成某种任务而进行的操作
- 语句以分号结尾,一个分号就表示一个语句结束
- 多个语句,可以写在一行内
- 分号前面可以没有任何内容,js将其视为空语句
表达式
表达式 expression 为了得到返回值的计算式
- 凡是预期为值得地方,都可以使用表达式
表达式和语句的区别
- 语句是为了进行某种操作,一般不需要返回值
- 表达式式为了得到返回值,一定有返回值
表达式和语句总结:
(1) 语句是为了完成某种任务进行得操作,一般不需要返回值
(2) 语句以分号结尾,分号前面可以没有任何内容,是空语句
(3) 多个语句可以写在一行内
(4) 表达式是为了得到返回值得计算值,一定有返回值,凡是预期为值的地方,都可以使用表达式
var a = 1 + 3 ; var b = 'abc'; ------------- 语句以分号结尾,两个语句可以写在一行内
;;; ----------------------------------------- 空语句,分号前面可以没有任何内容,js视其为空语句
1+3 在等号右边,预期是个值,所以可以使用表达式(为了得到返回值的计算式)
变量
变量是对值得具名引用
- 变量就是为值取名,-------引用这个名字,就是引用这个值
- 变量名:变量的名字就是变量名
- 变量名区分大小写 ( A和a是两个不同的变量 )
- 如果只是声明变量,而没有赋值,那么变量的值是 undefined
- 如果变量赋值的时候,忘了写var命令,这条语句也是有效的。
- 可以在同一条var命令中声明多个变量。
- js是动态语言,变量的类型没有限制,变量可以随时更改类型
- 如果使用var重新声明一个已经存在的变量,是无效的,但是,如果第二次声明的时候还进行了赋值,则会覆盖掉前面的值。
变量提升
js引擎的工作方式:先解析代码,获取所有被声明的变量,再一行一行的执行,造成造成的结果就是所有变量的声明语句,都会被提升到代码头部,这就叫做 ----- 代码提升hoisting -----
console.log(a);
var a = 1; --------------------- 变量提升,变量的声明语句会被提升到代码头部,注意不包括赋值语句
等同于
var a;
console.log(a); -------------------- a是undifined,不会报错
a = 1;
标识符
标识符identifier: 用来识别各种值得合法名称
- 最常见的表示符,------变量名和函数名
- 标识符的命名规则:
第一个字符,可以是任意 Unicode 字母(包括英文字母和其他语言的字母),以及美元符号($)和下划线(_)。
第二个字符及后面的字符,除了 Unicode 字母、美元符号和下划线,还可以用数字0-9。
第一个字符:字母,$,下划线
第二个字符:字母,数字,$,下划线
- 中文是合法的标识符,可以用作变量名。
注释
- 一种是单行注释,用
//
起头; - 另一种是多行注释,放在
/*
和*/
之间。
区块
JavaScript 使用大括号,将多个相关的语句组合在一起,称为“区块”(block)。
- 区块:大括号包裹的多个语句
- 对于var命令来说,区块不构成单独的作用域scop,与不使用区块没有任何区别
- 单独使用区块不常见,区块一般用来构成复杂的语法结构,如for,while,if,funcion等
{
var a = 1;
}
a // 1
if结构
if (m === 3) ------------------------- 只有在m等于3时,才会将其值加上1
m = m + 1; -------------------------- 只有一个语句时,可以不用 { }
break语句和continue语句
- break语句用于跳出代码块或循环。
- continue语句用于立即终止本轮循环,返回循环结构的头部,开始下一轮循环。
数据类型
number,string,boolean,null,undefined,object,symbol
如何确定一个值是什么类型 ( 三种方法 )
- typeof ---------------------------------- 有6种返回值
- instanceof ----------------------------- 主要用于对象,数组的区分
- object.prototype.toString
typeof
- typeof返回的是一个字符串,注意是一个字符串
- 数值、字符串、布尔值分别返回number、string、boolean。
- 函数返回function
- undefined返回undefined
- 对象返回object
- 数组返回object
- null返回object
typeof是个一元运算符,运算时具有较高的优先级
(1) es5有6种数据类型, typeof返回也是6种类型
---------- es5的6种数据类型:number, string, boolean, undefined, null, object
---------- typeof返回的6种类型:number, string, boolean, undefined, object, function
(2) typeof无法区分数组和对象
----------- 数组和对象可以通过 instanceof 来区分
var o = {};
var a = [];
o instanceof Array // false
a instanceof Array // true
(3) Number
Number(null) ------------------------- 0
Number(undefined) -------------------- NaN
Number('') --------------------------- 0
Number(true) ------------------------- 0
5 + null ----------------------------- 5
5 + undefined ------------------------ NaN
(4) typeof NaN ----------------------- 'number'
注意 typeof 返回的是一个字符串
NaN不等于任何值,包括自身
数组的indexOf方法内部使用的是严格相等运算符,所以该方法对NaN不成立。
[NaN].indexOf(NaN) // -1
(5) typeof是一元运算符,具有较高的运算优先级
typeof 1 !== 'undefined'
运算顺序是:
1. typeof 1 ----------------------------- 结果是 number
2. 'number' !== 'undefined' -------------- 结果是true
typeof ( 1 !== 'number' ); ----------------------- 结果是 'boolean'
typeof 1 !== 'number' ----------------------- 结果是 false
与数值相关的全局方法
parseInt(字符串,值的进制)
parseInt() 用于将 ( 字符串 ) 转化为 ( 整数 )
- 如果字符串头部有空格,空格会被自动去除。
- 如果parseInt的参数不是字符串,则会先转为字符串再转换。
- 字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。
- 如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN。
所以,parseInt的返回值只有两种可能,要么是一个十进制整数,要么是NaN。
- 如果字符串以0开头,将其按照10进制解析。
- 参数:
parseInt方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数。 - 如果第二个参数是0、undefined和null,则直接忽略
parseInt(1.23) // 1
// 等同于
parseInt('1.23') // 1
// 也等同于
parseInt(' 1.23') // 1
参数
parseInt('1000', 2) -------------------- 表示将2进制的字符串1000,转换成十进制整数
parseFloat()
- 如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回NaN。
- 区别Number()函数
parseFloat(true) // NaN
Number(true) // 1
parseFloat(null) // NaN
Number(null) // 0
parseFloat('') // NaN
Number('') // 0
parseFloat('123.45#') // 123.45
Number('123.45#') // NaN
isNaN()
isNaN方法可以用来判断一个值是否为NaN
- isNaN只对数值有效,如果传入其他值,会被先转成数值。
- 比如,传入字符串的时候,字符串会被先转成NaN,所以最后返回true。
也就是说,isNaN为true的值,有可能不是NaN,而是一个字符串。
- 出于同样的原因,对于对象和数组,isNaN也返回true。
- 但是,对于空数组和只有一个数值成员的数组,isNaN返回false。
isNaN('Hello') // true
// 相当于
isNaN(Number('Hello')) // true ---------------------------- Number('hello')值是NaN
class类
- 类的constructor()方法就是构造函数
- 定义类的方法的时候,前面不需要加 ( function ) 关键字
- 类的方法之间,不需要 ( 逗号 ) 分隔,加了逗号会报错
-
es6的类,可以看作是构造函数的另一种写法,类的数据类型是'function',类本身就指向构造函数,使用时,也是通过new命令生成实例,类的所有方法都是定义在类的prototype属性上面
------------------------- 重要 - 类的内部所有定义的方法,都是不可枚举的(non-enumerable)。
- 类的属性名,可以采用表达式。( 为了得到返回值的计算式是 表达式 )
- 类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。
- 实例的属性除非显式定义在自身,即this对象上,否则都是定义在原型上
- 类的实例可以共享一个原型对象,原型链继承
class Point {
doStuff() {
console.log('stuff');
}
}
var b = new Point ();
b.doStuff() // "stuff"
typeof Point // "function"
Point === Point.prototype.constructor // true
// 等同于
Point.prototype = {
doStuff() {},
};
constructor方法
一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法将会被默认添加
class表达式
与函数一样,类也可以使用表达式的形式定义
类不存在变量提升
class静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例所继承
- 如果在类的方法前加上 static 关键字,就表示该方法不会被实例所继承,而是直接通过类来调用,这就成为静态方法
- 静态方法: 在方法前加上 static 关键字,表示该方法不会被类的实例所继承,而是直接通过类来调用
注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。
- 静态方法可以和非静态方法重名
- 父类的静态方法,可以被子类继承。
- 静态方法也是可以从super对象上调用的。
class AAA{
static go() {
console.log('aaaa')
}
};
const BBB = new AAA();
BBB.go() --------------------- Uncaught TypeError: BBB.go is not a function
AAA.go() --------------------- aaaa
解析:
(1) 在类中定义的方法,都会被类的实例所继承
(2) 但是在方法前加上 static 关键字后,该方法是静态方法,不会被实例所继承,而是直接通过类本身调用
class Foo {
static bar () { -------------------------- 静态方法中的this指的是类,而不是实例
this.baz(); ---------------------------- 静态方法不被实例所继承
}
static baz () {
console.log('hello');
}
baz () { --------------------------------- 静态方法可以和非静态方法重名
console.log('world'); ------------------ 非静态方法,被实例所继承
}
}
Foo.bar() // hello
class Bar extends Foo { ------------------- 父类得静态方法,能被子类所继承
}
Bar.bar() // 'hello'
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
static classMethod() {
return super.classMethod() + ', too'; ----------------- super在静态方法中表示父类
}
}
Bar.classMethod() // "hello, too"
class的静态属性和实例属性
静态属性指的是class本身的属性,而不是定义在实例对象上的 ( this ) 属性
- 静态属性
class Foo {
}
Foo.prop = 1;
Foo.prop // 1
提案新写法:
class MyClass {
static myStaticProp = 42; ---------------------------- 静态属性
constructor() {
console.log(MyClass.myStaticProp); // 42
}
}
- 实例属性
以前,定义实例属性,只能写在类的constructor方法里面。
有了新的写法以后,可以不在constructor方法里面定义。
class ReactCounter extends React.Component {
constructor(props) {
super(props);
this.state = { --------------------- 在类的constructor构造函数中,定义实例属性
count: 0
};
}
}
class ReactCounter extends React.Component {
state = {
count: 0
};
}
- 静态属性和实例属性总结
class MyClass {
myProp = 42; --------------------------------- 类的实例属性
static myStaticProp = 42; ------------------------ 类的静态属性
static constructor() {
console.log(this.myProp); // 42
console.log(MyClass.myStaticProp); // 42
}
}
class继承
- class通过 extends 关键字实现继承
- 子类必须在constructor中调用super方法,否则新建实例时会报错。因为子类的自己的this对象,必须通过父类的构造函数完成塑造,得到与父类同样是实例属性和方法,然后对其加工,得到子类自己的实例属性和方法。
- 如果不调用super方法,就得不到this对象
- 在子类的constructor中,只有先调用 super 方法后,才能使用 this 关键字
- 父类的静态方法,被子类所继承,但是不被实例所继承
- Object.getPrototypeOf方法可以用来从子类上获取父类。
super关键字
super关键字,可以当函数,也可以当对象
super作为函数
super作为函数调用时,代表父类的构造函数
super为函数时,虽然代表父类的构造函数,但是 ( 返回 ) 的是 ( 子类的实例 )!!!!!
- super为函数时,只能用在子类的 constructor 中,用在其他地方会报错
super作为对象
super作为对象,在普通方法中指父类的原型对象
super作为对象时,用在普通方法中表示父类的原型对象,用在静态方法中,表示父类。
class A {
p() { ----------------------- 类的实例方法,是定义在类的原型上的
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.p()); -------- super作为对象,在普通方法中,表示父类的原型对象 //结果是2
}
}
let b = new B();
这里需要注意,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。
class A {
constructor() {
this.p = 2;
}
}
class B extends A {
get m() {
return super.p;
} ----------------super作为对象,表示父类的原型对象,所以定义在父类实例上的属性和方法无法通过super调用
}
let b = new B();
b.m // undefined
- 如果方法和属性定义在父类的原型对象上,super可以取到
class A {}
A.prototype.x = 2;
class B extends A {
constructor() {
super();
console.log(super.x) // 2
}
}
let b = new B();
ES6规定,在子类普通方法中,通过super调用父类的原型对象上的方法(父类的方法)时,方法内部的this,指向 ( 当前 ) 的 ( 子类实例 ) !!!!!!!!!!!
class A {
constructor() {
this.x = 1;
}
print() {
console.log(this.x);----------(3) this指类的实例
}
}
class B extends A {
constructor() {
super();
this.x = 2;
}
m() {
super.print();--(2) 指A中的print(),但是方法中的this,指向当前子类实例,this指函数调用时所在的对象
}
}
let b = new B();
b.m() // 2 ---------------------(1) b.m()即B中的m()
- 由于this指向子类实例,所以如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性。
class A {
constructor() {
this.x = 1;
}
}
class B extends A {
constructor() {
super();
this.x = 2;
super.x = 3; ----------------------- 通过super对某个属性赋值,super.x === this.x
console.log(super.x); --------------- 读取super.x的时候,读的是A.prototype.x,所以返回undefined
console.log(this.x); // 3
}
}
let b = new B();
super作为对象,在静态方法中,指父类
class Parent {
static myMethod(msg) {
console.log('static', msg);
}
myMethod(msg) {
console.log('instance', msg); ---------- 父类原型上的方法
}
}
class Child extends Parent {
static myMethod(msg) {
super.myMethod(msg);--------------- super在静态方法中表示父类,父类直接调用,父类的静态方法
}
myMethod(msg) {
super.myMethod(msg); -------------- 原型链上的方法,super在普通方法中,表示父类的原型
}
}
Child.myMethod(1); // static 1 ------------ 通过类直接调用,静态方法
var child = new Child();
child.myMethod(2); // instance 2 --------- 实例上调用,原型链方法
在子类的静态方法中通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例。
class A {
constructor() {
this.x = 1;
}
static print() {
console.log(this.x); ---------------------------- this指向B, B.x时B的静态属性
}
}
class B extends A {
constructor() {
super();
this.x = 2;
}
static m() {
super.print();
}
}
B.x = 3; -------------------------------------------- B的静态属性x
B.m() // 3 -------------------------------------------- 结果是3
解析:
静态方法B.m里面,super.print指向父类的静态方法print()。这个方法里面的this指向的是B,而不是B的实例。
- 注意,使用super的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错。
类的prototype属性和__ proto__属性
Class 作为构造函数的语法糖,同时有prototype属性和 __ proto__属性,因此同时存在两条继承链。
(1)子类的__ proto__属性,表示构造函数的继承,总是指向父类。
(2)子类prototype属性的__ proto__属性,表示方法的继承,总是指向父类的prototype属性。
lass A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
解析:
(1) 子类.__proto__ === 父类
(2) 子类.prototype.__proto__ === 父类.prototype
- 这样的结果是因为,类的继承是按照下面的模式实现的
class A {
}
class B {
}
// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);---------> B.prototype.__proto__ === A.prototype
// B 继承 A 的静态属性
Object.setPrototypeOf(B, A); --------------------------> B.__proto__ === A
const b = new B();
- 这两条继承链,可以这样理解:
(1) 作为一个对象,子类(B)的原型(__ proto__属性)是父类(A);
(2) 作为一个构造函数,子类(B)的原型对象(prototype属性)是父类的原型对象(prototype属性)的实例。
Object.create(A.prototype); --------------------- 以A.prototype为原型,创建实例对象
// 等同于
B.prototype.__proto__ = A.prototype;
- extends关键字后面可以跟多种类型的值。
class B extends A {
}
上面代码的A,只要是一个有prototype属性的函数,就能被B继承。
由于函数都有prototype属性(除了Function.prototype函数),因此A可以是任意函数。
regexp
字符串有四种与正则有关:
match(),search(),replace(),split()
- regular expression 正则表达式
- 新建正则表达式有两种方法:
- 字面量: 以斜杠表示开始和结束
- RegExp构造函数
- 字面量方式和RegExp方式的区别:
- 字面量--------------------- 编译时新建,效率高
- new Regexp() ----------- 运行时新建,效率低
var regex = /xyz/; ---------------------------------- 字面量方式,以斜杠表示开始和结束
var regex = new RegExp('xyz'); ----------------------- RegExp构造函数
- RegExp()可以有两个参数,第一个是正则字符串,第二个表示修饰符
var regex = new RegExp('xyz', 'i'); ---------------- i 是 ignoreCase 的缩写, 表示忽略大小写
// 等价于
var regex = /xyz/i;
正则对象的实例属性
- RegExp.prototype.ignoreCase:返回一个布尔值,表示是否设置了 ( i ) 修饰符。
- RegExp.prototype.global:返回一个布尔值,表示是否设置了 ( g ) 修饰符。
- RegExp.prototype.multiline:返回一个布尔值,表示是否设置了 ( m ) 修饰符。
上面三个属性都是只读的。 - RegExp.prototype.lastIndex:返回一个数值,表示下一次开始搜索的位置。
该属性可读写,但是只在进行连续搜索时有意义,详细介绍请看后文。
- RegExp.prototype.source:返回正则表达式的字符串形式(不包括反斜杠),该属性只读。
var r = /abc/igm;
r.ignoreCase // true
r.global // true
r.multiline // true
r.lastIndex -------------------------- 0 lastIndex返回一个数值,表示下一次开始搜索的位置
r.source --------------------------- "abc" source返回正则表达式的字符串形式,只读
正则表示式的实例方法
RegExp.prototype.test()
- 正则实例对象的test方法返回一个布尔值,表示当前模式是否能匹配参数字符串
- 如果正则表达式带有g修饰符,则每一次test方法都从上一次结束的位置开始向后匹配。
- 带有g修饰符时,可以通过正则对象的lastIndex属性指定开始搜索的位置。
var r = /x/g;
var s = '_x_x';
r.lastIndex // 0 ------------------- 从0开始匹配
r.test(s) // true ------------------ 匹配
r.lastIndex // 2 ------------------- 下一次从2位置开始匹配
r.test(s) // true ------------------ 匹配
r.lastIndex // 4
r.test(s) // false
- 如果正则模式是一个空字符串,则匹配所有字符串。
new RegExp('').test('abc')
// true
RegExp.prototype.exec()
1. exec()匹配成功返回数组,匹配失败返回null
2. 数组成员包括,整个匹配成功的字符串,input,index
3. 正则带有括号,数组有多个成员,第一个是整个匹配,第二个是第一个括号的匹配结果,第三个成员是第二个括号匹配的结果
4. 正则带有g修饰符,则exec()可以执行多次
正则实例对象的exec方法,用来返回匹配结果。如果发现匹配,就返回一个数组,成员是匹配成功的子字符串,否则返回null。
- 匹配成功,
exec()返回数组
,成员是匹配成功的子字符串
- 匹配失败,exec()返回null
- exec方法的返回数组还包含以下两个属性:
- input:整个原字符串。
- index:整个模式匹配成功的开始位置(从0开始计数)。
- 如果正则表示式包含圆括号(即含有“组匹配”),则返回的数组会包括多个成员。
- 第一个成员是整个匹配成功的结果,
- 后面的成员就是圆括号对应的匹配成功的组。
也就是说,
第二个成员对应第一个括号,
第三个成员对应第二个括号,
以此类推。整个数组的length属性等于组匹配的数量再加1。
var a = /a(a)(b)/; ---------------------- 如果正则带有括号,exec()返回的数组就包括多个成员
var b = 'aababacad';
var d = a.exec(b);
console.log(d)
结果是: ["aab", "a", "b", index: 0, input: "aababacad"]
第一个成员: 整个匹配的结果
第二个成员: 第一个括号匹配的结果
第三个成员: 第二个括号匹配的结果
- 如果正则表达式加上g修饰符,则可以使用多次exec方法,下一次搜索的位置从上一次匹配成功结束的位置开始。
var reg = /a/g;
var str = 'abc_abc_abc'
var r1 = reg.exec(str);
r1 // ["a"]
r1.index // 0
reg.lastIndex // 1
var r2 = reg.exec(str);
r2 // ["a"]
r2.index // 4
reg.lastIndex // 5
var r3 = reg.exec(str);
r3 // ["a"]
r3.index // 8
reg.lastIndex // 9
var r4 = reg.exec(str);
r4 // null
reg.lastIndex // 0
String.prototype.match()
- 匹配成功返回一个数组,匹配失败返回null。
- 当正则带有g修饰符时,返回所有匹配成功的结果
- 设置正则表达式的lastIndex属性,对match方法无效,匹配总是从字符串的第一个字符开始。
重要
var s = 'abba';
var r = /a/g;
s.match(r) // ["a", "a"] ----------------- string.match(正则带有g修饰符时),返回所有匹配成功的结果
r.exec(s) // ["a"] ---------------------- exec()返回匹配成功的子字符串
注意:
1. exec()和match()的区别: 成功时,都返回数组,但match()正则表达式参数中有g修饰符,返回所有匹配成功的结果
2. 设则正则的lastIndex属性,对match()无效,match()总是从第一个字符开始匹配
var r = /a|b/g;
r.lastIndex = 7;
'xaxb'.match(r) // ['a', 'b']
r.lastIndex // 0
String.prototype.search()
--------------- 返回正则匹配结果在字符串中的位置
-
区别 indexOf 方法:
-
search()的参数必须是正则表达式,而indexOf()的参数只是普通字符串, indexOf效率更高
- 字符串对象的search方法,返回第一个满足条件的匹配结果在整个字符串中的位置。
- 如果没有任何匹配,则返回-1。
String.prototype.replace()
- 字符串对象的replace方法可以替换匹配的值。它接受两个参数,第一个是正则表达式,表示搜索模式,第二个是替换的内容。
- 正则表达式如果不加g修饰符,就替换第一个匹配成功的值,否则替换所有匹配成功的值。
'aaa'.replace('a', 'b') // "baa"
'aaa'.replace(/a/, 'b') // "baa"
'aaa'.replace(/a/g, 'b') // "bbb" --------------- 正则带有g修饰符,替换所有匹配成功的值
- replace方法的一个应用,就是消除字符串首尾两端的空格。
String.prototype.split()
- 字符串对象的split方法按照正则规则分割字符串,返回一个由分割后的各个部分组成的数组。
- 该方法接受两个参数,第一个参数是正则表达式,表示分隔规则,第二个参数是返回数组的最大成员数。
// 非正则分隔
'a, b,c, d'.split(',')
// [ 'a', ' b', 'c', ' d' ]
// 正则分隔,去除多余的空格 --------------------------------- 重要
'a, b,c, d'.split(/, */)
// [ 'a', 'b', 'c', 'd' ]
// 指定返回数组的最大成员
'a, b,c, d'.split(/, */, 2)
[ 'a', 'b' ]
匹配规则
字面量字符和元字符
- 如果在正则表达式之中,某个字符只表示它字面的含义,那么它们就叫做
“字面量字符”(literal characters)
- 除了字面量字符以外,还有一部分字符有特殊含义,不代表字面的意思。它们叫做
“元字符”(metacharacters)
(1)点字符(.)
- 点字符(.)匹配除
回车(\r)
、换行(\n)
、行分隔符(\u2028)
和段分隔符(\u2029)
以外的所有字符。
(2)位置字符(^ $)
- 位置字符用来提示字符所处的位置,主要有两个字符。
- ^ 表示字符串的开始位置
- $ 表示字符串的结束位置
(3)选择符(|)
- 竖线符号(|)在正则表达式中表示“或关系”(OR)
- 即cat|dog表示匹配cat或dog。
- 多个选择符可以联合使用
- 选择符会包括它前后的多个字符,比如/ab|cd/指的是匹配ab或者cd,而不是指匹配b或者c。如果想修改这个行为,可以使用圆括号。
// 匹配fred、barney、betty之中的一个
/fred|barney|betty/
--------------
/a( |\t)b/.test('a\tb') -----------------true a和b之间有一个空格或者一个制表符。
转义符 ( \ )
- 正则表达式中那些有特殊含义的元字符,如果要匹配它们本身,就需要在它们前面要加上反斜杠,进行转义。
- 正则表达式中,需要反斜杠转义的,一共有12个字符
-
^
、.
、[
、$
、(
、)
、|
、*
、+
、?
、{
和\\
正则表达式中,需要加反斜杠转义的,一共有12个字符:
^ $ . | ( ) [ { ? * + \\
点字符( . )
位置字符( ^ $ )
选择符( | )
量词符( ? * + )
字符类( [ )
重复类( { )
组匹配( ( ) )
双反斜杠 ( \\ )
- 需要特别注意的是,如果使用RegExp方法生成正则对象,转义需要使用两个斜杠,因为字符串内部会先转义一次。
(new RegExp('1\+1')).test('1+1')
// false
(new RegExp('1\\+1')).test('1+1')
// true
上面代码中,RegExp作为构造函数,参数是一个字符串。
但是,在字符串内部,反斜杠也是转义字符,
所以它会先被反斜杠转义一次,然后再被正则表达式转义一次,因此需要两个反斜杠转义。
特殊字符
- 正则表达式对一些不能打印的特殊字符,提供了表达方法。
\cX 表示Ctrl-[X],其中的X是A-Z之中任一个英文字母,用来匹配控制字符。
[\b] 匹配退格键(U+0008),不要与\b混淆。
\n 匹配换行键。 -------------------------------- new line
\r 匹配回车键。 -------------------------------- return
\t 匹配制表符 tab(U+0009)。
\v 匹配垂直制表符(U+000B)。
\f 匹配换页符(U+000C)。
\0 匹配null字符(U+0000)。
\xhh 匹配一个以两位十六进制数(\x00-\xFF)表示的字符。
\uhhhh 匹配一个以四位十六进制数(\u0000-\uFFFF)表示的 Unicode 字符。
字符类 ( [ ] )
------ 表示一系列的字符可供选择,只要匹配其中一个就可以。
- 字符类(class)表示有一系列字符可供选择,只要匹配其中一个就可以了。
- 所有可供选择的字符都放在方括号内,比如[xyz] 表示x、y、z之中任选一个匹配。
- 有两个字符在字符类中有特殊含义。
(1)脱字符(^)
- 如果方括号内的第一个字符是[^],则表示除了字符类之中的字符,其他字符都可以匹配。
- [^xyz]表示除了x、y、z之外都可以匹配。
- 如果方括号内没有其他字符,即只有
[^],就表示匹配一切字符
,其中包括换行符。
相比之下,点号作为元字符(.)是不包括换行符的。
- 注意,脱字符只有在字符类的第一个位置才有特殊含义,否则就是字面含义。
(2)连字符(-)
- 某些情况下,对于连续序列的字符,连字符(-)用来提供简写形式,表示字符的连续范围。
- 比如:
- [abc]可以写成[a-c]
- [0123456789]可以写成[0-9]
- 同理[A-Z]表示26个大写字母
/a-z/.test('b') // false
/[a-z]/.test('b') // true
上面代码中,当连字号(dash)不出现在方括号之中,就不具备简写的作用,只代表字面的含义,所以不匹配字符b。
只有当连字号用在方括号之中,才表示连续的字符序列。
[0-9.,]
[0-9a-fA-F]
[a-zA-Z0-9-]
[1-31]
这些都是合法的字符类简写形式
-----------------------------
[1-31] ----------------------------------- 不代表1到31,只代表1到3。
/([12][0-9])|(3[01])/ -------------------- 表示1到31
- 另外,不要过分使用连字符,设定一个很大的范围,否则很可能选中意料之外的字符。最典型的例子就是[A-z],表面上它是选中从大写的A到小写的z之间52个字母,但是由于在 ASCII 编码之中,大写字母与小写字母之间还有其他字符,结果就会出现意料之外的结果。
预定义模式
\d 匹配0-9之间的任一数字,相当于[0-9]。 --------------------- digit 数字
\D 匹配所有0-9以外的字符,相当于[^0-9]。
\w 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]。
\W 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]。
\s 匹配空格(包括换行符、制表符、空格符等),相等于[ \t\r\n\v\f]。
\S 匹配非空格的字符,相当于[^ \t\r\n\v\f]。
\b 匹配词的边界。 --------------------- boundary 边界
\B 匹配非词边界,即在词的内部。
- [\S\s]指代一切字符。
重复类
- 模式的精确匹配次数,使用大括号({})表示。
- {n}表示恰好重复n次,
- {n,}表示至少重复n次,
- {n,m}表示重复不少于n次,不多于m次。
量词符
? 问号表示某个模式出现0次或1次,等同于{0, 1}。
* 星号表示某个模式出现0次或多次,等同于{0,}。
+ 加号表示某个模式出现1次或多次,等同于{1,}。
贪婪模式 ---------------- 3个量词符是贪婪模式
三个量词符,默认情况下都是最大可能匹配,即匹配直到下一个字符不满足匹配规则为止。这被称为贪婪模式。
- 如果想将贪婪模式改为非贪婪模式,可以在量词符后面加一个问号。!!!!!!!!!!!!!!!!
var a = 'aaaaa';
var b = a.match(/a+/);
console.log(b); ------------------------------- ["aaaaa", index: 0, input: "aaaaa"]
var c = a.match(/a*/);
console.log(c) ------------------------------- ["aaaaa", index: 0, input: "aaaaa"]
3个量词符的匹配 默认是贪婪模式
----------------------------
要将贪婪模式转化为 非贪婪模式,就要在量词符后面加一个问号
----> 量词符后面加问号 ----> 转化成非贪婪模式
var a = 'aaaaa';
var b = a.match(/a+?/); ------------------------------ ["a", index: 0, input: "aaaaa"]
console.log(b);
var c = a.match(/a*?/); ------------------------------ ["", index: 0, input: "aaaaa"]
console.log(c)
- 除了非贪婪模式的加号,还有非贪婪模式的星号(*)
*?:表示某个模式出现0次或多次,匹配时采用非贪婪模式。
+?:表示某个模式出现1次或多次,匹配时采用非贪婪模式。
修饰符
修饰符(modifier)表示模式的附加规则,放在正则模式的最尾部。
- modifier:修饰符的意思
- 修饰符可以单个使用,也可以多个一起使用。
(1)g 修饰符 ---------- global
- 默认情况下,第一次匹配成功后,正则对象就停止向下匹配了。g修饰符表示全局匹配(global),加上它以后,正则对象将匹配全部符合条件的结果,
主要用于搜索和替换。
var regex = /b/;
var str = 'abba';
regex.test(str); // true ------------------------------------- 不加g,正则每次都从头开始匹配
regex.test(str); // true
regex.test(str); // true
上面代码中,正则模式不含g修饰符,每次都是从字符串头部开始匹配。
所以,连续做了三次匹配,都返回true。
-----------
var regex = /b/g;
var str = 'abba';
regex.test(str); // true
regex.test(str); // true
regex.test(str); // false
上面代码中,正则模式含有g修饰符,每次都是从上一次匹配成功处,开始向后匹配。
因为字符串abba只有两个b,所以前两次匹配结果为true,第三次匹配结果为false。
(2)i 修饰符
- 默认情况下,正则对象区分字母的大小写,加上i修饰符以后表示忽略大小写(ignorecase)
(3)m 修饰符 ---- multiline多行模式,匹配换行符 \n
- m修饰符表示多行模式(multiline),会修改^和$的行为。
- 默认情况下(即不加m修饰符时),
^
和$
匹配字符串的开始处和结尾处, - 加上m修饰符以后,
^
和$
还会匹配行首和行尾,即^和$会识别换行符(\n)。
/world$/.test('hello world\n') // false
/world$/m.test('hello world\n') // true
/^b/m.test('a\nb') // true
------------------ a\nb 换行了,加了m,b就是在行首
上面代码要求匹配行首的b,如果不加m修饰符,就相当于b只能处在字符串的开始处。
加上b修饰符以后,换行符\n也会被认为是一行的开始。
组匹配
- 正则表达式的括号表示分组匹配,括号中的模式可以用来匹配分组的内容。
/fred+/.test('fredd') // true
/(fred)+/.test('fredfred') // true
- 注意,使用组匹配时,不宜同时使用g修饰符,否则match方法不会捕获分组的内容。
var m = 'abcabc'.match(/(.)b(.)/g);
m // ['abc', 'abc']
组匹配时,不宜使用g修饰符,上面情况就匹配了整个正则,而没有匹配组