开头的轮廓
前边js里面的函数,我们学习了js里面的函数包括自定义函数和全局函数,其中自定义函数通过function关键字来定义,而全局函数也就有限的几个,我们也举过例子了,大家知道了这个概念与分类,学起来认识上就清晰多了,深入的学习不过是对整个认知的添添补补。在学习了js里面的函数之后,这篇教程我们来认识下js里面的对象。
js里面的对象指的是一类东西的抽象,可以具有属性和行为(动作)。具体来说,javascript里面的对象也可以分为内置对象和自定义对象,下面是大的框架,大家先有个认识,之后再分别细说。
内置对象:
Number
Boolean
String
Math
Date
Object
Array
RegExp
自定义对象:
直接量方式
工厂方法
构造函数
prototype方式
prototype方式的优化
一、内置对象之Number
Number 对象是原始数值的包装对象,创建Number对象的方法:
var myNum=new Number(value);//作为构造函数使用
var myNum=Number(value);//作为全局函数使用
参数value为要转化为数值的值。在必要时,JavaScript 会自动地在原始数据和对象之间转换。
Number内置对象的属性和方法见下表格:
常用属性 | 属性描述 | 应用举例 |
MAX_VALUE | 可表示的最大的数。 | alert(Number.MAX_VALUE); |
MIN_VALUE | 可表示的最小的数。 | |
常用方法 | 方法描述 | 应用举例 |
NumberObject.toFixed(num) | 可把 Number 四舍五入为指定小数位数的数字。 | var num = new Number(13.37); document.write (num.toFixed(1)); 或document.write (13.37.toFixed(1)); 结果:13.4 |
二、内置对象之Boolean对象
Boolean对象是原始布尔值的包装对象,创建Boolean对象的方法:
var myNum=new Boolean(value);//作为构造函数使用
var myNum=Boolean(value);//作为全局函数使用
其中参数value为要转为Boolean对象的值,省略 value 参数,或者设置为 0、-0、null、""、false、undefined 或 NaN,则该对象值为 false。否则为true。
Boolean对象的常用属性和方法:
常用属性 | 属性描述 | 应用举例 |
constructor | 返回对创建此对象的 Boolean 函数的引用 | |
prototype | 使您有能力向对象添加属性和方法。 |
注意:不管是内置对象还是自定义对象都有这两个属性。
三、String对象
String对象也是javascript的内置对象之一,而且是最常用的一个。同前边介绍的Number、Boolean内置对象一样,String对象也是对原始字符串的包装,创建String对象的方法:
var myNum=new String(value);//作为构造函数使用
var myNum=String(value);//作为全局函数使用
其中,参数value为要转为字符串的任意类型。在必要时,JavaScript 会自动地在原始数据和对象之间转换。
String对象的属性和方法就比较多了,我总结了一些常用的列在下面的表格里面:
常用属性 | 属性描述 | 应用举例 |
length | 字符串的长度 | "Hello World!".length:12 |
常用方法 | 方法描述 | 应用举例 |
str.charAt(index) | index从0到str.length-1 | "Hello World!".charAt(1):e |
str.indexOf(searchvalue) | searchvalue在str中首次出现的位置,无则返回-1 | |
str.match(regexp) | g:返回值不提供与子表达式匹配的文本的信息 不带g:返回值跟执行一次exec的结果是一样的 | |
str.substr(start,[len]) | 从指定位置(包括)截取len个长度并返回新的字符串,下标从0开始,str不变 | |
str.substring(start,stop) | 截取字符串并返回新的字符串,[包括,不包括),下标从0开始,str不变 | |
str.split(separator) | 使用separator分割字符串,并返回数组 | |
str.replace(regexp/substr,replacement) | 使用replacement替换regexp/substr,并返回被替换后的字符串,str不变 |
match函数需要用到正则表达式,我在讲正则表达式的exec函数时已经说过match这个函数,参见js里面正则表达式的exec函数与字符串的match详解。下面挑几个String内置对象里面的其他函数举个例子:
<script type="text/javascript">
var str="radio_uncheck.jpg";
var arr=str.split("");
console.log(arr);
console.log(str);
var strnew=str.replace("_uncheck.jpg","_check.jpg");
console.log(strnew);
console.log(str);
var substr=str.substr(2,3);
console.log(substr);
console.log(str);
var substring=str.substring(2,3);
console.log(substring);
console.log(str);
</script>
执行结果:
四、Math对象
Math内置对象在js里面主要是封装了一些数学方面的操作,比如求平方,四舍五入,对数进行上舍入取整等。我也总结了几个列在下表里:
常用属性 | 属性描述 | 应用举例 |
PI | 圆周率 | Math.PI |
常用方法 | 方法描述 | 应用举例 |
ceil(x) | 对数进行上舍入取整 | Math.ceil(-5.9):-5 Math.ceil(5.2):6 |
floor(x) | 对数进行下舍入取整 | Math.floor(5.8):5 |
random() | 返回 [0,1) 之间的随机数。 | Math.random() |
round(x) | 把数四舍五入为最接近的整数。 | Math.round(5.5) |
举个例子,实现每次刷新页面改变页面元素id=div的背景颜色为随机背景颜色。这道题的关键在于如何生成随机的颜色,这里就用到了Math内置对象的函数,效果如下:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style>
#div{
width:100px;
height:100px;
}
</style>
</head>
<body>
<div id="div"></div>
</body>
//javascript代码
</html>
javascript:
<script>
function getClr(){
var r=Math.floor(Math.random()*255).toString(16);
r=r.length<2?"0"+r:r;
var g=Math.floor(Math.random()*255).toString(16);
g=g.length<2?"0"+g:g;
var b=Math.floor(Math.random()*255).toString(16);
b=b.length<2?"0"+b:b;
return "#"+r+g+b;
}
document.getElementById("div").style="background:"+getClr();
</script>
五、Date对象
s的内置对象Date的属性与方法:
常用方法 | 方法描述 | 应用举例 |
Date(字符串或数值) | 返回当日的日期和时间。 | var currentDate = new Date(); |
getFullYear() | 从 Date 实例以四位数字返回年份 | currentDate.getFullYear() |
getMonth() | 从 Date 对象返回月份 (0 ~ 11) | currentDate.getMonth() |
getDate() | 从 Date 对象返回一个月中的某一天 (1 ~ 31) | currentDate.getDate() |
getHours() | 返回 Date 对象的小时 (0 ~ 23) | currentDate.getHours() |
getMinutes() | 返回 Date 对象的分钟 (0 ~ 59) | currentDate.getMinutes() |
getSeconds() | 返回 Date 对象的秒数 (0 ~ 59) | currentDate.getSeconds() |
toUTCString() | 根据世界时,把 Date 对象转换为字符串。 | currentDate.toUTCString() |
getTime() | 返回 1970 年 1 月 1 日至今的毫秒数。 | currentDate.getTime() |
setDate() | 设置 Date 对象中月的某一天 (1 ~ 31)。 | |
setMonth() | 设置 Date 对象中月份 (0 ~ 11)。 | |
setFullYear() | 设置 Date 对象中的年份(四位数字)。 | currentDate.setFullYear(2014) |
setHours() | 设置 Date 对象中的小时 (0 ~ 23)。 | |
setMinutes() | 设置 Date 对象中的分钟 (0 ~ 59)。 | |
setSeconds() | 设置 Date 对象中的秒钟 (0 ~ 59)。 | |
setTime() | 以毫秒设置 Date 对象。 |
上面列出了Date对象的常用方法,案例参考js实现时钟clock效果
六、javascript内置对象Array
Array数组对象用于在单个的变量中存储多个值.
常用属性 | 属性描述 |
length | 设置或返回数组元素的个数 |
常用方法 | 方法描述 |
arr.join([separator]) | 返回以separator分割的字符串 |
arr.push(e1,[e2,..,eN]) | 向数组末尾添加一个或多个元素,并返回新的长度 |
arr.shift() | 把数组的第一个元素删除,并返回第一个元素的值。 |
arr.unshift(e1,[e2,.,eN]) | 向数组的开头添加一个或更多元素,并返回新的长度 |
arr.pop() | 删除并返回数组的最后一个元素 |
数组的基本定义和赋值操作:
<script>
var str="abc";
//数组:使用一个变量来存放很多个值
//定义数组的两种方式,完全等价
//var arr=new Array();
//var arr2=[];
//给数组赋值的两种方式1
/*
var students=[];//声明一个空的数组
console.log("没加元素前数组的长度:"+students.length);
students[0]="a";
students[1]="a1";
students[2]="a2";
students[3]="a3";
students[4]="a4";
console.log("加入元素后数组的长度:"+students.length);
console.log(students);
*/
//给数组赋值的两种方式2
/*
var students=["a","b","c","d"];
console.log("加入元素后数组的长度:"+students.length);
console.log(students);
console.log(students[2]);
*/
//数组里面放的元素可以是任意的类型,包括我们以后学的对象自定义对象
var arr=["小明",20,true,null,undefined,"小明的爸爸"];
//console.log(arr);
//console.log(arr[1]);
//数组的下标从0开始,下标和length的关系
console.log(arr[arr.length-1]);
console.log(arr[arr.length]);//OUT OF BOUND index
</script>
数组里面的方法测试:
<script>
/*
var arr=["a","b","c","d"];
console.log(arr.join());
//join:用指定的分隔符分割数组为字符串,默认就是,
console.log(typeof arr.join());
console.log(arr);
console.log(arr.join("|"));
*/
/*
var arr1=[];
for(var i=0;i<100;i++){
arr1[i]=i;//0 1 2 :指定位置来存放元素
}
console.log(arr1);
var arr2=[];
for(var i=0;i<100;i++){
//也是往数组里面存放元素,但是每次存放的元素都放在了数组的第一位
arr2.unshift(i);
}
console.log(arr2);
*/
/*
i=0:arr3.push(i); arr[0]=0;
i=1:arr3.push(i); arr[1]=1;
* */
/*
var arr3=[];
for(var i=0;i<100;i++){
//也是往数组里面存放元素,但是每次存放的元素都放在了数组的末尾
arr3.push(i);
}
console.log(arr3);
*/
/*
var arr=["a","b","c","d"];
console.log(arr);
//删除数组末尾的元素
arr.pop();
console.log(arr);
*/
var arr=["a","b","c","d"];
console.log(arr);
//删除数组的第一个元素
arr.shift();
console.log(arr);
</script>
另外,我还写了个利用数组实现的抽奖程序,参见“利用js实现抽奖小游戏”。
七、RegExp
RegExp是正则表达式对象,当要查找或者测试的是一个模式或者说一类字符串的时候使用正则表达式。
获取正则表达式的两种方法:
var reg=/pattern/flag;
var reg=new RegExp(“test”,[flag]);
flag为修饰符:i(ignore),g(global),m(multiple)
正则表达式中的转义字符“\”
区别方法reg.test(str),reg.exec(str),以及字符串的str.match(reg)
正则表达式里面的概念:
1.字符类别(元字符)
元字符 | 含义 |
. | 查找单个字符,除了换行和行结束符和空字符串 |
\w | 查找单词字符。等价于[a-zA-Z0-9_] |
\W | 查找非单词字符。等价于[^a-zA-Z0-9_] |
\d | 查找数字。等于[0-9] |
\D | 查找非数字字符。等价于[^0-9] |
\s | 查找空白字符。包括换行制表符等 |
\S | 查找非空白字符。 |
\n | 查找换行符。 |
\f | 查找换页符。 |
\r | 查找回车符。 |
\t | 查找制表符。 |
\v | 查找垂直制表符。 |
\xxx | 查找以八进制数 xxx 规定的字符。 |
\xdd | 查找以十六进制数 dd 规定的字符。 |
\uxxxx | 查找以十六进制数 xxxx 规定的 Unicode 字符。汉字[\u4e00-\u9fa5] |
2.字符集合(方括号)
字符 | 含义 |
[abc] | 查找方括号之间的任何字符。 |
[^abc] | 查找任何不在方括号之间的字符。 |
[0-9] | 查找任何从 0 至 9 的数字。 |
[a-z] | 查找任何从小写 a 到小写 z 的字符。 |
[A-Z] | 查找任何从大写 A 到大写 Z 的字符。 |
3.边界
字符 | 含义 |
n$ | 匹配任何结尾为 n 的字符串。 |
^n | 匹配任何开头为 n 的字符串。不要和[^n]混淆 |
4.数量词
字符 | 含义 |
n+ | 匹配任何包含至少一个 n 的字符串。 |
n* | 匹配任何包含零个或多个 n 的字符串。 |
n? | 匹配任何包含零个或一个 n 的字符串。 |
n{X} | 匹配包含 X 个 n 的序列的字符串。 |
n{X,Y} | 匹配包含 X 至 Y 个 n 的序列的字符串。 |
n{X,} | 匹配包含至少 X 个 n 的序列的字符串。 |
5.分组:()表示分组
正则表达式举例:
<script type="text/javascript">
var reg=/./;
console.log(reg.test(""));//false
reg=/\w/;
console.log(reg.test("-"));//false
reg=/\W/;
console.log(reg.test("_"));//false
reg=/\s/;
console.log(reg.test(" "));//true
reg=/\S/;
console.log(reg.test(" "));//false
reg=/-/;
console.log(reg.test("2017-03"));//true
reg=/[\u4e00-\u9fa5]+/;
var str="ABCDe124-_!找";
console.log("汉字:"+reg.test(str));//true
reg=/<[^>]+>/;//匹配html标签
str="<a href='xx.com'>";
console.log(reg.test(str));//true
str="</a>";
console.log(reg.test(str));//true
reg=/^[a-zA-Z$_]\d*/;
str="3a3333";
str="ab3a33330";//^[a-zA-Z$_]\d*只能匹配到ab3这里
reg=/^[a-zA-Z$_]+\d*\w\d*c$/;
str="ab3a333309c";
console.log("边界:"+reg.test(str));
</script>
校验邮箱和手机的例子:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>05-正则表达式</title>
<script>
function checkEmail(){
var val=document.getElementById("email").value;
var reg=/^[\w-\.]+@[\w-]+\.\w{2,}$/;
alert(reg.test(val));
}
function checkPhone(phone){
var reg=/^1[3|4|5|7|8][0-9]{9}$/;
return reg.test(phone);
}
alert(checkPhone("1111"));
</script>
</head>
<body>
请输入邮箱:<input type="text" name="email" id="email"> <br>
<input type="button" value="校验是否合法" onclick="checkEmail()">
</body>
</html>
八、自定义对象之直接量方式
对象的三种种定义方式:
var obj=new Object();
var obj={};
var ojb=Object();
自定义定义对象(直接量方式)的定义:
var personObj={
name:'小张',
"age":23,
weight:"80kg",
intro:function(){
console.log("你好,我叫"+this.name);
}
}
personObj.eat=function(){
console.log("我是吃货,重量"+this.weight);
}
自定义对象的使用:
//属性访问:
personObj.name
//或者
personObj[“name”]
//设置属性的值
personObj.age=24
方法访问:
personObj.intro();
personObj.eat();
注意:
对象的属性可以加引号也可以不加,this绑定的是调用自己(函数)的对象,谁调用我this就是指的谁。直接量的方式定义对象其实就是json的方式定义对象。
json:javascript Object Notation,js对象表示法,分为json数组和json对象两部分,是前端与后端系统进行数据交互的主要格式。
九、自定义方式之工厂方法创建对象
前面说了通过直接量的方式来实现自定义对象其实就是json的方式,直接量方式定义对象的缺点是什么呢?
直接量是一次性对象,想要再创建一个对象就要再写一遍,这样的话,就显得比较麻烦。所以,我们可以使用工厂方法来创建对象,示例代码如下:
<script>
function createObj(un,age){
var obj=new Object();
obj.uname=un;
obj.age=age;
obj.run=function (){
return this.uname+"今年"+this.age+"岁了";
};
return obj;
}
var a=createObj("刘德华","50");
var b=createObj("谭咏麟","53");
console.log(a.run());
console.log(b.run());
console.log(a.run==b.run);//false
console.log(typeof a);//object
console.log(typeof b);//object
console.log(a instanceof Object);
console.log(b instanceof Object);
</script>
执行结果:
由此,我们可以得到以下结论:
使用工厂方法可以创建任意多个对象,只需要调用createObj()函数就可以了,比起直接量的方式真的很方便。
因为在createObj()函数里面是每调用一次就创建了一个Object,每次都是不同的对象,自然a.run与b.run也就不相等了,因为这两个函数属于不同的对象。
不管是typeof操作符还是instanceof操作符,都证明了a与b都是Object对象的实例。
十、自定义对象之构造函数
边通过工厂方法定义对象依然存在着缺点,就是我通过
var a=createObj("刘德华","50");
var b=createObj("谭咏麟","53");
的方式创建了两个变量,我其实是想用a和b表示两个人,但是使用
console.log(a instanceof Object);
console.log(b instanceof Object);
判断的时候,却说明a与b只是Object的实例,能不能让a与b是Person的实例呢?这样就可以让javascript里面的“类”的概念更像“类”一点,在es5中,有“类”的实现却没有类的概念,在es5中类就被称为对象。
使用构造函数创建一个人的“类”javascript代码示例:
<script>
function Person(uname,age){
this.uname=uname;
this.age=age;
this.run=function(){//相当于new Function(...); 也就是说每次new一个对象,都会创建个函数
console.log("函数被创建了");
return this.uname+"今年"+this.age+"岁了";
};
}
var p1=new Person("小明",33);
var p2=new Person("小红",22);
console.log(p1.run());
console.log(p2.run());
console.log(p1.run==p2.run);//都会创建个函数==>false
console.log(typeof p1);//object
console.log(typeof p2);//object
console.log(p1 instanceof Person);//true
console.log(p1 instanceof Object);//true
console.log(p2 instanceof Person);//true
console.log(p2 instanceof Object);//true
</script>
结果:
总结:
使用构造函数的方式我们解决了工厂方式创建js自定义对象遗留的问题:在这里,p1和p2已经是Person的示例了,也就是说,你可以自己创建出阿猫阿狗的实例来了,那么为甚么 p1 instanceof Object也为true呢?因为js里面所有的对象都是以Object这个对象作为父对象的,既然是所有的对象,自然也就包含了自定义的js对象。
那么,现在就完美了吗?当然不是,我们看到我在注释里面已经写出,每次每次new一个对象,都会创建个函数,这样无形中也占用了更多的内存,虽然现在内存也不值钱了,但是我还是希望力求完美,这样才能进步啊,怎么样才能让即便创建多个对象,也能共享一个函数呢?因为函数是没必要创建多个的啊,实例之间可以共用函数,请继续往下看。
十一、使用prototype优化构造函数方式创建自定义对象
我说过,js里面所有的对象都是继承自Object这个对象,自然包括自定义对象。Object对象有一个属性,叫做prototype,而这个prototype属性也是一个对象,就像下面的定义:
var obj={
prototype:{
a:'a',
b:function (){
}
}
}
什么叫继承呢?就是Object有的东西,对象就有,也就是说,任意一个对象都有prototype这个属性。
接着说我们使用构造函数遗留下来的问题:怎么让所有的对象共享一个函数,而不是创建一次对象就创建一次函数?函数想要实现实例间共享只能通过Object.prototype实现,而如果直接使用Object.prototype这种方式就破坏了现有Object对象。因为js里所有的对象最终都是继承Object,所以所有对象都拥有prototype属性,因此我们可以使用自己定义的对象的prototype来实现函数共享。
<script>
function Person(uname,age){
this.uname=uname;
this.age=age;
}
//写法一
Person.prototype={
run:function(){//只加载一次,new Function()一次
return this.uname+"今年"+this.age+"岁了";
}
}
//写法二
Person.prototype.eat=function(){
console.log(this.uname+"是个吃货!");
}
var p1=new Person("a",33);
var p2=new Person("b",22);
alert(p2.run());
p1.eat();
alert(p1.run==p2.run);
</script>
使用上面的写法就可以了。
但是上面的写法有点不伦不类,大家看起来是不是有点乱?因为我的类“Person”的属性和方法分开写了,并没有写在一个{}中,因此为了实现把js对象的属性和方法写在一起,同时又要保证所有的实例共享一个函数,可以使用下面的终极写法:
<script>
function User(userName,userAge){
alert("new");
this.userName=userName;
this.userAge=userAge;
if(typeof this.introduce != "function"){//如果相等,说明原型部分已经加载过了[加载过了,所有实例都会有]
alert("创建函数开始");
User.prototype.introduce=function(){//不能用prototype={x:a}来声明多个函数,要一个个写
alert("进入introduce");
}
alert("创建函数结束");
}
}
var u=new User("小明",25);
var u2=new User("小红",252);
u2.introduce();
</script>