组件化网页开发JS
2020-04-29 15:51:59 4 举报
AI智能生成
个人前端学习
作者其他创作
大纲/内容
作用域与解析机制
变量的作用域(变量起作用的区域或范围)
可理解为:变量的生命周期、在哪能访问到变量
可理解为:变量的生命周期、在哪能访问到变量
1、全局作用域:处于全局作用域的变量叫做全局变量 全局变量在所有区域都可访问【当所有程序都执行完毕之后,全局作用域销毁,全局变量才会挂掉,生命力很顽强】
2、局部作用域:处于局部作用域的变量叫局部变量 局部变量只能在局部访问【局部变量只有函数执行的时候才能存活,该函数执行完毕后立马就会挂掉,它的生命力比较弱】
【局部作用域在js中主要指函数作用域,因为js中没有块级作用域。
块作用域由 { } 包括,块作用域内声明的变量生于这个块死于这个块,在整个块里它都有定义,但是出了这个块它就没有定义了。类似于if语句和for语句里面的{ }。if和for中的花括号都是全局作用域。】
【局部作用域在js中主要指函数作用域,因为js中没有块级作用域。
块作用域由 { } 包括,块作用域内声明的变量生于这个块死于这个块,在整个块里它都有定义,但是出了这个块它就没有定义了。类似于if语句和for语句里面的{ }。if和for中的花括号都是全局作用域。】
不用var声明的变量是全局变量
变量对象和作用域链
【变量对象】:执行上下文和作用域链中间的桥梁
例 var one={ };
one.sex='male';
with(one){name='xh';};
例子当中的one就是变量对象,
例 var one={ };
one.sex='male';
with(one){name='xh';};
例子当中的one就是变量对象,
【作用域链】:用于查找对象
查找对象是沿着作用域链进行的。
查找速度:局部变量>全局变量
查找对象是沿着作用域链进行的。
查找速度:局部变量>全局变量
解析机制
【JS解析机制】
第一步:预解析
第二步:逐行解析
第一步:预解析
第二步:逐行解析
js的预解析
有var 的都为undefined
函数function会跳过,但是函数里面的(argument)是undefined
有var 的都为undefined
函数function会跳过,但是函数里面的(argument)是undefined
注意
1:预解析时如果变量名冲突(重复),后面的变量名会覆盖前面的
2、预解析时如果变量名和函数名冲突,函数名会覆盖掉变量名
3、预解析时如果函数名和函数名冲突,谁在后面的时候保留谁
if或者for里面定义函数,在老版本浏览器中会不能预解析,造成错误,所以不必推荐在if或者for里面定义函数。
1:预解析时如果变量名冲突(重复),后面的变量名会覆盖前面的
2、预解析时如果变量名和函数名冲突,函数名会覆盖掉变量名
3、预解析时如果函数名和函数名冲突,谁在后面的时候保留谁
if或者for里面定义函数,在老版本浏览器中会不能预解析,造成错误,所以不必推荐在if或者for里面定义函数。
1. 以var 声明的变量 会预解析
2. 以let 声明的变量 不会进行预解析
3. 函数的声明会预解析
4. 函数表达式不进行预解析
2. 以let 声明的变量 不会进行预解析
3. 函数的声明会预解析
4. 函数表达式不进行预解析
正式解析时是按顺序解析的
在调用函数中如果不是匿名函数【fn(argument)】,并且全局变量有赋值,那么会直接呗函数调用,但是,局部变量是逃离不了函数本身,所以在window里面的console.log()会用全局变量的赋值
在调用函数中如果不是匿名函数【fn(argument)】,并且全局变量有赋值,那么会直接呗函数调用,但是,局部变量是逃离不了函数本身,所以在window里面的console.log()会用全局变量的赋值
对象
js中的对象:
值得集合
1.对象是由多个属性(属性名:属性值)构成的--- 可包括基本类型(字符串、数值等)和引用类型(数组、对象、函数等)
2.多个属性用逗号隔开
值得集合
1.对象是由多个属性(属性名:属性值)构成的--- 可包括基本类型(字符串、数值等)和引用类型(数组、对象、函数等)
2.多个属性用逗号隔开
【创建对象】
第一种:var 名字{属性:值,属性:值,属性:值};
第二种:构造函数创建对象: var one=new Object
第三种:Object.create( );存在浏览器兼容性,不建议使用;
第一种:var 名字{属性:值,属性:值,属性:值};
第二种:构造函数创建对象: var one=new Object
第三种:Object.create( );存在浏览器兼容性,不建议使用;
2.修改对象中的属性值,用英文句号取出。也可设置新的属性。
cat.name="Tim" 或者cat[ "name"}="Tim" 两者相等。
cat.type="布偶猫'..
若既不赋值也不创建新属性,用英文句号表示将其属性值读取。
cat.name="Tim" 或者cat[ "name"}="Tim" 两者相等。
cat.type="布偶猫'..
若既不赋值也不创建新属性,用英文句号表示将其属性值读取。
3.删除对象属性:
delete cat.type 表示删除cat的type属性。
delete cat.type 表示删除cat的type属性。
4.检测对象属性是否存在,使用in方法:
“name”in cat 表示“name”这个属性是否存在cat对象中,属性 in 对象 检测结果为 true || false
“name”in cat 表示“name”这个属性是否存在cat对象中,属性 in 对象 检测结果为 true || false
5.遍历对象属性(对象cat):使用 for in
for(var p in cat) //遍历对象属性
{
console.log(p);//输出属性名;
console.log(cat[p]);// return > p:AAA; 这是我们想要的结果--现将p这个变量的值计算出来,然后再到变量中查找
}
Obj.p 只能表示字符串
Obj[p] 功能更强大,甚至可以进行运算
for(var p in cat) //遍历对象属性
{
console.log(p);//输出属性名;
console.log(cat[p]);// return > p:AAA; 这是我们想要的结果--现将p这个变量的值计算出来,然后再到变量中查找
}
Obj.p 只能表示字符串
Obj[p] 功能更强大,甚至可以进行运算
返回值
参数:函数的输入
返回值:函数的输出
1、return含义:(1)结束(2)将值返回
2、return在函数中使用,表示函数的返回;
continue在循环中使用,表示跳出本次循环而不是跳出整个循环;
break用在循环中,表示跳出整个循环
返回值:函数的输出
1、return含义:(1)结束(2)将值返回
2、return在函数中使用,表示函数的返回;
continue在循环中使用,表示跳出本次循环而不是跳出整个循环;
break用在循环中,表示跳出整个循环
什么可以作为返回值
数据都可做返回值
如果没有返回值,默认返回undefined
什么都不写和只写return结果一样,都返回undefined
但是return还有另外一个作用,可以提前退出函数
如果没有返回值,默认返回undefined
什么都不写和只写return结果一样,都返回undefined
但是return还有另外一个作用,可以提前退出函数
1、数字做返回值
2、字符串做返回值
alert(字符串)期望接受字符串,如果不是字符串,会强制转化为字符串再输出
当打印数组、对象、函数时,就会调用它们的toString()方法,将它们转为字符串形式输出
当打印数组、对象、函数时,就会调用它们的toString()方法,将它们转为字符串形式输出
3、布尔值:return true/false,
表单验证 if(用户名不存在){return true;}else{return false;}
表单验证 if(用户名不存在){return true;}else{return false;}
4、undefined【就是一开始提到的,什么都不写或者只写return】
5、null:return null;
6、返回数组
function add(num1,num2){
return [num1+num2, num1, num2];
}
function add(num1,num2){
return [num1+num2, num1, num2];
}
7、返回对象:
function getPerson(){
return {
name:'xm',
age:17
};
}
function getPerson(){
return {
name:'xm',
age:17
};
}
【这里要注意:return后面的那个左花括号‘{’如果写在下一行,那么会报错,因为js解析器会自动在最后没有写分号的语句后面加一个分号,这样就会导致函数提前结束了】
8、函数作为参数传参;
【为了写出更好更优雅的函数,会将函数作为参数传到另一个函数中,组成一个新功能函数,这个新函数就具有了两个功能:(1)传进来的函数功能(2)接收函数的功能】
【为了写出更好更优雅的函数,会将函数作为参数传到另一个函数中,组成一个新功能函数,这个新函数就具有了两个功能:(1)传进来的函数功能(2)接收函数的功能】
DOM方法
querySelector() 获取指定元素中的第一个元素。
querrySelectorAll()获取指定的全部元素。
js在dom上取到的是字符串,想要做数值的运算操作中的加法操作,就会形成字符串拼接,那么就达不到数值相加的操作了。解决办法是在其前面添加一元运算符,加号+,表示取正,将其强制转换为数字,从而使其可以执行运算操作
querrySelectorAll()获取指定的全部元素。
js在dom上取到的是字符串,想要做数值的运算操作中的加法操作,就会形成字符串拼接,那么就达不到数值相加的操作了。解决办法是在其前面添加一元运算符,加号+,表示取正,将其强制转换为数字,从而使其可以执行运算操作
id就前面加#,class就前面加.
继承
原型继承
原型和原型链
原型:是利用prototype添加属性和方法
原型:是利用prototype添加属性和方法
原型链:JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数的原型对象prototype。
创建对象都分为三步:
1、var p={}; 创建对象
2、p.__proto__=person,prototype prototype是person里面代表对象的值,__proto__是它自带的一个属性
3、创建对象(初始化对象)p 这一步其实是调用person里面的call方法【person.call(p)】
1、var p={}; 创建对象
2、p.__proto__=person,prototype prototype是person里面代表对象的值,__proto__是它自带的一个属性
3、创建对象(初始化对象)p 这一步其实是调用person里面的call方法【person.call(p)】
原型链
对象实例.__proto__等同于对象.prototype
调用p.name,person里面若没有name这个属性,则会去p.__proto__中查找;而__proto__也是一个对象,就会取查找p.__proto__.__proto__,如果还没有就继续往下找,以此类推就会一直往下找__proto__,这样就形成了原型链。
对象实例.__proto__等同于对象.prototype
调用p.name,person里面若没有name这个属性,则会去p.__proto__中查找;而__proto__也是一个对象,就会取查找p.__proto__.__proto__,如果还没有就继续往下找,以此类推就会一直往下找__proto__,这样就形成了原型链。
构造函数继承
说明:
1、在子类内部构造父类的对象实现继承
2、在里面用this关键词来定义属性或方法
3、对象内置方法中的apply和call都可以用于继承,区别在于传参方式不同【区别示例见下方例子2】
1、在子类内部构造父类的对象实现继承
2、在里面用this关键词来定义属性或方法
3、对象内置方法中的apply和call都可以用于继承,区别在于传参方式不同【区别示例见下方例子2】
call:调用一个对象的一个方法,以另一个对象替换当前对象
obj.call(方法,var1,var2,var3...)
apply:应用某一对象的一个方法,用另一个对象替换当前对象
obj.apply(方法,[var1,var2,var3]);
obj.call(方法,var1,var2,var3...)
apply:应用某一对象的一个方法,用另一个对象替换当前对象
obj.apply(方法,[var1,var2,var3]);
例子:
function parents(name){ //父
this.name = name;
this.say = function(){
alert("父亲的名字:"+this.name);
}
}
function child(name,age){ //子继承parents
this.pObj = parents; //子对象的参数name传递到父对象中,其实就
是用父对象创建子对象
this.pObj(name);
this.age = age;
this.sayC = function(){ //定义子对象里的内容
alert("child:"+this.name+"age:"+this.age); //此时调用的是父
对象里的name
}
}
//实例化
var p = new parents("张三");
p.say(); //弹出:父亲的名字:张三
var c = new child("李四",20);
c.sayC(); //弹出:child:李四age:20
//李四 --> this.pObj(name); --> parents(name) --> this.name=name='李四'
//this.sayC --> this.name --> parents --> this.name
//父对象被子对象继承,所有的属性和方法,都将传递到子对象中
function parents(name){ //父
this.name = name;
this.say = function(){
alert("父亲的名字:"+this.name);
}
}
function child(name,age){ //子继承parents
this.pObj = parents; //子对象的参数name传递到父对象中,其实就
是用父对象创建子对象
this.pObj(name);
this.age = age;
this.sayC = function(){ //定义子对象里的内容
alert("child:"+this.name+"age:"+this.age); //此时调用的是父
对象里的name
}
}
//实例化
var p = new parents("张三");
p.say(); //弹出:父亲的名字:张三
var c = new child("李四",20);
c.sayC(); //弹出:child:李四age:20
//李四 --> this.pObj(name); --> parents(name) --> this.name=name='李四'
//this.sayC --> this.name --> parents --> this.name
//父对象被子对象继承,所有的属性和方法,都将传递到子对象中
例子2:
function person(name,age,len){
this.name = name;
this.age = age;
this.len = len;
this.say = function(){
alert(this.name+":"+this.age+":"+this.len);
}
}
//call继承
function student(name,age){
person.call(this,name,age);【this都指向了student,因此传参时就
把person里的this都变成了student,所以下面李四没有传len参数弹
出的就是undefined】
}
var per = new person("张三",25,"170");
per.say(); //弹出:张三:25:170
var stu = new student("李四",18);
stu.say(); //弹出:李四:18:undefined
//apply继承
function teacher(name,age,len){
person.apply(this,[name,age,len]);
}
var tea = new teacher("王五",20,"180");
tea.say();
function person(name,age,len){
this.name = name;
this.age = age;
this.len = len;
this.say = function(){
alert(this.name+":"+this.age+":"+this.len);
}
}
//call继承
function student(name,age){
person.call(this,name,age);【this都指向了student,因此传参时就
把person里的this都变成了student,所以下面李四没有传len参数弹
出的就是undefined】
}
var per = new person("张三",25,"170");
per.say(); //弹出:张三:25:170
var stu = new student("李四",18);
stu.say(); //弹出:李四:18:undefined
//apply继承
function teacher(name,age,len){
person.apply(this,[name,age,len]);
}
var tea = new teacher("王五",20,"180");
tea.say();
正则表达式
1、正则表达式的模式匹配:用模式匹配字符串
2、模式:规则,是正则的具体化
3、匹配:作比较,利用上面写的规则和字符串相比较,找符合规则的字符
4、正则表达式都是操作字符串string的
2、模式:规则,是正则的具体化
3、匹配:作比较,利用上面写的规则和字符串相比较,找符合规则的字符
4、正则表达式都是操作字符串string的
正则表达式是什么
说明:
1、由普通字符(字母、数字、下划线、汉字、空格、普通标点)和特殊字符(有特殊含义的,如.\等)组成的文字模式
2、该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配
3、正则表达式可搜索关键字,可以将找到的关键字替换成想要的内容
4、可以将爬来的东西里面的链接替换掉
5、数据有效性验证
6、匹配的内容一定是字符串中的内容
7、正则表达式默认区分大小写
说明:
1、由普通字符(字母、数字、下划线、汉字、空格、普通标点)和特殊字符(有特殊含义的,如.\等)组成的文字模式
2、该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配
3、正则表达式可搜索关键字,可以将找到的关键字替换成想要的内容
4、可以将爬来的东西里面的链接替换掉
5、数据有效性验证
6、匹配的内容一定是字符串中的内容
7、正则表达式默认区分大小写
创建正则表达式的两种方式
1、字面量或直接量
/js/修饰符
/js/修饰符
2、构造函数
regular expreesion
new RegExp(‘’,‘修饰符’)
regular expreesion
new RegExp(‘’,‘修饰符’)
构造函数里的转义字符都要双重转义,就是两个\\
普通字符:字母、数字、下划线、空格、汉字、逗号、冒号、叹号、@等(只要不是特殊字符都是普通字符)【上面的就是一些例子】
特殊字符如:.
特殊字符如:.
一般情况下是不使用构造的方式来创建正则的
var str='love kasdkl';
var test1='love';
var test2=new RegExp(test1,'i');
console.log(test2.test(str));
像这种给直接给参数传递字符串形式的可以使用构造的方式来写正则
var test1='love';
var test2=new RegExp(test1,'i');
console.log(test2.test(str));
像这种给直接给参数传递字符串形式的可以使用构造的方式来写正则
正则匹配字符串
1.test 方法: pattern.test(str)--- pattern表示正则表示变量,传入的参数要匹配的字符串变量,返回结果为布尔值(true/false);
2.exec方法: pattern.exec(str)返回的结果是以数组的形式(将匹配到的字符串放入到数组中返回)。若未匹配到,返回null;
模式的修饰符:
i :ignoreCase 忽略大小写--var pattern=/js/i
g:global 全局匹配
m:multiline 多行匹配
可组合,位置无关系;如:var pattern=/js/igm 或im 等;
g:global 全局匹配
m:multiline 多行匹配
可组合,位置无关系;如:var pattern=/js/igm 或im 等;
g 全局匹配(会匹配字符串所有能匹配上的)
pattern.lastIndex属性,初始值为0,普通模式(未开启全局匹配模式)时是一直为0,开启全局匹配模式后,指向匹配到的字符的下一个位置,当全部匹配完后,会重置为0
pattern.lastIndex属性,初始值为0,普通模式(未开启全局匹配模式)时是一直为0,开启全局匹配模式后,指向匹配到的字符的下一个位置,当全部匹配完后,会重置为0
简单的转义字符
“\”可以将字符转义,可以将特殊字符转为普通字符,也可给普通字符赋予特殊含义使它变为特殊字符
【\n换行,\t匹配tab键,\x0A也可以表示\n,\u0009匹配tab键】
【\n换行,\t匹配tab键,\x0A也可以表示\n,\u0009匹配tab键】
特殊字符总结
http://file.mukewang.com/class/assist/792/6614186/1gktf1nntsr/%E7%89%B9%E6%AE%8A%E5%AD%97%E7%AC%A6%E6%80%BB%E7%BB%93%E6%95%99%E8%BE%85.pdf
字符类
1.var mm=/[abcd]/只能匹配里面任意1个字符,先匹配到谁就是谁;
2. [^abcd]表示只匹配除了里面的任意1个字符(取反);
3.[a-z]表示匹配a到z的26个英文字母中的任意1个字符;可修改开始与结束;--按照一定顺序,从小到大,相等也可(前面的小于等于后面的)。
大写也是[a-zA-Z],不能一边大写,一边小写;
大写也是[a-zA-Z],不能一边大写,一边小写;
4.[\u4e00-\u9fa5] 表示中文在unicode编码的范围,匹配到需匹配的1个中文字符即可。
5.[0-9]:表示0-9数字匹配--与字母匹配同理,前面小于等于后面,但前面最小为0,不能为负数;
6.可多种组合[a-zA-Z0-9@_]
常用的字符类
/./表示匹配除了换行符之外的所有
/\./表示匹配小数点
/\d/表示匹配0-9的数字【/[0-9]/】
/\D表示匹配除了0-9之外的任意字符【/[^0-9]/】
/\s/表示匹配空格或者unicode空白符或者制表符tab【/ /或/ /】
/\S/表示除了空格或者unicode空白符或者制表符tab以外都能匹配
/\w/表示匹配[a-zA-Z0-9_]/【字母数字下划线】
/\W/表示匹配[^a-zA-Z0-9_]/
/\./表示匹配小数点
/\d/表示匹配0-9的数字【/[0-9]/】
/\D表示匹配除了0-9之外的任意字符【/[^0-9]/】
/\s/表示匹配空格或者unicode空白符或者制表符tab【/ /或/ /】
/\S/表示除了空格或者unicode空白符或者制表符tab以外都能匹配
/\w/表示匹配[a-zA-Z0-9_]/【字母数字下划线】
/\W/表示匹配[^a-zA-Z0-9_]/
正则中的重复量词
/\d{3}/ 重复3次
/\d{1,2}/ 最少一次,最多两次(逗号和2中间不能有空格)
/\d{1,}/ 至少一次,大于等于一 (不能小于等于,只能只写最小不能只写最大-->/\d{,2}/会报错)
/\d?/ 表示/\d{0,1}/, 0次或1次
/\d+/ 表示/\d{1,}/,至少1次
/\d*/ 表示/\d{0,1}/, 至少0次
/\d{1,2}/ 最少一次,最多两次(逗号和2中间不能有空格)
/\d{1,}/ 至少一次,大于等于一 (不能小于等于,只能只写最小不能只写最大-->/\d{,2}/会报错)
/\d?/ 表示/\d{0,1}/, 0次或1次
/\d+/ 表示/\d{1,}/,至少1次
/\d*/ 表示/\d{0,1}/, 至少0次
【匹配零次,也就是说当字符串从左侧开始匹配时,开始不是数字,没有匹配到数字也就是匹配到了0次,所以就可以不继续往下面匹配了(因为可以匹配0次),输出结果是空字符串。
示例:
var str ='我家的电话是6930184,地址是北京西城区';
var pattern_1=/\d*/;
console.log(pattern_1.exec(str));
匹配结果:空字符串 ""】
示例:
var str ='我家的电话是6930184,地址是北京西城区';
var pattern_1=/\d*/;
console.log(pattern_1.exec(str));
匹配结果:空字符串 ""】
贪婪匹配
1.贪婪匹配:只和量词量(+、*、?等)有关,正则在默认的情况下都是贪婪的,只要条件允许,它都会尽可能多的去匹配。
2. 在量词后面加?变为非贪婪匹配:尽可能少
var nn=/a+?/
2. 在量词后面加?变为非贪婪匹配:尽可能少
var nn=/a+?/
选择
使用|来分隔匹配的字符,从字符串最左边从左往右进行匹配,只输出第一个匹配到的结果,直接忽略后面所有的选择项
var str = bac;
var pattern = /a|b|c/;
匹配结果为:b
得到的是最先匹配的,而不是最合适的。
var str = bac;
var pattern = /a|b|c/;
匹配结果为:b
得到的是最先匹配的,而不是最合适的。
分组和引用
分组
1、“()”可以用括号将匹配字符归为一组,还会自动捕获一次括号内容
var str='abab';
var pattern=/ab+/; 加号只影响字符b,匹配结果是ab而不是abab;
var pattern=/(ab)+/; 匹配结果是['abab','ab'];
var str='abab';
var pattern=/ab+/; 加号只影响字符b,匹配结果是ab而不是abab;
var pattern=/(ab)+/; 匹配结果是['abab','ab'];
2、先忽略括号运行一次,然后再自动捕获一遍括号内容,按顺序排列
var str='abcd';
var pattern=/(ab)c/; 将ab单独捕获,exec结果是['abc','ab']【捕获性分组】
var pattern=/(a(b(c)))/; exec结果是['abc','abc','bc','c']
var str='abcd';
var pattern=/(ab)c/; 将ab单独捕获,exec结果是['abc','ab']【捕获性分组】
var pattern=/(a(b(c)))/; exec结果是['abc','abc','bc','c']
3、“?:”可以放在括号里取消自动捕获,但无法与\1一起用
var pattern=/(?:ab)c/ ;不用将ab捕获,exec结果是['abc']【非捕获性分组】
var pattern=/(?:ab)c/ ;不用将ab捕获,exec结果是['abc']【非捕获性分组】
引用
4、“\1”代表第一个分组,以此类推
var str='ab cd ab';
var pattern =/(ab) cd \1/; \1代表第一个分组,如果有第二个分组可以用\2来代表第二个分组。exec结果是['ab cd ab','ab']
实际应用↓:
var str='<p><a>adffdafd</a></p>';
var pattern= /<([a-zA-Z]+)>(.*?)<\/\1>/;【保证后面的标签名和前面的标签名一样】exec结果是['<p><a>adffdafd</a></p>','p','<a>adffdafd</a>']
var str='ab cd ab';
var pattern =/(ab) cd \1/; \1代表第一个分组,如果有第二个分组可以用\2来代表第二个分组。exec结果是['ab cd ab','ab']
实际应用↓:
var str='<p><a>adffdafd</a></p>';
var pattern= /<([a-zA-Z]+)>(.*?)<\/\1>/;【保证后面的标签名和前面的标签名一样】exec结果是['<p><a>adffdafd</a></p>','p','<a>adffdafd</a>']
5、解析器会在控制台中自动给返回的数组添加两个属性:index、input
index:表示匹配到的值在字符串中的位置,从0开始
input:存放被匹配到的字符串,也就是数组中这个位置的内容
index:表示匹配到的值在字符串中的位置,从0开始
input:存放被匹配到的字符串,也就是数组中这个位置的内容
指定匹配位置
首尾匹配
首匹配^:
var str = 'html js';
var pattern = /^js/;【j必须在行首】
注意:^在字符类中([^])是取反的意思
var str = 'html js';
var pattern = /^js/;【j必须在行首】
注意:^在字符类中([^])是取反的意思
尾匹配$:
var str = 'html js';
var pattern = /js$/;【s必须在行尾】
var str = 'html js';
var pattern = /js$/;【s必须在行尾】
匹配数字:/^\d+$/匹配的全是数字,匹配成功则说明全是数字
逆向思考:/\D/ 这个正则找到的是除数字外的所有字符,有匹配结果说明不全是数字并且将非数字返回
逆向思考:/\D/ 这个正则找到的是除数字外的所有字符,有匹配结果说明不全是数字并且将非数字返回
单词边界匹配
\b 元字符匹配单词边界。
构造语法:new RegExp("\bregexp")
直接量语法:/\bregexp/
构造语法:new RegExp("\bregexp")
直接量语法:/\bregexp/
说明:
在单词边界匹配的位置,单词字符后面或前面不与另一个单词字符直接相邻。请注意,匹配的单词边界并不包含在匹配中。换句话说,匹配的单词边界的长度为零。如果未找到匹配,则返回 null。
在单词边界匹配的位置,单词字符后面或前面不与另一个单词字符直接相邻。请注意,匹配的单词边界并不包含在匹配中。换句话说,匹配的单词边界的长度为零。如果未找到匹配,则返回 null。
例子:
/\bm/ 匹配 "moon" 中的 'm';
/oo\b/ 不匹配 "moon" 中的 'oo',因为 'oo' 后面的 'n' 是一个单词字符;
/oon\b/ 匹配 "moon" 中的 'oon',因为 'oon' 位于字符串的末端,后面没有单词字符;
/\w\b\w/ 不匹配任何字符,因为单词字符之后绝不会同时紧跟着非单词字符和单词字符。
/\bm/ 匹配 "moon" 中的 'm';
/oo\b/ 不匹配 "moon" 中的 'oo',因为 'oo' 后面的 'n' 是一个单词字符;
/oon\b/ 匹配 "moon" 中的 'oon',因为 'oon' 位于字符串的末端,后面没有单词字符;
/\w\b\w/ 不匹配任何字符,因为单词字符之后绝不会同时紧跟着非单词字符和单词字符。
前瞻性匹配
“(?=指定字符)”前瞻性匹配,只有被匹配字符后面跟的是指定字符时才匹配
负向前瞻性匹配
(?!指定字符)”负向前瞻性匹配,被匹配字符后面跟的是指定字符时不匹配
RegExp对象的实例方法(了解)
除了 test 和 exec 还有其他的方法,但是用的不是很多
这三个方法都是Object原型继承的方法:
pattern.toString()返回字符串【转换为字面量形式的字符串】
pattern.toLocaleString()转换为具有本地特色的字符串
pattern.valueOf()返回的是正则表达式本身
这三个方法都是Object原型继承的方法:
pattern.toString()返回字符串【转换为字面量形式的字符串】
pattern.toLocaleString()转换为具有本地特色的字符串
pattern.valueOf()返回的是正则表达式本身
RegExp对象的实例属性和构造函数属性(了解)
实例属性
pattern.ignoreCase 返回布尔值 判定有没i
pattern.global 返回布尔值 判定有没g
pattern.multiline 返回布尔值 判定有没m
pattern.source 返回字面量形式所对应的字符串 --> js
这些属性的用处不大
pattern.global 返回布尔值 判定有没g
pattern.multiline 返回布尔值 判定有没m
pattern.source 返回字面量形式所对应的字符串 --> js
这些属性的用处不大
pattern.lastIndex 这个比较重要
它默认是0,全局匹配下,是匹配一次后下一个位置的索引
构造函数属性【更不常用,因为不同浏览器实现结果不太一样,有的浏览器根本不能实现,它们的支持情况也不一样】
RegExp.input ==RegExp.$_==RegExp['$_'](所有用.来表示的都可以用[],[]就不一定能用.)
RegExp.lastMatch最近一次匹配到的字符 == RegExp['$&']
RegExp.leftContext上次匹配左边剩余的字符
RegExp['$`']
RegExp.rightContext上次匹配右边剩余的字符
RegExp["$'"]
RegExp.lastParen上次匹配到的子选项
RegExp['$+']
console.log(RegExp.$1);返回第一个分组 (常用, 上面的不常用
RegExp.lastMatch最近一次匹配到的字符 == RegExp['$&']
RegExp.leftContext上次匹配左边剩余的字符
RegExp['$`']
RegExp.rightContext上次匹配右边剩余的字符
RegExp["$'"]
RegExp.lastParen上次匹配到的子选项
RegExp['$+']
console.log(RegExp.$1);返回第一个分组 (常用, 上面的不常用
String对象中与正则相关的方法
A.search
var str="html js";
var pattern=/js/;
console.log(str.search(pattern)); //返回5,即匹配到的位置,若没有匹配到,将返回-1
var str="html js";
var pattern=/js/;
console.log(str.search(pattern)); //返回5,即匹配到的位置,若没有匹配到,将返回-1
添加全局匹配修饰符不会影响到结果:
var str="html js js";
var pattern=/js/g;
console.log(str.search(pattern)); //返回5
var str="html js js";
var pattern=/js/g;
console.log(str.search(pattern)); //返回5
也可以不用创建正则,直接搜索,但实现的过程依然是通过构造方式创建正则来进行匹配:
var str="html js js";
console.log(str.search("js")); //返回5
var str="html js js";
console.log(str.search("js")); //返回5
B.match
var str="js js js";
var pattern=/js/;
console.log(str.match(pattern)); //返回[“js”],其index值为0
var str="js js js";
var pattern=/js/;
console.log(str.match(pattern)); //返回[“js”],其index值为0
①match与全局匹配修饰符g:
非全局匹配模式下,与exec()方法相同;全局匹配模式下,分组中的内容将会被舍弃:
var str="js js js";
var pattern=/(j)s/g;
console.log(pattern.exec(str)); //返回["js","j"]
console.log(str.match(pattern)); //返回["js","js","js"],分组内容被舍弃
非全局匹配模式下,与exec()方法相同;全局匹配模式下,分组中的内容将会被舍弃:
var str="js js js";
var pattern=/(j)s/g;
console.log(pattern.exec(str)); //返回["js","j"]
console.log(str.match(pattern)); //返回["js","js","js"],分组内容被舍弃
②match和exec区别总结:
match在非全局的情况下才会返回分组中匹配到的内容;全局匹配下返回所有匹配到的内容,而分组中的内容将会被舍弃;
exec无论是否全局匹配都会返回分组中匹配到的内容,都只会返回当前匹配到的一个内容,而不是全部返回。
match在非全局的情况下才会返回分组中匹配到的内容;全局匹配下返回所有匹配到的内容,而分组中的内容将会被舍弃;
exec无论是否全局匹配都会返回分组中匹配到的内容,都只会返回当前匹配到的一个内容,而不是全部返回。
③match与多行匹配修饰符m
var str="1.js\n2.js\n3.js";
var pattern=/js/m;
console.log(str.match(pattern)); //返回["js"],index值为2
var str="1.js\n2.js\n3.js";
var pattern=/js/m;
console.log(str.match(pattern)); //返回["js"],index值为2
改为全局匹配的情况下:
var str="1.js\n2.js\n3.js";
var pattern=/js/mg;
console.log(str.match(pattern)); //返回["js",js",js"]
var str="1.js\n2.js\n3.js";
var pattern=/js/mg;
console.log(str.match(pattern)); //返回["js",js",js"]
m若想发挥作用除了与g配合外,还可以跟首^尾$匹配相结合:
var str="1.js\n2.js\n3.js";
var pattern=/js$/g;
console.log(str.match(pattern)); //返回["js"]
var pattern=/js$/mg;
console.log(str.match(pattern)); // 返回["js", "js", "js"]
var str="1.js\n2.js\n3.js";
var pattern=/js$/g;
console.log(str.match(pattern)); //返回["js"]
var pattern=/js$/mg;
console.log(str.match(pattern)); // 返回["js", "js", "js"]
3、split split('')把字符串分割成数组,()里面加正则,因为正则很灵活
正则中的split
split('')把字符串分割成数组,()里面加正则,因为正则很灵活
字符串实例:
var str = 'html,css,js';
console.log(str.split(',')); //返回: [ "html", "css", "js" ]
split('')把字符串分割成数组,()里面加正则,因为正则很灵活
字符串实例:
var str = 'html,css,js';
console.log(str.split(',')); //返回: [ "html", "css", "js" ]
正则实例2:
var str = 'html, css , js '; //被匹配字符中有随机空格
var pattern = /\s*,\s*/;
console.log(str.split(pattern)); //返回结果将空格去掉了
var str = 'html, css , js '; //被匹配字符中有随机空格
var pattern = /\s*,\s*/;
console.log(str.split(pattern)); //返回结果将空格去掉了
replace用于替换相关内容,返回结果是替换后的新字符串
语法:str.replace(参数1,参数2)
参数1:要替换的内容,传入的是字符串的话只能替换一次,如果使用正则也是默认只能替换一次,加上全局匹配g才能全部替换
参数2:替换成什么内容
语法:str.replace(参数1,参数2)
参数1:要替换的内容,传入的是字符串的话只能替换一次,如果使用正则也是默认只能替换一次,加上全局匹配g才能全部替换
参数2:替换成什么内容
①替换
var str="I love js js";
var pattern=/js/g;
console.log(str.replace(pattern,"html")); //返回I love html html
var str="1111-11-11";
var pattern=/-/g;
console.log(str.replace(pattern,":")); //返回1111:11:11
var str="I love js js";
var pattern=/js/g;
console.log(str.replace(pattern,"html")); //返回I love html html
var str="1111-11-11";
var pattern=/-/g;
console.log(str.replace(pattern,":")); //返回1111:11:11
②replace对分组的引用 将分组内容加粗变红
var str="I love js";
var pattern=/(js)/;
document.write(str.replace(pattern,'<strong style="color:red">$1</strong>')); //$1表示第一个分组【pattern中的那个分组js】
页面中的输出结果:I love js【js加粗并且是红色】
var str="I love js";
var pattern=/(js)/;
document.write(str.replace(pattern,'<strong style="color:red">$1</strong>')); //$1表示第一个分组【pattern中的那个分组js】
页面中的输出结果:I love js【js加粗并且是红色】
③replace过滤敏感词:
var str="中国军队和阿扁一起办证";
var pattern=/国军队|阿扁|办证/g;
console.log(str.replace(pattern,function($0){
//$0相当于母匹配,是最大的匹配,表示匹配到的内容;$1$2这些都算是子匹配(括号包含的分组)
var result="";
for(var i=0;i<$0.length;i++){
result+="*";
}
return result;
}));
var str="中国军队和阿扁一起办证";
var pattern=/国军队|阿扁|办证/g;
console.log(str.replace(pattern,function($0){
//$0相当于母匹配,是最大的匹配,表示匹配到的内容;$1$2这些都算是子匹配(括号包含的分组)
var result="";
for(var i=0;i<$0.length;i++){
result+="*";
}
return result;
}));
常用正则
1、QQ号
规则:全是数字、首位不能为0、最少是5位、目前最多只有11位
/^[1-9]\d{4,10}$/
/^[1-9]\d{4,}$/
规则:全是数字、首位不能为0、最少是5位、目前最多只有11位
/^[1-9]\d{4,10}$/
/^[1-9]\d{4,}$/
2、昵称
例如:慕课网
规则:昵称为2-18位,中英文、数字及下划线
/^[\u4e00-\u9fa5a-zA-Z0-9_]{2,18}$/
/^[\u4e00-\u9fa5\w]{2,18}$/
例如:慕课网
规则:昵称为2-18位,中英文、数字及下划线
/^[\u4e00-\u9fa5a-zA-Z0-9_]{2,18}$/
/^[\u4e00-\u9fa5\w]{2,18}$/
3、密码
例如:慕课网
规则:6-16位密码,区分大小写,不能用空格(空白字符)
/^\S{6,16}$/
/^[\w~!@#$%^\[\]]{6,16}$/
例如:慕课网
规则:6-16位密码,区分大小写,不能用空格(空白字符)
/^\S{6,16}$/
/^[\w~!@#$%^\[\]]{6,16}$/
4、去除字符串首尾的空白字符
①首匹配
var str=' Alex ';
var pattern=/^\s+/;【用+不用*是为了节省时间,没有空格的话就不需要执行替换操作】
console.log(str,replace(pattern,''));
var str=' Alex ';
var pattern=/^\s+/;【用+不用*是为了节省时间,没有空格的话就不需要执行替换操作】
console.log(str,replace(pattern,''));
②尾匹配
var str=' Alex ';
var pattern=/\s+$/;
console.log(str,replace(pattern,''));
var str=' Alex ';
var pattern=/\s+$/;
console.log(str,replace(pattern,''));
③首尾匹配
方法①:一次全部替换
var str=' Alex ';
var pattern = /^\s+|\s+$/g;
console.log(str.replace(pattern,''));
方法②:匹配两次(首、尾各一次),推荐
var str=" steady ";
var pattern1=/^\s+/;
var pattern2=/\s+$/;
console.log("|"+str.replace(pattern1,"").replace(pattern2,"")+"|"); //输出|steady|
方法①:一次全部替换
var str=' Alex ';
var pattern = /^\s+|\s+$/g;
console.log(str.replace(pattern,''));
方法②:匹配两次(首、尾各一次),推荐
var str=" steady ";
var pattern1=/^\s+/;
var pattern2=/\s+$/;
console.log("|"+str.replace(pattern1,"").replace(pattern2,"")+"|"); //输出|steady|
5、转驼峰
转驼峰
css:background-color:red;
js:elem.style.backgroundColor=red;
jquery:$(elem).css('background-color','red');
A.简单案例:
var str="background-color";
var pattern=/-([a-z])/ig; //加上括号进行分组是为了获得匹配到的c
console.log(str.replace(pattern,function(all,letter){
return letter.toUpperCase();
})); //输出backgroundColor
【注意:all和letter这两个参数是replace方法自己封装好的。replace中第二个参数是一个函数时,函数里面的第一个参数是匹配模式的字符串,第二个参数是与模式中的子表达式匹配的字符串。即all是匹配的正则/-([a-z])/的结果-c ,而letter是匹配正则/-([a-z])/中的第一个分组,分组([a-z])匹配的c,所以letter就是c。】
css:background-color:red;
js:elem.style.backgroundColor=red;
jquery:$(elem).css('background-color','red');
A.简单案例:
var str="background-color";
var pattern=/-([a-z])/ig; //加上括号进行分组是为了获得匹配到的c
console.log(str.replace(pattern,function(all,letter){
return letter.toUpperCase();
})); //输出backgroundColor
【注意:all和letter这两个参数是replace方法自己封装好的。replace中第二个参数是一个函数时,函数里面的第一个参数是匹配模式的字符串,第二个参数是与模式中的子表达式匹配的字符串。即all是匹配的正则/-([a-z])/的结果-c ,而letter是匹配正则/-([a-z])/中的第一个分组,分组([a-z])匹配的c,所以letter就是c。】
6、匹配HTML标签
①正向思考
var str=''<p class="odd" id="odd">123</p>;
var pattern=/<\/?[a-zA-Z]+(\s+[a-zA-Z]+=".*")*>/g;
console.log(str.match(pattern));
var str=''<p class="odd" id="odd">123</p>;
var pattern=/<\/?[a-zA-Z]+(\s+[a-zA-Z]+=".*")*>/g;
console.log(str.match(pattern));
②逆向思考
var str=''<p class="odd" id="odd">123</p>;
var pattern=/<[^>]+>/g;
console.log(str.match(pattern));
var str=''<p class="odd" id="odd">123</p>;
var pattern=/<[^>]+>/g;
console.log(str.match(pattern));
③适用所有情况的方法
var str='<input type="text" value=">" name="username" />';
var pattern=/<(?:[^"'>]|"[^"]*"|'[^']*')*>/g;
?:表示取消对分组的捕获,提高匹配效率
var str='<input type="text" value=">" name="username" />';
var pattern=/<(?:[^"'>]|"[^"]*"|'[^']*')*>/g;
?:表示取消对分组的捕获,提高匹配效率
简化后的写法:
var str='<input type="text" value=">" name="username" />';
var pattern=/<(?:[^"'>]|(["'])[^"']*\1)*>/g; 【因为前面用了?:所以前面的就是非捕获性分组,而后面这个才是捕获性分组,所以\1指的就是["'],(["'])[^"']*\1就是匹配了一对双引号或者单引号以及它里面的内容】
console.log(str.match(pattern));
\s可以匹配任何空白字符,*可以匹配前面的表达式零次或多次,+可以匹配前面的表达式一次或多次。
var str='<input type="text" value=">" name="username" />';
var pattern=/<(?:[^"'>]|(["'])[^"']*\1)*>/g; 【因为前面用了?:所以前面的就是非捕获性分组,而后面这个才是捕获性分组,所以\1指的就是["'],(["'])[^"']*\1就是匹配了一对双引号或者单引号以及它里面的内容】
console.log(str.match(pattern));
\s可以匹配任何空白字符,*可以匹配前面的表达式零次或多次,+可以匹配前面的表达式一次或多次。
7、邮箱
邮箱可能的格式
steady@sina.com
steady_1@sina.com.cn
steady_1.abcd.efgh.com@sina.com.qwerty.cn
可匹配的正则:
/(?:\w+\.)*\w+@(?:\w+\.)+[a-z]+/i
steady@sina.com
steady_1@sina.com.cn
steady_1.abcd.efgh.com@sina.com.qwerty.cn
可匹配的正则:
/(?:\w+\.)*\w+@(?:\w+\.)+[a-z]+/i
较复杂的邮箱格式:(包含连字符)
steady_1.a-bcd.efgh.com@si_n-a.com.qwerty.cn
/^[a-z0-9]+(?:[._-][a-z0-9]+)*@[a-z0-9]+(?:[._-][a-z0-9]+)*\.[a-z]{2,4}$/i
如果是验证邮箱,记得要加上首^尾$匹配
steady_1.a-bcd.efgh.com@si_n-a.com.qwerty.cn
/^[a-z0-9]+(?:[._-][a-z0-9]+)*@[a-z0-9]+(?:[._-][a-z0-9]+)*\.[a-z]{2,4}$/i
如果是验证邮箱,记得要加上首^尾$匹配
8、url地址
匹配URL地址:
(协议:\/\/)主机名(:端口号)/(路径)
简化版正则: /^(https?:\/\/)?([^:\/]+)(:\d+)?(\/.*)?$/
匹配主机名:
/^([a-z0-9\.|[a-z0-9][-a-z0-9]*[a-z0-9]\.)*([a-z)+$/i
(协议:\/\/)主机名(:端口号)/(路径)
简化版正则: /^(https?:\/\/)?([^:\/]+)(:\d+)?(\/.*)?$/
匹配主机名:
/^([a-z0-9\.|[a-z0-9][-a-z0-9]*[a-z0-9]\.)*([a-z)+$/i
变量
数据类型:基本类型和引用类型
基本类型
1、数字,字符串,布尔值,undifined,null
2. 值不可修改
3. 基本类型的' . '方法,实际使用的是其包装对象的方法:
比如 '123'.replace('1', ''),对应String的replace()函数;
比如 '123'.replace('1', ''),对应String的replace()函数;
4. 值保存在栈内存中, 按值访问
引用类型
1、数组、对象
2. 值可修改
3. 地址保存在栈内存,值保存在堆内存中, 按引用访问
命名规则
$ == jQuery (字母开头)
堆栈
数据在运行的时候,是从硬盘放到了内存中,内存分为栈内存和堆内存;
栈内存的大小是固定的,堆内存的大小是不固定的;
基本类型是不可以修改的,所以放到栈内存中;
引用类型因是大小可以修改的,所以大小是不固定的,所以放在堆内存中
栈内存是有序放置的,堆内存是无序放置的,无序放置需要将其地址保存起来,这样会方便查找,这个地址因不分大小,放在了容易查找的栈内存中,叫做引用地址,先找到地址,再根据地址找到堆内存中的引用对象
栈内存的大小是固定的,堆内存的大小是不固定的;
基本类型是不可以修改的,所以放到栈内存中;
引用类型因是大小可以修改的,所以大小是不固定的,所以放在堆内存中
栈内存是有序放置的,堆内存是无序放置的,无序放置需要将其地址保存起来,这样会方便查找,这个地址因不分大小,放在了容易查找的栈内存中,叫做引用地址,先找到地址,再根据地址找到堆内存中的引用对象
变量比较
变量比较
变量比较:
两个基本类型的数据比较,只要数据是一样的,保存两个数据的变量就是相等(===)的;
两个引用类型的数据比较,比如两个对象,即使两个对象中的内容是一样的,保存两个对象的变量是不相等(===)的,因为引用类型的数据是保存在堆内存中,变量保存的是其地址,两个对象的地址是不相同的
两个基本类型的数据比较,只要数据是一样的,保存两个数据的变量就是相等(===)的;
两个引用类型的数据比较,比如两个对象,即使两个对象中的内容是一样的,保存两个对象的变量是不相等(===)的,因为引用类型的数据是保存在堆内存中,变量保存的是其地址,两个对象的地址是不相同的
有些情况,我们是只想看两个对象/数组里的属性和方法是否相同的,不管其地址是否相同,这样如何处理呢?只有通过遍历来查看两个对象/数组,这样可以查看两个对象的内容是否相同的;
复制变量的值
变量中存储的是基本类型的数据时:
将一个变量复制给另一个变量,如果其中一个变量的数据改变,另一个变量存的数据时不受影响的,即不改变;
将一个变量复制给另一个变量,如果其中一个变量的数据改变,另一个变量存的数据时不受影响的,即不改变;
变量中存储的是引用类型的数据时:
将一个变量复制给另一个变量,如果其中一个变量的数据改变,另一个变量存的数据将也更着改变,因为引用类型的数据,其变量存的是地址,复制后,两个变量存的都是一个引用类型的地址,当引用类型的数据改变后,地址并没有变化,只是地址指向的堆内存中的数据发生了变化,所以两个变量中的属性和方法会同时变化。
将一个变量复制给另一个变量,如果其中一个变量的数据改变,另一个变量存的数据将也更着改变,因为引用类型的数据,其变量存的是地址,复制后,两个变量存的都是一个引用类型的地址,当引用类型的数据改变后,地址并没有变化,只是地址指向的堆内存中的数据发生了变化,所以两个变量中的属性和方法会同时变化。
参数传递和类型检测
数据类型检测:
数字、字符串、布尔值、undefined、null 、[] 、{}、函数、RegExp(正则表达式)
数字、字符串、布尔值、undefined、null 、[] 、{}、函数、RegExp(正则表达式)
1、typeof
检测基本数据类型都可以(除了null),但检测引用类型,会返回object
检测基本数据类型都可以(除了null),但检测引用类型,会返回object
对呀,null代表的是对象 用typeof 运算符可以检测出来null的结果为Object类型值,Object是引用类型,null实际代表的是一个空对象的指针哦~
2、instanceof(判断前者是否是后者的实例)
[]是Array的实例(console.log([] instanceof Array))
[]是Object的实例(继承关系,所有东西都继承自Object)(console.log([] instanceof Object)
{}是object的实例(console.log({} instanceof Object)
{}不是Array的实例(console.log({} instanceof Array)
instanceof只能和引用类型联用,作用于基本类型会返回false
[]是Array的实例(console.log([] instanceof Array))
[]是Object的实例(继承关系,所有东西都继承自Object)(console.log([] instanceof Object)
{}是object的实例(console.log({} instanceof Object)
{}不是Array的实例(console.log({} instanceof Array)
instanceof只能和引用类型联用,作用于基本类型会返回false
内存管理与垃圾收集机制(拓展,作为了解)
垃圾收集机制
自动回收:JS会自动回收
手动回收:例如Objective C语言
————————————————————————————
原理:找出没用的数据,打上标记,释放其内存;周期性执行
手动回收:例如Objective C语言
————————————————————————————
原理:找出没用的数据,打上标记,释放其内存;周期性执行
标识无用数据的策略
1、标记清除
垃圾收集器会给存储在内存编中的所有变量一次性都加上标记,会去掉环境中的变量以及被这些环境中的变量所引用的变量上面的标记【环境中的变量:没有离开它的执行环境的变量,比如在执行的函数执行完以后,它里面的局部变量就离开了它的执行环境,因为这个函数被执行完后就被销毁了】,剩下的就是离开了环境的变量,这些就要被清除掉,因为我们已经没有办法访问到这些离开了环境的变量了。最后垃圾收集器就会完成内存的清除工作,销毁那些带标记的值,并回收它们所占的内存。
目前来说,几乎所有浏览器的JavaScript的实现使用的都是标记清除的方式,只不过可能在垃圾收集的时间间隔上有一些区别而已。
垃圾收集器会给存储在内存编中的所有变量一次性都加上标记,会去掉环境中的变量以及被这些环境中的变量所引用的变量上面的标记【环境中的变量:没有离开它的执行环境的变量,比如在执行的函数执行完以后,它里面的局部变量就离开了它的执行环境,因为这个函数被执行完后就被销毁了】,剩下的就是离开了环境的变量,这些就要被清除掉,因为我们已经没有办法访问到这些离开了环境的变量了。最后垃圾收集器就会完成内存的清除工作,销毁那些带标记的值,并回收它们所占的内存。
目前来说,几乎所有浏览器的JavaScript的实现使用的都是标记清除的方式,只不过可能在垃圾收集的时间间隔上有一些区别而已。
2、引用计数(不常用)
跟踪并记录每个数据被引用的次数。
当声明一个变量,并将一个引用类型的值赋值给这个变量时,这个数据就被这个变量引用一次,此时认为这个值的引用次数为1;若这个值又被赋值给另一个变量,此时就有两个变量引用这个值,那么这个值的引用次数就+1变成了2;反之,若引用该值的变量变心了,取得新的值,则原来值的引用次数-1;当原来值的引用次数变成0的时候,那就说明我们已经没有变量可以访问到这个值了,这个时候它所占的内存空间就会被收回。
跟踪并记录每个数据被引用的次数。
当声明一个变量,并将一个引用类型的值赋值给这个变量时,这个数据就被这个变量引用一次,此时认为这个值的引用次数为1;若这个值又被赋值给另一个变量,此时就有两个变量引用这个值,那么这个值的引用次数就+1变成了2;反之,若引用该值的变量变心了,取得新的值,则原来值的引用次数-1;当原来值的引用次数变成0的时候,那就说明我们已经没有变量可以访问到这个值了,这个时候它所占的内存空间就会被收回。
函数
函数
1、function//告诉别人这是一个函数 add//函数名,方便调用,知道函数的具体位置,函数名可被省略(num1,num2){
}
function add(){//叫命名函数,参数可有多个,参数之间用逗号隔开
//{}里是一个函数体,封装代码,相当于一个局部作用域
//return 函数从此结束,后面不要写代码,return返回结果
}
2、window.onload=funtion(){}//匿名函数
1、function//告诉别人这是一个函数 add//函数名,方便调用,知道函数的具体位置,函数名可被省略(num1,num2){
}
function add(){//叫命名函数,参数可有多个,参数之间用逗号隔开
//{}里是一个函数体,封装代码,相当于一个局部作用域
//return 函数从此结束,后面不要写代码,return返回结果
}
2、window.onload=funtion(){}//匿名函数
//当定义一个函数的时候,window下面创造了一个全局的add函数,这个时候没有开辟函数的局部环境;调用时,函数才会执行,当调用add函数的时候,add函数开辟了一个局部环境;当调用完add函数(即return后),局部环境被当成垃圾销毁,同时局部变量也被销毁,但是全局add没有被销毁;
如果在调用add函数,add函数则再开辟一个局部环境;
如果在调用add函数,add函数则再开辟一个局部环境;
【为什么要使用函数】:
1、复用代码 2、.统一修改和维护 3、增加可读性
【什么时候使用函数】
1、当你的程序中有太多相似或相同的代码时
2、当你的程序暴露了太多的细节,使它的可读性变差时
1、复用代码 2、.统一修改和维护 3、增加可读性
【什么时候使用函数】
1、当你的程序中有太多相似或相同的代码时
2、当你的程序暴露了太多的细节,使它的可读性变差时
函数的本质:
1、二象性:
(1)调用
(2)函数是对象{}【理由如下】
1、二象性:
(1)调用
(2)函数是对象{}【理由如下】
<1>定义
字面量方式:function add(num1){}
构造函数:new Function('num1','num2','...')
字面量方式:function add(num1){}
构造函数:new Function('num1','num2','...')
<2>添加属性和方法
变量:
var person = {}
person.name = 'xm';
person.setName=function(name){
this.name = name}
函数:
function add(num1,num2){
return num1+num2;
}
add.sex='male';
add.setSex=function (sex) {
this.sex=sex;
}
变量:
var person = {}
person.name = 'xm';
person.setName=function(name){
this.name = name}
函数:
function add(num1,num2){
return num1+num2;
}
add.sex='male';
add.setSex=function (sex) {
this.sex=sex;
}
<3>作为数据值使用
var person={};
var add = function (){
return 1;
}
add();// 通过变量调用
console.log(add());//1
console.log(add);//function()
var person={};
var add = function (){
return 1;
}
add();// 通过变量调用
console.log(add());//1
console.log(add);//function()
<4>作为参数
注意:fn处加括号,fn()就是将函数执行了,不加括号就是将函数本体传进去,并不会执行代码
注意:fn处加括号,fn()就是将函数执行了,不加括号就是将函数本体传进去,并不会执行代码
<5>作为返回值
function fn(){
return function(){
console.log(1)
};
}
调用return后面的函数:
【var newFn=fn(); newFn();】或【fn()();】
fn()得到的返回值是其内部的函数,再加()就是内部函数的调用
function fn(){
return function(){
console.log(1)
};
}
调用return后面的函数:
【var newFn=fn(); newFn();】或【fn()();】
fn()得到的返回值是其内部的函数,再加()就是内部函数的调用
函数的定义
三种定义方式及其区别
1、【字面量】:
1-第一种【function 声明 】
function add(){} //没有分号
add();
function add(){} //没有分号
add();
1-第二种【var赋值表达式 】
var add = function ( ){ };// 赋值语句
add();
var add=function fn(){ // fn相当于局部变量,只能在函数体内调用
add(); // add在函数体外部和内部都可调用
}
add();
var add = function ( ){ };// 赋值语句
add();
var add=function fn(){ // fn相当于局部变量,只能在函数体内调用
add(); // add在函数体外部和内部都可调用
}
add();
2、【构造函数】
第三种【构造函数的方式】,参数和函数体都必须是字符串形式
var add=new Function('num1','num2','return num1+num2;');
add(); //调用函数
var add=new Function('num1','num2','return num1+num2;');
add(); //调用函数
以上三种定义方式的区别:
【字面量定义方式和构造函数定义方式】
字面量定义方式相比构造函数,直观简洁、方便书写,
*****
【函数声明定义方式和赋值语句定义方式,主要是预解析方面】
1、使用声明函数的方式,调用在前在后都可以执行(调用提前)
2、赋值语句的方式,只能在函数后面调用
选择:
function声明和赋值表达式都可以,注意上面提到的调用提前的区别
【字面量定义方式和构造函数定义方式】
字面量定义方式相比构造函数,直观简洁、方便书写,
*****
【函数声明定义方式和赋值语句定义方式,主要是预解析方面】
1、使用声明函数的方式,调用在前在后都可以执行(调用提前)
2、赋值语句的方式,只能在函数后面调用
选择:
function声明和赋值表达式都可以,注意上面提到的调用提前的区别
函数定义的位置
1、全局作用域
2、函数作用域:可以访问同一级和上一级【可以根据作用域链来梳理函数的作用域,如图】
3、在if / for 代码块中,声明函数相当于全局函数,预解析时会造成调用提前;var赋值函数可以实现效果,因为预解析结束它们都是undefined。但还是不推荐在if / for 代码块中定义函数
4、作为对象的方法
2、函数作用域:可以访问同一级和上一级【可以根据作用域链来梳理函数的作用域,如图】
3、在if / for 代码块中,声明函数相当于全局函数,预解析时会造成调用提前;var赋值函数可以实现效果,因为预解析结束它们都是undefined。但还是不推荐在if / for 代码块中定义函数
4、作为对象的方法
函数的调用
普通函数:命名函数,匿名函数。
命名函数
命名函数调用:函数名加()
匿名函数
匿名函数调用:
方法一:将其赋值给一个变量(实际就是变成了命名函数),调用还是函数名加()。
方法二:直接调用,用函数本体取代函数名。但会报错,不是思路不对,而是解析时,会把function开头的当做声明,自然就不会当成调用了。解决办法,不以function打头,也叫命名函数的自我执行/自我执行的命名函数。
var add=function(){ } ();
var add=function(){ } ();
方法三:使用括号括起来,当做值执行;(匿名函数自执行)
(function(){ })();!function(){ }();~function(){ }()等;
(function(){ })();!function(){ }();~function(){ }()等;
反正只要不是function开头就行,前面随便加个东西比如用console.log,JS就不会认为你在声明函数
最后的括号除了表示执行函数就是用来传入实参
特殊函数的调用(方法的调用)
1、var op={
add:function(num1,num2){
return num1+num2;
};
}
op.add(1,2);
add:function(num1,num2){
return num1+num2;
};
}
op.add(1,2);
2、document.onclick=function(){
console.log('你点击了')
} // 浏览器帮忙调用
document.onclick(); // 自己调用,可以进行模拟操作
console.log('你点击了')
} // 浏览器帮忙调用
document.onclick(); // 自己调用,可以进行模拟操作
3、对象里的属性,何时加引号何时不加
合法的标识符加不加引号都可以
不合法的标识符要加引号【比如@】,否则会报错
非法标识符调用时,只能用对象['非法标识符']
合法的标识符加不加引号都可以
不合法的标识符要加引号【比如@】,否则会报错
非法标识符调用时,只能用对象['非法标识符']
4、方法链式调用:
例:$('p').html('段落').css('background-color','red);
写在一行上,直观又简洁【图中也是一个例子】
例:$('p').html('段落').css('background-color','red);
写在一行上,直观又简洁【图中也是一个例子】
构造函数
1、构造函数也是一个普通函数,创建方式和普通函数一样,但构造函数习惯上首字母大写
2、构造函数和普通函数的区别在于:调用方式不一样。作用也不一样(构造函数用来新建实例对象)
3、调用方式不一样。
a. 普通函数的调用方式:直接调用 person();
b.构造函数的调用方式:需要使用new关键字来调用 new Person();
4、构造函数的函数名与类名相同:Person( ) 这个构造函数,Person 既是函数
5、内部用this 来构造属性和方法
2、构造函数和普通函数的区别在于:调用方式不一样。作用也不一样(构造函数用来新建实例对象)
3、调用方式不一样。
a. 普通函数的调用方式:直接调用 person();
b.构造函数的调用方式:需要使用new关键字来调用 new Person();
4、构造函数的函数名与类名相同:Person( ) 这个构造函数,Person 既是函数
5、内部用this 来构造属性和方法
函数的间接调用
所有函数下面都有一个call()方法和apply()方法
一般使用call()方法和apply()方法来实现间接调用,它们的第一个参数可以改变this指向【默认的都是指向该方法的调用对象,但是设置以后可以指向其他对象】,借用其他对象的方法来操作自己的函数;还可以判断数据是什么类型。
一般使用call()方法和apply()方法来实现间接调用,它们的第一个参数可以改变this指向【默认的都是指向该方法的调用对象,但是设置以后可以指向其他对象】,借用其他对象的方法来操作自己的函数;还可以判断数据是什么类型。
call方法:第一个参数指的是指针对象【改变this的指向】,后面为原方法的参数,一个一个的写上去【例:图中注释的最后一行】
apply方法:第一个参数与call一样,第二个参数为参数数组,可以直接写一个数组而不需要把那些参数一个一个的写上【例:图中的最后一个console.log语句】
参数
函数的参数
参数传递的本质就是将实参赋值给形参: 形参 = 实参
1.定义时,函数上的:形参,形参可以当成用var声明的局部变量
2.调用函数时,传入的:实参, 会替换形参
参数传递的本质就是将实参赋值给形参: 形参 = 实参
1.定义时,函数上的:形参,形参可以当成用var声明的局部变量
2.调用函数时,传入的:实参, 会替换形参
基本类型的参数传递相当于只是拷贝了一个副本,所以在函数内部形参对象的修改不会影响实参对象;
而引用类型的参数传递实际上就是引用地址的复制,形参和实参指向了同一个地址,所以函数内部形参对象的修改会影响实参对象
参数个数问题
1.实参==形参
2.实参<形参
可选参数【下面的函数作用是计算base的power次幂。如果只传了一个参数,那这个参数赋值给base;因为没有传入第二个参数,所以power的值undefined为false,所以power||2就会返回
可选参数【下面的函数作用是计算base的power次幂。如果只传了一个参数,那这个参数赋值给base;因为没有传入第二个参数,所以power的值undefined为false,所以power||2就会返回
3.实参 >形参 【 不确定实参有多少个,那么一个形参都不写。】
arguments是类数组,代表的是形参
function add(){
if(arguments.length === 0) return;
var sum = 0;
for(var i = 0; i< arguments.length; i++){
sum += arguments[i];
}
return sum;
}
可以传任意多个实参
arguments是类数组,代表的是形参
function add(){
if(arguments.length === 0) return;
var sum = 0;
for(var i = 0; i< arguments.length; i++){
sum += arguments[i];
}
return sum;
}
可以传任意多个实参
arguments
在每个函数中都有(局部),是类数组【只是类似数组,其实是对象】
注意:1、它里面的数据和形参是一一对应的
2、arguments是每个函数中所独有的,不同函数中的参数不会
互相影响
2、arguments是每个函数中所独有的,不同函数中的参数不会
互相影响
arguments.callee,指函数本身,一般用于递归中。
严格模式("use strict")下不允许使用arguments.callee,否则会报错。
严格模式("use strict")下不允许使用arguments.callee,否则会报错。
解决办法:使用函数表达式,给它两个名字
var jicheng=function fn(num){【jicheng相当于大名,fn相当于小名】
if(num<=1) return 1;
return num*fn(num-1);
}
这样即使jicheng这个函数名改变了,里面的fn没有变化,对函数的执行不会有影响。
var jicheng=function fn(num){【jicheng相当于大名,fn相当于小名】
if(num<=1) return 1;
return num*fn(num-1);
}
这样即使jicheng这个函数名改变了,里面的fn没有变化,对函数的执行不会有影响。
arguments.length指代实参的个数,函数名.length指代形参的个数;
throw new Error('请传入'+add.length+'个参数') 手动抛出错误
throw new Error('请传入'+add.length+'个参数') 手动抛出错误
什么可以做参数
数据都可以做参数,例如:
1.数字 2.字符串 3.布尔值 4.undefined
5.null 6.数组 7.对象 8.函数
1.数字 2.字符串 3.布尔值 4.undefined
5.null 6.数组 7.对象 8.函数
传对象$.each({name:'xm', age:18},function(index, item){});
对象做参数传参:当参数大于等于三个,调用函数的时候不方便,因为需要考虑参数顺序并且可选参数还得写undefined,这时可以使用对象传参,这样可以不用记形参的顺序,且清晰
函数做参数的例子:
setTimeOut(function(){
},2000);
对象做参数传参:当参数大于等于三个,调用函数的时候不方便,因为需要考虑参数顺序并且可选参数还得写undefined,这时可以使用对象传参,这样可以不用记形参的顺序,且清晰
函数做参数的例子:
setTimeOut(function(){
},2000);
面向对象
javascript中面向对象概述
面向对象:对代码的一种抽象,对外统一提供调用接口的编程思想
面向对象:对代码的一种抽象,对外统一提供调用接口的编程思想
基于原型的面向对象:基于原型的面向对象方式中,对象(object)则是依靠构造器(constructor)利用原型(prototype)构造出来的。
属性:事物的特性
方法:事物的功能
对象:事物的一个实例
原型:Js函数中由prototype属性引用了一个对象,即原型对象
Object是Javascript中一个父对象,JS中所有的自定义函数或面向对象都继承于object
属性:事物的特性
方法:事物的功能
对象:事物的一个实例
原型:Js函数中由prototype属性引用了一个对象,即原型对象
Object是Javascript中一个父对象,JS中所有的自定义函数或面向对象都继承于object
构造函数对象:函数构造器创建函数对象
var obj = new Function(var1, var2, ..., functionBody());
var1、var2是正常变量;functionBody()是自定义函数体,前面的那些参数在这里都能用
注意:构造器构造的对象效率低,var1、var2顺序在functionBody()中不能变
说明:对象分为函数对象和普通对象【凡是用new Function的方式创建的对象都是函数对象】
以函数的方式调用函数构造器定义出来的对象,它会先执行后面的函数体再来创建这个对象,例如:
var obj=new Function('a', 'b', 'return a+b');
var s=obj(2,5);
alert(s);
【会直接弹出7,因为先执行函数体2+5得到7,然后将7返回给s,所以s就是7】
function F() {} // F 是一个函数,函数也是对象,而且每个函数都有一个属性叫:"prototype"
var o = new F(); // F.prototype 就是 o 的原型对象
var obj = new Function(var1, var2, ..., functionBody());
var1、var2是正常变量;functionBody()是自定义函数体,前面的那些参数在这里都能用
注意:构造器构造的对象效率低,var1、var2顺序在functionBody()中不能变
说明:对象分为函数对象和普通对象【凡是用new Function的方式创建的对象都是函数对象】
以函数的方式调用函数构造器定义出来的对象,它会先执行后面的函数体再来创建这个对象,例如:
var obj=new Function('a', 'b', 'return a+b');
var s=obj(2,5);
alert(s);
【会直接弹出7,因为先执行函数体2+5得到7,然后将7返回给s,所以s就是7】
function F() {} // F 是一个函数,函数也是对象,而且每个函数都有一个属性叫:"prototype"
var o = new F(); // F.prototype 就是 o 的原型对象
闭包:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数)
全局变量在函数内部可以访问
闭包的特点:
函数内需要嵌套一层函数,外层函数需要返回内层函数
函数内需要嵌套一层函数,外层函数需要返回内层函数
用途:
1、读取函数内部变量
2、让外层函数的变量保留在内存中
1、读取函数内部变量
2、让外层函数的变量保留在内存中
闭包的优缺点:
优点:有利于封装,可以访问局部变量
缺点:内存占用浪费严重,内存泄漏
JS中的闭包
闭包:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数)
优点:有利于封装,可以访问局部变量
缺点:内存占用浪费严重,内存泄漏
JS中的闭包
闭包:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数)
声明对象的方式
构造模式:三种方法
一、js字面式对象声明对象:
var obj = {
属性名 : 属性值,
方法名称 : function() {},
}
var obj = {
属性名 : 属性值,
方法名称 : function() {},
}
二、new操作符后跟Object构造函数:
var obj = new Object();
obj.属性 = 属性值;
obj.方法 = function(str) {
方法代码;
};
var obj = new Object();
obj.属性 = 属性值;
obj.方法 = function(str) {
方法代码;
};
三、js中构造方法声明对象:
function test([参数列表]) {
this.属性 = 属性值;
this.方法 = function() {
方法中代码
}
}
var obj = new test(参数列表);
三中,函数内部只能用this访问属性和方法
function test([参数列表]) {
this.属性 = 属性值;
this.方法 = function() {
方法中代码
}
}
var obj = new test(参数列表);
三中,函数内部只能用this访问属性和方法
工厂方式声明对象:
说明:按照某种模式,可以不断地创造对象
【注意:任何模式下,同种模式中创造出来的对象都是独立存在的;无论以何种方式创建的对象,彼此之间都是无关联的】
说明:按照某种模式,可以不断地创造对象
【注意:任何模式下,同种模式中创造出来的对象都是独立存在的;无论以何种方式创建的对象,彼此之间都是无关联的】
举例:
function createObject(name,age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function(){
//在obj对象中调用obj对象的属性要用this
return this.name + this.age +'运行中。。。';
};
obj.say = function(){
return "今天天气不错";
};
return obj;
}
//box1和box2没有任何关系,是独立存在的
var box1 = createObject('张三',16);
var box2 = createObject('李四',20);
alert(box1.name); //调用属性成功,输出:张三
alert(box1.run());
function createObject(name,age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function(){
//在obj对象中调用obj对象的属性要用this
return this.name + this.age +'运行中。。。';
};
obj.say = function(){
return "今天天气不错";
};
return obj;
}
//box1和box2没有任何关系,是独立存在的
var box1 = createObject('张三',16);
var box2 = createObject('李四',20);
alert(box1.name); //调用属性成功,输出:张三
alert(box1.run());
构造方法与工厂模式的不同之处:
1、构造函数不会显示创建对象,将属性赋值给this,不需要
【return 对象;】
2、工厂模式在方法内部创建object对象,要返回object对象,属性方法都要赋给object对象
1、构造函数不会显示创建对象,将属性赋值给this,不需要
【return 对象;】
2、工厂模式在方法内部创建object对象,要返回object对象,属性方法都要赋给object对象
js中原型模式声明对象
任何js方法或函数,都自带一个prototype属性,且它以对象方式存在。prototype是Object的子对象。
原型模式根本:函数本身声明为空内容,利用prototype定义一些属性及方法,让所有实例化的对象都拥有它包含的属性及方法。
原型模式根本:函数本身声明为空内容,利用prototype定义一些属性及方法,让所有实例化的对象都拥有它包含的属性及方法。
语法:
function test(){
}
test.prototype.属性 = 属性值;
test.prototype.属性 = 属性值;
test.prototype.方法名称 = function(){
执行代码
}
var obj = new tst();
function test(){
}
test.prototype.属性 = 属性值;
test.prototype.属性 = 属性值;
test.prototype.方法名称 = function(){
执行代码
}
var obj = new tst();
原型模式有两种写法:
1、用prototype每个都写明白
例子:
function test(){
}
test.prototype.color = "red";
test.prototype.heights = "1.7";
test.prototype.widths = "1.2";
test.prototype.showInfo = function(){
alert(this.color+"---"+this.heights+"---"+this.widths);
}
test.prototype.getinfo = function(){
alert("aaa");
}
var run = new test();
alert(run.color);
alert(run.showInfo);
例子:
function test(){
}
test.prototype.color = "red";
test.prototype.heights = "1.7";
test.prototype.widths = "1.2";
test.prototype.showInfo = function(){
alert(this.color+"---"+this.heights+"---"+this.widths);
}
test.prototype.getinfo = function(){
alert("aaa");
}
var run = new test();
alert(run.color);
alert(run.showInfo);
2、json数据定义属性和方法
例子:
function test(){
}
test.prototype = {
color:"red",
heights:"1.7",
widths:"1.2",
showinfo:function(){
alert(this.color+"---"+this.heights+"---"+this.widths);
},
getinfo:function(str){
alert(str);
}
}
var run = new test();
run.showinfo();
run.getinfo("abs");
例子:
function test(){
}
test.prototype = {
color:"red",
heights:"1.7",
widths:"1.2",
showinfo:function(){
alert(this.color+"---"+this.heights+"---"+this.widths);
},
getinfo:function(str){
alert(str);
}
}
var run = new test();
run.showinfo();
run.getinfo("abs");
js中混合模式声明对象
混合模式即为:构造模式+原型模式
语法:
function test(v1,v2,v3){
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
}
test.prototype.方法名称 = function(){
执行代码
}
var obj = new Blog(v1,v2,v3);
例子:
function blog(name,url,friend){
this.name = name;
this.url = url;
this.friend = friend;
}
blog.prototype = {
test:"abc",
showinfo:function(){
alert(this.name+"---"+this.url);
},
gets:function(){
alert(this.friend);
}
}
var peo = new blog("张三","baidu.com","李四");
alert(peo.url);
peo.showinfo();
function test(v1,v2,v3){
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
}
test.prototype.方法名称 = function(){
执行代码
}
var obj = new Blog(v1,v2,v3);
例子:
function blog(name,url,friend){
this.name = name;
this.url = url;
this.friend = friend;
}
blog.prototype = {
test:"abc",
showinfo:function(){
alert(this.name+"---"+this.url);
},
gets:function(){
alert(this.friend);
}
}
var peo = new blog("张三","baidu.com","李四");
alert(peo.url);
peo.showinfo();
对象的遍历
js遍历对象的属性和方法:
对象可以当做数组处理
var ren ={};
ren.name = "zhangsan";
ren.age=18;
ren.demo=function(){
document.write("aaaaa");
}
for (var i in ren){
//alert(i);// 弹出属性和方法的名称
alert(ren[i]);//弹出属性的值和方法的内容【方法的内容指的是方法名后的等号后面的所有内容:function(){ 函数内的代码 }】
}
for(var i in ren)【i作为变量,表示单元下标。在遍历对象时,i的值取的是所有的属性名称和方法名称。】
使用构造函数声明的对象要实例化后才可以进行遍历。
对象可以当做数组处理
var ren ={};
ren.name = "zhangsan";
ren.age=18;
ren.demo=function(){
document.write("aaaaa");
}
for (var i in ren){
//alert(i);// 弹出属性和方法的名称
alert(ren[i]);//弹出属性的值和方法的内容【方法的内容指的是方法名后的等号后面的所有内容:function(){ 函数内的代码 }】
}
for(var i in ren)【i作为变量,表示单元下标。在遍历对象时,i的值取的是所有的属性名称和方法名称。】
使用构造函数声明的对象要实例化后才可以进行遍历。
for in 的遍历过程就相当于循环取值,能取到多少个值,就执行多少次函数体。对象遍历时,可以当做数组一样处理,通过[]取值。
对象的存储
js对象的存储:两点需要重点记住:
1、对象所赋值的变量,这个变量指向的是堆内存中的地址,地址中存放的就是对象中的属性和方法;
2、对象之间没有任何联系;
1、对象所赋值的变量,这个变量指向的是堆内存中的地址,地址中存放的就是对象中的属性和方法;
2、对象之间没有任何联系;
1、栈内存:保存基本值和引用类型值的地址。
2、堆内存:保存一组无序且唯一的引用类型值,可以使用栈中的键名来取得。
3、代码段:通常是指用来存放程序执行代码的一块内存区域。
4、数据段:数据段通常是指用来存放程序中已初始化的全局变量的一块内存区域。
2、堆内存:保存一组无序且唯一的引用类型值,可以使用栈中的键名来取得。
3、代码段:通常是指用来存放程序执行代码的一块内存区域。
4、数据段:数据段通常是指用来存放程序中已初始化的全局变量的一块内存区域。
封装
封装:
概念:把对象内部数据和操作细节进行隐藏
概念:把对象内部数据和操作细节进行隐藏
说明:1、大多面向对象的语言都支持封装的特性,提供了private关键字来隐藏某些属性或方法,用来限制被封装的数据或者内容的访问,只对外提供一个对象的专门访问的接口。接口一般为调用方法
2、js中没有提供专门封装这样的关键字,但是可以通过闭包实现封装,函数内部声明的变量,外部是访问不到的
3、公有与私有内容的区别是:能否在对象外部被访问
2、js中没有提供专门封装这样的关键字,但是可以通过闭包实现封装,函数内部声明的变量,外部是访问不到的
3、公有与私有内容的区别是:能否在对象外部被访问
面向对象的关键词
instanceof 变量是否是对象的实例
var arr = new Array(); alert(arr instanceof Array);
var arr = new Array(); alert(arr instanceof Array);
2、delete
说明:
1)可以删除对象中的属性和方法,【语法:delete 属性名/方法名;】
2)不可删除变量
3)不可删除原型链上的属性和方法
说明:
1)可以删除对象中的属性和方法,【语法:delete 属性名/方法名;】
2)不可删除变量
3)不可删除原型链上的属性和方法
3、call apply
说明:
调用一个对象的一个方法,以另一个对象替换当前对象
说明:
调用一个对象的一个方法,以另一个对象替换当前对象
因为call调用的没有this所以这样
【call()方法的作用是调用一个方法,并改变其this的指向。第一个参数是传递this的,这里就是把subs的this传递给了add,那么add中如果有this,指向的就是subs。因为add代码中只是一个运算,没有使用到this,所以this还是指向add,调用的是add方法】
示例1:
function add(a,b){
alert(a+b);
}
function subs(a,b){
alert(a-b);
}
//下一行中subs这个位置只能引用一个存在的对象。这里是把subs替换成了add,不管subs是啥,都调用的add,前提是得声明
add.call(subs,5,3); //返回8
add.apply(subs,[5,3]); //返回8
function add(a,b){
alert(a+b);
}
function subs(a,b){
alert(a-b);
}
//下一行中subs这个位置只能引用一个存在的对象。这里是把subs替换成了add,不管subs是啥,都调用的add,前提是得声明
add.call(subs,5,3); //返回8
add.apply(subs,[5,3]); //返回8
示例2:
function animal(){
this.name = "ani";
this.showName = function(){
alert(this.name);
}
}
function cat(){
this.name = "cat";
}
var an = new animal();
var c = new cat();
//通过call方法,将showName-->cat使用
an.showName.call(c,","); //返回cat
an.showName.apply(c,[]); //返回cat
function animal(){
this.name = "ani";
this.showName = function(){
alert(this.name);
}
}
function cat(){
this.name = "cat";
}
var an = new animal();
var c = new cat();
//通过call方法,将showName-->cat使用
an.showName.call(c,","); //返回cat
an.showName.apply(c,[]); //返回cat
4、callee
说明:
1)返回正在执行的function对象,返回的就是function的内容
2)callee是arguments的一个属性,arguments存在于所有函数中
3)arguments.callee的默认值就是正在执行的function对象
4)callee就是指代函数本身
说明:
1)返回正在执行的function对象,返回的就是function的内容
2)callee是arguments的一个属性,arguments存在于所有函数中
3)arguments.callee的默认值就是正在执行的function对象
4)callee就是指代函数本身
语法:
function demo(){
//把callee当做属性时,返回函数内容
alert(arguments.callee); //返回的是整个demo的代码
}
demo();
function demo(){
//把callee当做属性时,返回函数内容
alert(arguments.callee); //返回的是整个demo的代码
}
demo();
递归例子:
var sum = function(n){
if(n<=1){
return 1;
}else{
//在函数内部调用本函数
return n+arguments.callee(n-1);
}
}
alert(sum(5));
var sum = function(n){
if(n<=1){
return 1;
}else{
//在函数内部调用本函数
return n+arguments.callee(n-1);
}
}
alert(sum(5));
5、arguments
说明:arguments是作为伪数组存在的。
1)每个函数都有一个arguments对象的实例,她引用函数的参数(实参)
2)可以用数组下标方式引用arguments元素
3)arguments.length用来代表参数的个数
4)arguments.callee是引用函数自身
5)arguments只有函数开始时有,可以访问参数,且是以数组的方式存在的,0-n
说明:arguments是作为伪数组存在的。
1)每个函数都有一个arguments对象的实例,她引用函数的参数(实参)
2)可以用数组下标方式引用arguments元素
3)arguments.length用来代表参数的个数
4)arguments.callee是引用函数自身
5)arguments只有函数开始时有,可以访问参数,且是以数组的方式存在的,0-n
语法:
function test(a,b,c){
alert(arguments.length); //弹出3
alert(arguments[0]); //弹出1,arguments若表示参数,可遍历
alert(arguments.callee); //弹出test内容
}
test(1,2,3);
function test(a,b,c){
alert(arguments.length); //弹出3
alert(arguments[0]); //弹出1,arguments若表示参数,可遍历
alert(arguments.callee); //弹出test内容
}
test(1,2,3);
6、this
说明:
1)this主要应用在构造函数上,可以在函数内部定义属性或变量
说明:
1)this主要应用在构造函数上,可以在函数内部定义属性或变量
在call和apply中,this指第一个参数
var x = 0;
function test(){
alert(this.x)
}
var o = {};
o.x = 1;
o.m = test
o.m.apply(); //返回0
o.m.apply(o); //返回1——因为apply改变了this的指向对象,指向了o,o里的x属性的值为1
var x = 0;
function test(){
alert(this.x)
}
var o = {};
o.x = 1;
o.m = test
o.m.apply(); //返回0
o.m.apply(o); //返回1——因为apply改变了this的指向对象,指向了o,o里的x属性的值为1
对象冒充
对象冒充
图中在student内,用(this.newMethod=person;)实现了冒充person对象;而s1是student的对象,所以它继承person,拥有person所有属性和方法。
使用了this的是特权属性和特权方法,person所拥有的属性和方法是这些特权属性和特权方法;walk不属于person,因为它是在person的prototype对象上定义的,属于共有方法。
所以【对象冒充只能继承特权属性和特权方法,不能继承原型的共有属性和共有方法】
图中在student内,用(this.newMethod=person;)实现了冒充person对象;而s1是student的对象,所以它继承person,拥有person所有属性和方法。
使用了this的是特权属性和特权方法,person所拥有的属性和方法是这些特权属性和特权方法;walk不属于person,因为它是在person的prototype对象上定义的,属于共有方法。
所以【对象冒充只能继承特权属性和特权方法,不能继承原型的共有属性和共有方法】
表单验证
账户名验证
用户名一般的规则:
1、用户名不能为空
2、一般为数字、字母、下划线_ (\w)
1、用户名不能为空
2、一般为数字、字母、下划线_ (\w)
0 条评论
下一页