JavaScript
JS的特点:1、解释性语言,2、单线程
JS三大部分:ECMAScript、BOM、DOM
前端的特点:结构、行为、样式相分离
ECMAScript
NaN不等于任何东西,包括自己。
JS数据类型
(原始值和引用值)其中原始值包括:number, string, boolean, undefined, null,引用值包括:array, object, function
逻辑运算符:&& || !
1、&&(与):碰到假停,先看第一表达式转换成布尔值的结果,如果结果为真,那么会看第二个表达式转换为布尔值的结果,然后如果两个表达式的话,只看到第二个表达式,就可以返回该表达式的值了。以此类推。在充当判断条件时,可称为并且。
var a = 1 && 2;
document.write(a);
2
//undefined, null, NaN, "", 0, false
即如果第一个表达式为真,则返回第二个表达式的值,否则返回第一个表达式的值。
2、||(或):碰到真则停。
var num = 0 || 3;
document.write(num);
3
3、!(非):对目标的布尔值取反。
if语句
基础语法:if(<条件>){######}else if{#####}else{#####}
在使用else if时,<条件>必须互斥。
如:
var score = parseInt(window.prompt('input'))
if(score > 90 && score < 100){
document.write('alibaba');
}else if(score > 80 && score < 90){
document.write('tencent');
}else{
document.write('11111');
}
循环语句
for循环:for(<1>;<跳出条件>;<执行语句>){}其中<1>可放到for前面,<执行语句>可放到{}里。
如:
for(var i = 1; i < 10; i ++){
//省略
}
while循环:while(<条件>){<执行条件>}( 同for循环类似用法)。
如:
var i = 0;
while(i < 100){
if(i % 7 == 0 || i % 10 == 7):
document.write(i + " ");
i ++;
}
do···while循环:没卵用。
条件语句补充
switch case:switch(条件){case <判断>}
当执行成功后,后边的语句会继续执行,可用break来跳出循环。
如:
var n = 3;
switch(n){
case 1:
console.log('a');
break;
case 2:
console.log('b');
case 3:
console.log('c');
}
break:终止循环。
continue:终止此次循环,执行下次循环。
初识引用值
数组(arr):用中括号表示[变量, 变量, 变量······]
长度用arr.length来表示。
对象(object):
如:var obj = {
lastName : “111”;
}
**typeof:**可用来判断变量的类型,可用来返回number, string, boolean, object, undefined, function。
用法:typeof(变量)或typeof 变量,typeof判断未声明的变量并不会报错,返回undefined
typeof(null)返回object
类型转换
类型转换一般没有特别强调都转换为数字,若无法转为数字则转为NaN
除+以外,其余均会把符号两侧的变量转化为数字类型
1、Number(mix)将目标转化为数字类型。
2、parseInt(string, “num”),以目标数字为基底转化为十进制。
3、parseFloat(string)将目标转化为浮点型数字。
4、toString,用法···.toString(),undefined和null不可用。数据.toString(n), 将num转化为n进制数并转换为字符串。
5、String(),将目标转化为字符串。
6、Boolean()转换位布尔类型。
7、isNaN(),判断数据是否为NaN,执行过程为先对数据进行Number()操作,然后将执行后的数据跟NaN进行对比看是否相同。
function(函数)
创建方式:
1、function name(形式参数){};
2、var test = function(形式参数){};又叫函数表达式。
3、var test = function name(形式参数){}; 其中name为test函数的别名,可用test.name进行打印;
调用方法:
test(实际参数)
形参的定义大致同变量的定义(var name)是一个意思。
return:a、终止函数;b、返回值。
str.charAt(num)可用来选择字符串中的某位字符。
str.charcodeAt(num)可以返回字符串中某位字符在ASCII码中的序号,若序号小于等于255则其字节长度为1,否则其字节长度为2。
function mul(n) {
//n的阶乘
if (n == 0) {
return 1;
}
return n * mul(n - 1);
}
function fb(n) {
//斐波那契数列
//fb(n) = fb(n-1) + fb(n-2)
if (n == 1 || n == 2) {
return 1;
}
return fb(n - 1) + fb(n - 2);
}
作用域
当出现嵌套函数的时候,内部函数可以访问外部函数,但外部函数不可以访问内部函数。
预编译(JS的特点:单线程、解释性语言)
//函数声明整体提升:即构建的函数会提升到逻辑的最前边
//变量声明提升
1、暗示全局变量:imply global,即如果变量未经声明就赋值,则该变量就为全局对象所有。
2、一切声明的全局变量,都是window的属性。
预编译过程(预编译发生在函数执行的前一刻/同时发生在全局(区别为全局创建的叫GO(Global Object)对象==window,同AO对象一样))
1、创建AO对象(Active Object)(即执行期上下文)
2、找形参和变量声明,值为undefined
3、将实参值和形参值统一
4、在函数体里找函数声明,值赋予函数体
例:
function fn(a){
console.log(a);
var a = 123;
console.log(a);
function a(){}
console.log(a);
var b = function(){}
console.log(b);
function d(){}
}
fn(1);
//输出为function, 123, 123, function即函数fn中的function a(){}提升到前边
作用域精解
AO数据即时的存储空间,在每次函数执行完成后会被删除
[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合
查找变量时从作用域链的顶端依次向下查找。
例:
function a(){
function b(){}
}
var glob = 100;
a();
//当函数执行时,所产生的AO放在作用域链的最顶端,在使用嵌套函数的时候子函数跟父函数使用的是同一个AO,不过在调用子函数的过程中,将AO的引用指向子函数,在子函数执行完后,AO重新指向父函数
闭包
当内部函数被保存到外部时,会产生闭包,闭包会导致原有作用域链不释放,造成内存泄漏。
例:
function a(){
function b(){
var bbb = 234;
console.log(aaa);
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a();
demo();
内存泄漏:即占用内存多了之后,剩余内存减小
闭包的作用:
1、实现公有变量,如:函数累加器
function add() {
var count = 0;
function demo() {
count++;
return count;
}
return demo;
}
var counter = add();
counter();
2、可以做缓存(存储结构)
function eater(){
var food = "";
var obj = {
eat : function(){
console.log("I am eating " + food)
}
push : function(myfood){
food = myfood;
}
}
return obj;
}
var eater1 = eater();
eater1.push('banana');
eater1.eat();
3、可以实现封装,属性私有化
function Deng(){
var prepareWife = "xiaozhang";
this.name = wife;
this.divorce = function(){
this.wife = prepareWife;
}
this.changePrepareWife = function(target){
prepareWife = target;
}
this.sayPrepareWife = function(){
console.log(prepareWife);
}
}
var deng = new Deng();
//利用deng.prepareWife无法访问到“xiaozhang”
4、模块化开发,防止污染全局变量(命名空间)
闭包在定义过程中不会去访问所要保存的函数体内部的内容,只有在执行的时候才会去访问其函数内部结构。
如:
function test(){
var arr = [];
for(var a = 0; i < 10; i ++){
arr[i] = function b(){
document.write(i + " ");
}
}
return arr;
}
var arr1 = test();
for(var i = 0; i < arr1.length; i ++){
arr1[i]();
}
立即执行函数
仅执行一次便释放空间的函数即为立即执行函数。
创建方式
1、(function(){}())
2、(function(){})()
一般建议使用第一种,立即执行函数的原理同(1 + 2)* 3中括号的作用类似,即利用()的作用来实现执行符号(即函数后边的括号)对函数的调用。
对象(Object)
对象的创建方法:
1、var obj = {} plainObject 对象字面量/对象直接量
2、构造函数
1) 系统自带的构造函数 Object
2) 自定义
如:var obj = new Object();
在使用构造函数创建对象的时,也可通过传形参的形式直接给对象的属性进行赋值。
构造函数自定义采用大驼峰式写法:即每个单词的首字母都用大写字母。
如:function Person(){}
function Car(){
this.name = "BMW";
this.heigth = "1400";
this.lang = "4900";
this.weight = 1000;
this.health = 100;
this.run = function(){
this.health --;
}
}
var car = new Car();
对象属性的修改通过obj. = 来进行修改
对象属性的删除可通过delete obj.
在对象内部修改属性值时可用this. = value来实现
注:在向对象的属性传值时,尽量采用单引号。
构造函数内部原理
1、在函数体最前面隐式的加上this = {};(即var this = {})
2、执行this.xxx = xxx;(即this = {xxx: xxx})
3、隐式的返回this;(即return this)
包装类:使用new创建的数字或字符串、布尔类型数据不仅可当数字或字符串使用,还拥有对象的功能,可以增加属性。
new Number();new String();new Boolean()。
原型
1、原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法,原型也是对象。
原型也是对象即通过<构造函数名>.prototype所打印出的为对象,而用<构造函数名>.prototype.<属性名>打印出来的为原型的属性值。
2、利用原型的特点,可以提取公有属性。
3、注:原型创建后自带constructor属性,其属性值为构造函数名,利用这个属性,可以查看子对象的父类,
4、原型中还会自带一个__proto__属性,这个属性是用来存储对象的原型,子对象可通过该属性替换父对象,即子对象的__proto__指向父对象的prototype,如person.proto = <构造函数名>。
原型的创建方法,<构造函数名>.prototype.<属性名> = “<属性值>”
也可利用对象赋值方式对原型进行属性赋值
如:Person.prototype = {}
构造函数产生的子对象也可以调用其祖先的原型。
如:
Person.prototype.LastName = "Deng";
Person.prototype.say = function(){
console.log("hehe");
}
function Person(name, age, sex){
this.name = name;
this.age = age;
this.sex = sex;
}
var person = new Person('xuming', 35, 'male');
console.log(preson.LastName);
输出结果:Deng
例题:
Person.prototype.name = 'sunny';
function Person(){
}
var person = new Person();
Person.prototype = {
name : 'cherry';
}
console.log(person.name);
//输出为sunny
Person.prototype.name = 'sunny';
function Person(){
}
var person = new Person();
Person.prototype.name = 'cherry';
console.log(person.name);
//输出为cherry
题解:在1中,person对象创建后通过Person.prototype = {name = ‘cherry’}相当于将其原型指向了另外一个空间,而在2中,通过Person.prototype.name = 'cherry’是在原对象的原型属性中进行修改,所以创建的对象也会跟着修改。
其思路同以下代码类似:
obj = {name : 'a'}
obj1 = obj;
obj.name = 'b'/obj = {name : 'b'}
原型链
原型连原型再连原型生成的链式结构即为原型链,通过prototype连接,所有对象的最终原型为Object.prototype
如:
Grand.prototype.lastName = "deng";
function Grand(){
}
var grand = new Grand();
Father.prototype = grand;
function Father(){
}
var father = new Father();
Son.prototype = farher;
function Son(){
}
var son = new Son();
console.log(son.lastName);
Object.create(原型)其中原型值<构造函数名>.prototype
并不是所有的对象都来自于Object.prototype(),如Object.create(null)构造的对象就没有原型。
toString()方法详解:num.toString() -->new Number(num).toString(),Number.prototype中自带toString()方法而Number.prototype.proto = Object.prototype
call/apply
call: 作用为改变this指向,使用:<被调用构造函数名>.call(<对象名>, 参数, 参数··· ···)
可通过其来跨级访问原型中的函数如:Object.prototype.toString.call(123),其执行过程中调用的不是Number.prototype中的toString()方法,而是Object.prototype中的toString()方法。
如:
function Person(name, age){
this.name = name;
this.age = age
}
var person = new Person('deng', 100);
var obj = {}
Person.call(obj, 'cheng', 300);
//this == obj 相当于利用别人的方法执行自己的功能
call也可通过以下方法使用
function Person(name, age, sex){
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name, age, sex, tel, grade){
Person.call(this, name, age, sex);
this.tel = tel;
this.grade = grade;
}
var student = new Student('Sunny', 123, 'male', 122, 2017);
apply: 同call的作用基本一样,
call和apply的区别:(传参列表不同)call需要把实参按照形参的个数传进去,而apply需要传一个arguments,即参数的传递必须是数组(将所有参数构造成一个列表进行参数传递)
例题:
var a = 5;
function test(){
a = 0;
alert(a);
alert(this.a);
var a;
alert(a);
}
//运行test()和new test()的结果分别是什么?
Math.ceil(num)向上取整
Math.floor(num)向下取整
toFixed(n)保留n位有效数字,使用方法:num.toFixed(n)其中n为要保留的位数
JavaScript可正常计算的范围,小数点前16位,小数点后16位
继承发展史
1、传统方式:原型链
缺点:过多的继承了没用的属性
2、借用构造函数(call)
缺点:不能继承借用构造函数的原型
每次构造函数都要多走一个函数
3、共享原型
缺点:不能随便改动自己的原型
例:
Father.prototype.LastName = "Deng";
function Father(){
}
function Son(){
}
Son.prototype = Father.prototype;
function inherit(Target, Origin){
Target.prototype = Origin.prototype;
}
inherit(Son, Father);
4、圣杯模式
通过一个过度的构造函数去继承原对象的原型,如:
Father.prototype.LastName = "Deng";
function Father(){
}
function F(){}
F.prototype = Father.prototype;
function Son(){
}
Son.prototype = new F();
利用函数进行封装
function inherit(Target, Origin){
function F(){}
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constructor = Target;//若没此句,目标函数原型中的constructor指向的为Origin()
Target.prototype.uber = Origin.prototype;//可用来查看其真正继承来自谁,即它的超类。
}
也可用立即执行函数实现属性的私有化,在下边例子中,在生成闭包的过程总,F被私有化。
var inherit = (function (){
var F = function(){};
return function(Target, Origin){
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constructor = Target;
Target.prototype.uber = Origin.prototype;
}
}());
命名空间
管理变量,防止污染全局,适用于模块化开发。
webpack
例
var init = (function(){
var name = 'abc';
function callName(){
console.log(name);
}
return function(){
callName();
}
}())
init();
小知识点:函数在执行完后会默认返回一个undefined
若一个对象中存在多个函数,可通过在每个函数中插入return this来实现连续调用执行的效果,如
var obj = {
smoke : function(){
console.log("smoking....");
return this;
},
perm : function(){
console.log("perm....");
return this;
},
drink : function(){
console.log("drink....");
return this;
}
}
obj.smoke().perm().drink();
对象属性的访问的两种方式,1、obj.<属性名>; 2、obj[‘属性名’],2中的中括号内必须时字符串,因此可以通过字符串拼接的形式来实现一些特定的功能
对象的枚举
小知识:obj.<属性名>------>obj[‘属性名’]
for in循环遍历对象的属性,这里遍历到的属性名权威字符串类型,故在打印过程中必须使用obj[‘属性名’]
1、for in循环遍历会默认将__proto__属性也遍历
可通过if(obj.hasOwnProperty(<属性名>)){}来判断遍历到的属性名是否为自身的方法来跳过原型属性
var obj = {
name : '13',
age : 123,
sex : "male",
height : 100,
weight : 75,
__proto__ : {
lastName : "deng"
}
}
//1、for in循环遍历对象的属性,这里遍历到的属性名权威字符串类型,故在打印过程中必须使用obj['属性名']
for(prop in obj){
if(obj.hasOwnProperty(prop)){
console.log(prop + " " + typeof(prop) + " " + obj[prop]);
}
}
2、in,“属性名” in obj,在判断过程中,其原型的属性也被判定时对象自身的属性(使用很少)
3、instanceof,判断A对象是不是B对象构造出来的
A instanceof B,判断A的原型链上是否存在B的原型
例题讲解
1、参数传递
function foo(){
bar.apply(null, arguments);
}
function bar(){
console.log(arguments);
}
foo(1, 2, 3, 4, 5);
//结果为1 2 3 4 5
2、我是一行文本,需要水平和垂直居中
<div class="didiv">
这是一行文本,我要居中
</div>
<style type="text/css">
.didiv{
height: 500px;
width: 500px;
background-color: silver;
display: table-cell;
padding: 0px;
text-align: center;
vertical-align:middle;
}
</style>
3、parseInt(a, b),以b为基底将a转化为10进制
16进制:1 2 3 4 5 6 7 8 9 a b c d e f(即f代表15,e代表14,d代表13,c代表12,b代表11,a代表10)
4、if括号中的function会转化为表达式,即立即执行函数,在执行过后就找不到f了
var x = 1;
if(function f(){}){
x += typeof f;
}
console.log(x);
//输出1undefined
this
1、预编译过程,this–>window
2、全局作用域里,this–>window
3、call/apply可以改变函数运行时的this指向
4、obj.func();func()里面的this指向obj
例:
var name = "222";
var a = {
name : "111";
say : function(){
console.log(this.name);
}
}
var fun = a.say;
fun();//222
a.say;//111
var b = {
name : "333";
say : function(fun){
fun();
}
}
b.say(a.say);//222
b.say = a.say;
b.say();//333
arguments
1、arguments.callee,代表函数的引用,callee位于哪个函数里边,就指向哪个函数
例:
var test = (function(n){
if(n == 1){
return 1;
}
return n * arguments.callee(n-1);
}(10))
2、caller,返回函数的执行环境,若函数的执行环境为window,则返回null
小例题:克隆
var obj = {
name : 'abc',
age : 123,
sex : 'female'
}
var obj1 = {};
function clone(origin, target){
for(var prop in origin){
if(origin.hasOwnProperty(prop)){
target[prop] = origin[prop];
}
}
}
clone(obj, obj1);
深度克隆
//深度克隆
var obj = {
name : "abc",
age : 123,
card : ['visa', 'master'],
wife : {
name : "bcd",
son : {
name : "aaa"
}
}
}
//1、判断是不是原始值 typeof object
//2、判断是数组还是对象 instanceof() constructor toString
//3、建立相应的数组或对象
function deepClone(origin, target){
var target = target || {},
toStr = Object.prototype.toString,
arrStr = "[object Array]";
for(var prop in origin){
if(origin.hasOwnProperty(prop)){
if(origin[prop] !== "null" && typeof(origin[prop]) == 'object'){
if(toStr.call(origin[prop]) == arrStr){
target[prop] = [];
}else{
target[prop] = {};
}
deepClone(origin[prop], target[prop]);
}else{
target[prop] = origin[prop];
}
}
}
return target;
}
var obj1 = {};
deepClone(obj, obj1);
三目运算符
基本写法:条件判断?是:否,并且会返回值
数组
创建方式:var arr = [];或var arr = new Array(num)
数组常用方法
改变原数组
push,pop,shift,unshift,reverse
1、push,在数组后添加元素
2、pop,剪切数组的最后一位
3、shift,剪切数组第一位
4、unshift,在数组前添加元素
5、reverse,数组反转
6、splice,arr.splice(从第几位开始,截取多少的长度,在切口处添加新的数据)
数组利用负数访问机制:pos += pos > 0 ? 0 : this.length;如负数可以访问倒数第一个位置的元素
7,sort(),arr.sort(function(){})可根据各种规则进行排序
//1.必须写俩形参
//2.看返回值 1)当返回值为负数时,前面的书放在前面
2)为正数,那么后面的数在前
3)为0,不动
即
arr.sort(function(a, b){
if(a > b){
return 1;
}else{
return -1;
}
})
不改变原数组
1、concat,arr1.concat(arr2),作用,将两个数组进行连接
2、toString,将数组变成字符串
3、slice,arr.slice(num1, num2),从num1位开始截取,截取到num2位
arr.slice(num),从num位开始截取,一直截取到最后
arr.slice(),截取整个数组
4、join,arr.join(str),将数组的每一位利用传入的参数连接起来返回一个字符串,同时字符串可利用str.split(str)将字符串拆为数组
字符串是以栈内存存储数据,而数组时以散列形式存储数据的,因此在连接字符串时可利用数组先存储所有字符串,然后通过join函数来实现字符串之间的连接。
类数组
类数组:属性要为索引属性,必须有length属性,最好加上push方法(调用Array.prototype.push来添加)
Array.prototype.push = function(target){
obj[obj.length] = target;
obj.length ++;
}
当给一个对象添加splice方法(Array.prototype.push)后,该对象打印出来同数组基本一致
1、可以利用属性名模拟数组特性
2、可以动态的增长length属性
3、如果强行让类数组调用push()方法,则会根据length属性值的位置进行属性的扩充。
例题:
//数组去重 hash
Array.prototype.unique = function(){
var temp = {},
arr = [],
len = this.length;
for(var i = 0; i < len; i ++){
if(!temp[this[i]]){
temp[this[i]] = 'abc';
arr.push(this[i]);
}
}
return arr;
}
复习:原始值没有属性,str.length—>new String(str).length------------------即为包装类
对象通过在访问原型中的属性时,是通过__proto__来进行访问的
通过var定义的属性较不可配置属性,如var num = 123, 利用delete window.num不可实现
try······catch
相当于python中的try······except
用法try{}catch(e){console.log(e)},try里的代码如果有错误的话并不会报错,会自动跳出,即不执行错误后边的代码
如
try{
console.log('a');
console.log(b);//此处为错误,在执行过程中不会报错,catch会捕捉这个错误然后将这个错误的信息返回给e
console.log('c');
}catch(e){
console.log(e.massage + " " + e.name);//e.name为错误类型,e.massage为错误信息
}
错误的类型:Error.name的六种值对应的信息:
1、EvalError:eval()的使用与定义不一致
2、RangeError:数值越界
3、ReferenceError:非法或不能识别的引用数值
4、SyntaxError:发生语法解析错误
5、TypeError:操作数类型错误
6、URIError:URI处理函数使用不当
es5严格模式
即es3.0和es5.0产生冲突的部分
浏览器是基于es3.0和es5.0新增方法使用的
es5.0严格模式,那么es3.0和es5.0产生冲突的部分就使用es5.0,否则会使用es3.0的
es5.0启用方式,在整个页面的最顶端写上”use strict“;
es5.0启用后,不再兼容es3的一些不规则语法。使用全新的es5方法
es5.0严格模式中变量必须声明,arguments.callee caller等方法不可使用,with(){}不可使用
局部this必须被赋值,赋什么就是什么
拒绝重复属性和参数
eval()
可将字符串当成代码来使用,如var a = 123; eval(“console.log(a);”) //打印123,但在es5严格模式中也禁止使用
with(obj){}
with可将括号中的obj放到其作用域链的最顶端,但由于修改作用域链会严重降低效率,故在es5.0严格模式中禁止使用with(){}
DOM
xml – html – html5
1、DOM–>Document Object Model
2、DOM定义了表示和修改文档所需的方法。DOM对象即为宿主对象,由浏览器厂商定义,用来操作html和xml功能的一类对象的集合。也有人称DOM是对HTML以及XML的标准编程接口。
小案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JS学习(下)</title>
<style>
.content{
display: none;
width: 200px;
height: 200px;
border: 2px solid red;
}
.active{
background-color: yellow;
}
</style>
</head>
<body>
<div class="wrapper">
<button class="active">111</button>
<button>222</button>
<button>333</button>
<div class="content" style="display: block">帅</div>
<div class="content">酷</div>
<div class="content">炫</div>
</div>
<script type="text/javascript">
var btn = document.getElementsByTagName('button');
var div = document.getElementsByClassName('content');
for(var i = 0; i < btn.length; i++){
(function(n){
btn[n].onclick = function(){
for(var j = 0; j < btn.length; j ++){
btn[j].className = "";
div[j].style.display = "none";
}
this.className = "active";
div[n].style.display = "block";
}
}(i))
}
</script>
</body>
</html>
DOM基本操作(查找)
document代表整个文档
选择元素方法
document.getElementsById(),利用元素id值选择标签
document.getElementsByTagName(),利用标签名选择标签
document.getElementsByName(),如,通过name值可以选择input标签
需注意只有部分标签可以加name属性,如表单,表单元素,img,iframe
document.getElementsByClassName(),
.querySelector(),css选择器,可利用css语法进行选择,如var p = document.querySelect(“div > span > p.abc”)
.querySelectorAll(),css选择器,同querySelector类似,选择所有符合标准的标签,返回一个数组,但querySelector选择器为静态的,并非实时,因此在用法上有很多局限。
如:
var div = document.getElementsByTagName("div")[0];
div.style.width = "100px";
div.style.height = "100px";
div.style.backgroundColor = "red";
小提示:写网页尽量不用id选择器(如section标签在代码整合过程中会通过id进行抽取,抽取后更换id名称,多个id可能会导致功能失效)
遍历节点树
.parentNode -->父节点
.childNode -->子节点们
.firstChild -->第一个子节点
.lastChild -->最后一子节点
.nextSibling -->下一个兄弟节点
.previousSibling ->前一个兄弟节点
基于元素节点的遍历树
parentElement -->返回当前元素的父节点
children -->只返回当前元素的元素子节点
firstElementChild
lastElementChild
nextElementSibling/previousElementSibling
节点的四个属性
nodeName,元素的标签名,以大写的形式表示,只读
nodeValue,Text节点或Comment节点的文本内容,可读写
nodeType,该节点的类型,只读
attributes,Element节点的属性集合
每个节点都有一个方法:Node.hasChildNodes()返回布尔值
节点的类型
元素节点 --------1(nodeType返回值)
属性节点 --------2
文本节点 --------3
注释节点 --------8
document --------9
DocumentFragment --------11
document --> HTMLDocument.prototype --> Document.prototype
1、getElementById方法定义在Document.prototype上,即Element节点上不能使用。
2、getElementsByName方法定义在HTMLDocument.prototype上,即非html中的document以外不能使用(xml document,Element)
3、getElementsByTagName方法定义在Document.prototype 和 Element.prototype上
var div = document.getElementsByTagName("*")可选择所有标签
4、HTMLDocument.prototype定义了一些常用的属性,body,head,分别指代HTML文档中的标签。即document.body即为标签,document.head即为标签
5、Document.prototype上定义了documentElement属性,指代文档的根元素,在HTML文档中,他总是指代元素(document.documentElement)
6、getElementsByClassName、querySelectorAll、querySelector在Document,Element类中均有定义
DOM基本操作(增,插,删,替换)
增
1、document.createElement(),创建元素节点
2、document.createTextNode(),创建文本节点
3、document.createComment(),创建注释节点
插
1、PARENTNODE.appendChild();向节点中插入子节点
2、PARENTNODE.insetBefore(a, b),把a插入到b前
删
1、parent.removeChild(),删除子节点(谋杀),也可通过var xxx = parent.removeChild()将节点保存下来
2、child.remove(),节点销毁自身(自尽)
替换
parent.replaceChild(new, origin),用新元素替换老元素,可返回一个节点,即老元素被剪切出来了
DOM基本操作(Element)
Element节点的一些属性
1、.innerHTML,可读取或修改元素的html内容
2、.innerText,(火狐浏览器不兼容/textContent(老版本IE不好使))读取或修改元素的文本内容,若元素中还有其他节点,修改元素内容时会覆盖掉原有节点,需谨慎使用
Element节点的一些方法
1、.setAttribute(属性名,属性值),为元素添加属性
2、.getAttribute(属性值),获取元素属性,
经典例题
1、利用原型链封装实现元素.insertAfter(),原理为通过insertBefore()完成在当前元素后一个元素节点的前面插入该元素
<div>
<i></i>
<b></b>
<span></span>
</div>
<script>
Element.prototype.insertAfter = function(targetNode, afterNode){
var beforeNode = afterNode.nextElementSibling;
this.insertBefore(targetNode, beforeNode);
if(beforeNode == null){
this.appendChild(targetNode);
}
}
var div = document.getElementsByTagName('div')[0];
var b = document.getElementsByTagName('b')[0];
var p = document.createElement('p');
var span = document.getElementsByTagName('span')
</script>
2、标签逆序
从倒数第二个标签开始利用appendChild()方法依次将元素剪切到父元素内
<div>
<i></i>
<b></b>
<span></span>
</div>
<script>
var div = document.getElementsByTagName('div')[0];
len = div.children.length;
for(var i = len-2; i >= 0; i --){
div.appendChild(div.children[i]);
}
</script>
Date对象
Date对象属性:constructor和prototype
Date对象方法:
Date对象创建后记录创建时的时间
1、Date(),返回当前日期和时间
2、getDate(),返回当日是本月的第几天
3、getDay(),返回当日是本周的第几天,周末返回数字为0
4、getMonth(),返回月份(0~11)
5、getFullYear(),返回年份
6、getHours(),返回Date对象的小时(0~23)
7、getMiniutes(),返回Date对象的分钟(0~59)
8、getSeconds(),返回Date对象的秒(0~59)
9、getTime(),返回1970年1月1日(纪元时间)至今的毫秒数,可用来计算时间戳
上述方法均可用set进行使用,如setDate(),可以设置日期,若超过30则推到下个月
定时器
<script type="text/javascript">
var date = new Date();
date.setHours(17);
date.setSeconds(0);
date.setMinutes(0);
setInterval(function (){
if(new Date().getTime() - date.getTime() > 1000){
console.log('现在是下午五点钟');
}
},1000)
</script>
10、toString(),将date转化为字符串
11、toTimeString(),将时间部分转化为字符串
12、定时器setInterval(function(){}, time),每隔time时间就执行一次,其中time以毫秒为单位,且在使用自定义time时,定时器只对time识别一次。
注:定时器不准
13、clearInterval每个setInterval()都会返回一个数作为自己的特定标识timer,可通过clearInterval(timer)来停止定时器的运行。如:
var i = 0;
var timer = setInterval(function(){
console.log(i++);
if(i > 10){
clearInterval(timer);
}
}, 10)
14、setTimeout(function(){},time),延时运行,即推迟time时间后再执行
15、clearTimeout(timer),与clearInterval类似,即去掉延迟运行
全局window上的方法,this指向window
例子:计时器(记录三分钟后停止)
<style type="text/css">
input{
border: 1px solid rgba(0,0,0,0.8);
text-align: right;
font-size: 15px;
font-weight: bold;
}
</style>
minutes:<input type="text" value="0">
seconds:<input type="text" value="0">
<script type="text/javascript">
var minutesNode = document.getElementsByTagName("input")[0];
var secondsNode = document.getElementsByTagName("input")[1];
var minutes = 0,
seconds = 0;
timer = setInterval(function (){
seconds ++;
if(seconds === 60){
seconds = 0;
minutes ++;
}
secondsNode.value = seconds;
minutesNode.value = minutes;
if(minutes === 3){
clearInterval(timer);
}
}, 1000);
</script>
DOM基本操作(理解,后续使用会封装)
1、查看滚动条的滚动距离,
window.pageXOffset/pageYOffset IE8及IE8以下不兼容
2、IE8及IE8以下不兼容(a兼容时b必不兼容,b兼容时a必不兼容因此用的过程中通过取两个值相加来解决兼容性混乱的问题):
a),document.body.scrollLeft/scrollTop
b),document.documentElement.scrollLeft/Top
如(将获取滚动距离封装成一个函数):
function getScrollOffset(){
if(window.pageXOffset){
return {
x : window.pageXOffset,
y : window.pageYOffset
}
}else{
return {
x : document.body.scrollLeft + document.documentElement.scrollLeft,
y : document.body.scrollTop + document.documentElement.scrollTop
}
}
}
3、查看可视区窗口尺寸
window.innerWidth/window.innerHeight IE8以及IE8以下不兼容
document.documentElement.clientWidth/clientHeight 标准模式下任意浏览器都兼容
document.body.clientWidth/clientHeight 适用于怪异/混杂模式下的浏览器
例:查看可视区窗口尺寸封装函数
function getViewportOffset(){
if(window.innerWidth){
return {
w : window.innerWidth,
h : window.innerHeight
}
}else{
if(document.compatMode === "BackCompat"){
return {
w : document.body.clientWidth,
h : document.body.clientHeight
}
}else{
return {
w : document.documentElement.clientWidth,
h : document.documentElement.clientHeight
}
}
}
}
4、查看元素的几何尺寸
domEle.getBoundingClientRect() 兼容性很好,返回结果并不是实时的
5、查看元素的尺寸
dom.offsetWidth/Heigth 获取元素的宽和高
6、查看元素的位置
dom.offsetTop/Left,嵌套div所求的结果为相对于其所在父级元素的位置,而不是整个页面
对于无定位父级的元素,返回相对文档的坐标。对于有定位父级的元素,返回相对于最近的有定位的父级的坐标
html中会有一个默认的margin = 8px
dom.offsetParent,返回最近的有定位的父级,如无,返回body,body.offsetParent返回null
7、让滚动条滚动
window上有三个方法:window.scroll(),window.scrollTo(),scrollBy(),其中scroll和scrollTo没有任何差别,都是滚动到(x, y)距离,而scrollBy()是相对于当前位置进行滚动,即累加滚动距离
例:自动阅读实现
<div class="stop" style="width: 100px; height: 100px; background-color: red;
color: black; font-size: 40px; text-align: center; line-height: 100px;
position: fixed; bottom: 200px; right: 50px; border-radius: 50%; opacity: 0.7;
font-weight: bold">
stop
</div>
<div class="start" style="width: 100px; height: 100px; background-color: chartreuse;
color: black; font-size: 40px; text-align: center; line-height: 100px;
position: fixed; bottom: 320px; right: 50px; border-radius: 50%; opacity: 0.7;
font-weight: bold">
start
</div>
<script>
var start = document.getElementsByClassName('start')[0];
var timer = 0;
var key = true;
start.onclick = function(){
if (key){
timer = setInterval(function (){
window.scrollBy(0, 5);
}, 100)
key = false;
}
}
var stop = document.getElementsByClassName('stop')[0];
stop.onclick = function(){
clearInterval(timer);
key = true;
}
</script>
脚本化CSS(须记)
1、读写css属性
dom.style.prop
可读写行间样式,没有兼容性问题,碰到样式名称是用“-”连接的,改用小驼峰式,碰到float这样的保留字属性,前面加css,如:dom.style.float应该为dom.style.cssFloat
2、查询计算样式(获取css属性)
window.getComputedStyle(ele, null),返回的为最终展示样式值,以类数组形式返回,括号中的第二个参数null位置为伪元素
计算样式只读,返回的计算样式的值都是绝对值,没有相对单位,IE8以及IE8以下不兼容
ele.currentStyle,计算样式只读,返回的计算样式的值不知经过转换二等绝对值,IE独有的属性
函数封装(获取css属性)
function getStyle(elem, prop){
if(window.getComputedStyle){
returm window.getComputedStyle(elem, null)[prop];
}else{
return elem.currentStyle[prop];
}
}
window.getComputedStyle(ele, null)可用来查看为元素的样式属性,其中null为伪元素的名称
例子:小方块运动
<div style="width: 100px; height: 100px; background-color: red; position: absolute; left: 0; top: 0"></div>
<script type="text/javascript">
function getStyle(elem, prop){
if(window.getComputedStyle){
return window.getComputedStyle(elem, null)[prop];
}else{
return elem.currentStyle[prop];
}
}
var div = document.getElementsByTagName('div')[0];
var speed = 1;
var timer = setInterval(function(){
speed += speed/20;
div.style.left = parseInt(getStyle(div, 'left')) + speed + 'px';
if (parseInt(div.style.left) > 500){
clearInterval(timer);
}
}, 10)
</script>
事件
如何绑定事件处理函数
1、ele.onxxx = function(event){}
兼容性很好,但是一个元素的同一个事件上只能绑定一个处理函数
基本等同于写在HTML行间上
2、obj.addEventListener(事件类型, function, false);第一个参数为事件类型,第二个参数为事件处理函数
IE9以下不兼容,一个事件可以绑定多个事件处理函数,并且按照绑定顺序依次执行
3、attachEvent(‘on’ + 事件类型, function)
IE独有,一个事件同时可以绑定多个处理程序
例:绑定事件用到for循环时,需考虑闭包问题,可采用立即执行函数来解决
<ul>
<li>a</li>
<li>a</li>
<li>a</li>
<li>a</li>
</ul>
<script>
var liCol = document.getElementsByTagName('li'),
len = liCol.length;
for (var i = 0; i < len; i++){
(function(i){
liCol[i].addEventListener('click', function(){
console.log(i + 1);
})
}(i))
}
</script>
事件处理程序的运行环境
1、ele.onxxx = function(event){}
程序this指向的是dom元素本身
2、obj.addEventListener(type, fn, false)
程序this指向的是dom元素本身
3、obj.attachEvent(‘on’ + type, fn)
程序this指向window
封装兼容性的handle()方法
function addEvent(elem, type, handle){
if(elem.addEventListener){
elem.addEventListener(type, handle, false)
}else if(elem.attachEvent){
elem.attachEvent('on' + type, function(){
handle.call(elem);
})
}else{
elem['on' + type] = handle
}
}
function handle(){}//handle函数为要绑定的函数
解除绑定事件处理函数
1、ele.onclick = null/false
2、ele.removeListener(type, fn, false)
3、ele.detachEvent(‘on’ + type, fn)
若绑定函数为匿名函数,则无法解除
事件处理模型–冒泡、捕获
1、事件冒泡:**结构上(非视觉上)**嵌套关系的元素,会存在事件冒泡的功能,即同一事件,自子元素冒泡向父元素。(自底向上)
如:三个嵌套的div各自绑定自己的事件函数,在执行最内部事件函数时,会自底向上冒泡,分别执行外部事件函数
2、事件捕获: **结构上(非视觉上)**嵌套关系的元素,会存在事件捕获的功能,即同一时间,自父元素捕获至子元素(事件源元素)。(自顶向下)
IE没有捕获事件,事件捕获实现方法,将addEventListener中的false改为true
3、触发顺序,先捕获后冒泡
4、focus,blur,change,submit,reset,select等事件不冒泡
取消冒泡和阻止默认事件
1、取消冒泡
W3C标准“:ele.stopPropagation(),但不支持ie9以下版本
IE独有:event.cancelBubble = true;
封装取消冒泡的函数stopBubble(event)
function stopBubble(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
2、阻止默认事件
1、return false,以对象属性的方式注册的事件才生效。如:oncontextmenu,右键出菜单方法
<script type="text/javascript">
document.oncontextmenu = function(){
console.log('a');
return false;
}
</script>
2、event…preventDefailt(),W3C标准,IE9以下不兼容
3、event.returnValue = false,兼容IE
封装阻止默认事件的函数cancelHandle(event)
function cancelHandle(event){
if(e.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
}
标签中可以直接写入JavaScript代码如
<a href="javascript:alert('a')">demo</a>
<a href="javascript:void('a')">demo</a> //在void中写入内容相当于写返回值,作用同return一样,可通过void(false)来取消默认事件
<a href="#">demo</a> //当<a>标签中的地址名称为#时,该标签有一个默认事件为跳转到当前页,可通过void(false)来取消默认事件
事件对象
event || window.event用于IE
事件源对象:即事件对象中的target属性
事件委托
利用事件冒泡,和事件源对象进行处理
优点:
1、性能 不需要循环所有元素一个个绑定事件
2、灵活 当有新的子元素时不需要重新绑定事件
例子
<script>
var ul = document.getElementsByTagName('ul')[0];
ul.onclick = function (e){
var event = e || window.event;
var target = event.target || event.srcElement;
console.log(target.innerText);
}
</script>
事件分类
1、鼠标事件
click、mousedown、mouseup、mousemove(鼠标移动事件)、contextmenu(右键产生菜单事件)、mouseover、mouseout、mouseenter、mouseleave
click相当于mousedown加上mouseup
onmouseover为鼠标放到元素上时产生的事件,onmouseout为当鼠标离开元素时产生的事件
HTML5新规范中将onmouseover和onmouseout改名为onmouseenter和onmouseleave
2、用button来区分鼠标的左右键(0/1/2,仅onmousedown和onmouseup可区分):e.button的值0时为鼠标左键,e.button的值为1时为滚轮,e.button的值为2时为右键,DOM3标准规定:click事件只监听左键
<script>
document.onmousedown = function (e){
if (e.button === 0){
console.log('left');
}else if(e.button === 1){
console.log('middle');
}else{
console.log('right');
}
}
</script>
例子:解决mousedown和click的冲突(利用点击时长通过key来控制事件的发生)
<script type="text/javascript">
var key = false;
var firstTime = 0;
var lastTime = 0;
document.onmousedown = function (){
firstTime = new Date().getTime();
}
document.onmouseup = function () {
lastTime = new Date().getTime();
if(lastTime - firstTime < 300){
key = true;
}
}
document.onclick = function (){
if (key){
console.log('click');
key = false;
}
}
</script>
键盘类事件
1、keydown、keypress、keyup
keydown>keypress>keyup
keydown和keypress的区别:keydown可以响应任意按键,keypress只能响应字符类按键
若要监听字符串按键且要区分大小写,用keypress
keypress返回ASCII码,可转为字符串
文本类事件
1、input.oninput,input输入框内文本变化时触发
2、input.onchange,输入框在聚焦和上次失去焦点这两个状态内容有所不同时触发 若输入框内容无变化则不触发
3、onfocus,输入框聚焦点时触发,onblur,输入框失去聚焦点时触发
例:输入框的实现
<input type="text" value="请输入关键字" name="SerchKey" class="inp-txt"
onfocus="if (this.value=='请输入关键字'){this.value='';}"
onblur="if(this.value==''){this.value='请输入关键字';}">
窗体操作类(window上的事件)
scroll,滚动条滚动时触发
load,window.onload = function 页面加载完再执行
json
JSON是一种传输数据的格式(以对象为样板,本质上就是对象,但用途有区别,对象就是本地用的,json是用来传输的)
JSON.parse(),string——>json
JSON.stringfy(),json——>string
htmlTree遵循广度优先原则,domTree遵循深度优先原则,cssTree也为深度优先原则
domTree + cssTree = randerTree
domTree或cssTree的改变都会使randerTree改变,
1、reflow 重排,dom节点的删除,添加,dom节点的宽高变化,位置变化,display none——>block,offsetWidth offsetLeft
2、repaint 重绘,css颜色等的改变,重绘浪费的效率较少
dom树的完成代表所有节点的解析完毕
异步加载JS
js加载的缺点:加载工具方法没必要阻塞文档,过多js加载会影响页面效率,一旦网速不好,那么整个网站将等待js加载而不进行后续渲染工作等。
有些工具方法需要按需加载,用到在加载,不用不加载。
异步加载的三种方案:
1、defer异步加载,但要等到dom文档全部解析完才会被执行,只有IE能用,也可以将代码写到内部。
用法:在script标签中添加defer="defer"如:
<script type="text/javascript" defer="defer"></script>
2、async异步加载,加载完就执行,async只能加载外部脚本,不能把js写在script标签里。
用法:在script标签中添加async="async"如:
<script type="text/javascript" async="async"></script>
1和2执行不阻塞页面。
3、**创建script,插入到DOM中,加载完后callBack。**如:为确保加载完script文件后再执行,可利用onload方法,而IE中则通过readyState状态码来解决。
<script>
function loadScript(url, callback){
var script = document.createElement('script');
script.type = 'text/javascript';
if(script.readyState){
script.onreadyStatechange = function(){
if(script.readyState == "complete" || script.readyState == "loaded"){
callback();//IE中的解决方案
}
}
}else{
script.onload = function(){
callback(); //test为tool.js中的方法,load事件IE中不兼容
}
}
script.src = url;
document.head.appendChild(script);
}
loadScript('demo.js','function(){test();}');
</script>
js加载时间线
1、创建Document对象,开始解析web页面,解析HTML元素和他们的文本内容后添加Element对象和Text节点到文档中,这个阶段document.readyState = ‘loadiing’。
2、遇到link外部css,创建线程加载,并继续解析文档。
3、遇到script外部js,并且没有设置async、defer,浏览器加载,并阻塞,等待js加载完成并执行该脚本,然后继续解析文档。
4、遇到script外部js,并且设置有async、defer,浏览器创建线程加载,并继续解析文档。
对于async属性的脚本,脚本加载完成后立即执行,而defer属性的脚本要等待解析完才执行。(异步禁止使用document.write())
5、遇到img等,先正常解析dom结构,然后浏览器异步加载src,并继续解析文档。
6、当文档解析完成,document.readyState = ‘interactive’。
7、文档解析完成后,所有设置有defer的脚本会按照顺序执行。(注意与async的不同,但同样进制使用document.write())
8、document对象触发DOMContentLoaded事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段。
9、当所有async的脚本加载完成并执行后、img等加载完成后,document.readyState = ‘complete’。window对象触发load事件。
10、从此,以异步相应方式处理用户输入,网络事件等。
正则表达式(RegExp)
补充:
1、转义字符:\,可将反斜杠后的字符转为文本"ab\'cd"打印为ab’cd,\n为换行,\t代表table(一个table相当于四个空格),\r为行结束。
2、多行字符串,
3、字符串换行符,\n
正则表达式两种创建方式
1、直接量
如:var reg = /xxxxxx/;再第二个/后可加i/g/m,其中i(ignorCase)为忽视大小写;g为全局匹配;m为多行匹配。
2、new RegExp();
如:var reg = new RegExp(“xxx”, “i/g/m”);
var reg1 = new RegExp(reg);会创建两个相互独立的正则表达式,去掉new的话,reg和reg1就指向同一个正则表达式。
注:推荐直接量
正则表达式的作用:匹配特殊字符或有特殊搭配原则的字符的最佳选择。
正则表达式中的方法:
reg.test();返回Boolean值,表示是否匹配到 str.match();返回匹配到的所有字符串,以数组的形式展示。
1、方括号(表达式,每个方括号代表一个字符)
^放到表达式外表示以什么开头,放到[ ]里表示非,如[abc]查找方括号之间的任何字符, [^abc]查找任何不在方括号之间的字符,(red|blue|green)查找任何指定的选项。表达式里还可写入元字符
n$表示以某字符结尾
2、元字符(拥有特殊含义的字符)
\w,相当于[0-9A-z_]
\W,相当于[^\w]
\d,相当于[0-9]
\D,相当于[^d]
\s,查找空白字符,空白字符可以是(空格符,制表符\t,换行符\n,换页符\f,回车符\r)
\b,单词边界
\B,非单词边界
\v,查找垂直制表符
\uxxxx,匹配Unicode编码字符
. ,匹配字符串中出了行结束符\n和换行符\r外的所有字符
可利用 [\w\W] 或 [\d\D] 或 [\s\S] 等组合方法来匹配任意字符
3、量词
n+,匹配1-正无穷个某字符
n*,匹配0-正无穷个某字符(正则表达式遵循贪婪原则,匹配不到字符时,会返回一个逻辑空串)
如:
<script>
var reg = /\d*/g;
var str = "ab12c3d";
console.log(str.match(reg));
</script>
//返回为["", "", "12", "", "3", "", ""]
n?,匹配0-1个某字符
n{X},匹配x个连续的某字符
n{x, y},匹配x-y个连续的某字符
n{x, },匹配x-正无穷个连续某字符
4、RegExp对象属性
global,RegExp对象是否具有标志g
ignoreCase,RegExp对象是否具有i
multiline,是否有多行
source,返回正则表达式源文本
lastIndex,
5、RegExp方法
test,检验一个字符串中是否有与所创建的正则表达式相匹配的部分,返回为Boolean值
exec,与reg.lastIndex配合使用,当进行全局匹配时,游标(lastIndex)随着匹配次数向后推移,如:
var reg = /ab/;
var str = "abababab";
console.log(reg.lastIndex);
console.log(reg.exec(str));
console.log(reg.lastIndex);
//返回为0 lastIndex为0的类数组 2
compile,
扩展:()可用作子表达式,如reg = /(\w)\1\1\1/,用来匹配连续的四个0-9A-z的字串,其中\n表示与第n个子表达式中一样的元素。
在使用exec匹配时,返回类数组中会罗列出每个子表达式匹配到的字串
6、string方法
match,全局匹配时,只返回匹配结果,非全局匹配时,返回同exec方法的返回结果类似。
search,若能匹配到,返回匹配到的字串在源字符串中的位置,否则,返回-1
split,拆分字符串,括号中可写入RegExp,当括号中为正则表达式子表达式时,返回数组中同样会返回子表达式中的内容。
replace(str1, str2),将字符串中的str1元素替换为str2元素,正常情况下只会匹配字符串中的第一个元素,而当str1为全局匹配的正则表达式时,会被全替换掉
如:var str = “aa”; str.replace(“a”, “b”),打印结果为ba,str.replace(/a/g, “b”),打印结果为bb
var reg = /(\w)\1(\w)\2/;
var str = "aabb";
str.replace(reg, "$2$2$1$1")
//打印结果为bbaa,其中$n表示第n个子表达式所匹配到的内容,若要将字符串中的内容替换为$,应写为$$,与\\类似
toUpperCase()和toLowerCase(),为字符串大写化和字符串小写化
var str = "the-first-name";
var reg = /-(\w)/;
console.log(str.replace(reg, function($, $1){
return $1.toUpperCase();
}))
正向预查/正向断言,如:
var str = "abaaaaa";
var reg = /a(?=b)/g;//匹配任何其后紧接指定字符串n的字符串
console.log(str.match(reg));
//打印为["a"]
var reg = /a(?!b)/g;//匹配任何其后没有紧接指定字符串n的字符串
console.log(str.match(reg));
//打印为["a", "a", "a", "a", "a"]
贪婪匹配和非贪婪匹配,如n+,n*,n?,{x, y},遵循尽可能多的匹配,/n+?/,表达式中的?作用为打破贪婪匹配,即遵循尽可能少的匹配
例题:
<script>
var str = "100000000000";
var reg = /(\B)(?=(\d{3})+$)/g;
console.log(str.replace(reg, ","));
</script>
//打印结果为100,000,000,000
其中可能会有一些小错误,见谅!