1 对象类型
JavaScript语言中的对象可分为三种类型:
- 用户定义对象(user-defined object):由程序员自行创建的对象
- 内建对象(native object):内建在JS语言中的对象,即Array,Math等
- 宿主对象(host object):有浏览器提供的对象
其中,内建对象在入门笔记有讲过,JS的数据类型分为原始类型以及Object对象。
1.1 包装对象
1 什么是包装对象?
在JavaScript中string
,number
,boolean
这三者都是基本包装类型,即他们不是对象(object),但在一定条件下会自动转化为对象,因此被称为原始类型的“包装类型”。
举例子说明,都知道只有对象(object
类型)才能拥有属性以及方法。参考以下代码:
var str="seiei";
str.tall="190";
console.log(str.tall);//undefined
该例子中,str是一个字符串,并不是对象,当它引用字串符的属性时(代码第二行),JS就会将字符串通过隐性调用new String(str)
的方式转换成对象,这个对象继承了字符串的方法,并被用来处理属性的引用。一旦属性引用结束,这个新创建的对象就会销毁(所以最后调用时undefined
)这个过程就叫包装对象。
对于以上方法,可以直接显式地创建包装对象
var str=new String("seiei");
str.tall="190";
console.log(str.tall);//190
typeOf str;//object
2 那么为什么平时使用字符串就可以调用诸如indexOf
的方法呢?
其实,在我们调用这些方法和属性时,JS内部已经隐式地帮我们帮创建了一个包装对象了,以上的实际的情形应该是这样的:
console.log("this a string".indexOf("a"));
console.log(new String("this a string").indexOf("a"));//隐性创建一个字符串对象
引用类型和包装类型的主要区别是对象的生存期。
使用new
操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。
而自动创建的基本包转类型的对象,则只存在于一行代码的执行期间,然后立即被销毁,这也意味着我们不能在运行时为基本类型添加属性和方法。
1.2 小总结
没有使用new时,Number()、Boolean和String()被当做普通函数,把任何类型的数据转换为
number
、boolean
和string
类型。
还有几个规则要注意:
- 用
String()
来转换任意类型到string,或者直接调用某个对象的toString()
方法,但null
和undefined
就没有toString()
方法,而且调用number时,语法是这样的:(num).toString();
var b2 = Boolean('false');
像这样的转换布尔值,其值为true,因为字串符不为空。- 判断Array要使用
Array.isArray(arr);
(注意这是一个整体,arr为参数) - 判断
null
要使用arg === null;
- 判断某个全局变量是否存在用
typeof window.arg === 'undefined';
- 函数内部判断某个变量是否存在用
typeof myVar === 'undefined'
- 判断给定属性是否在当前实例中(不包活继承而来的)使用
obj.hasOwnProperty(propertyname);
方法 - 检查传入对象是否为当前对象的原型,使用
obj1.isPrototypeof(obj2)
2 Math对象
JS中除了加减乘除有相对应的符号外,诸如平方开方的算法都得依靠Math对象,Math对象的方法有很多,以下选取一些常用的:
Math.random();//随机0~1之间的数值
Math.abs(x);//绝对值
Math.ceil(x);//向上取整,如4.1 --> 5, (-5.9) --> (-5)
Math.round(x);//四舍五入,如(-5.52)-->-6
Math.floor(x);//向下取整
Math.max(x,y);//最大
Math.min(x,y);//最小
Math.pow(x,y);//x的y次方
Math.sqrt(x);//开方
3 Date对象
在JavaScript中,Date对象用来表示日期和时间。
获取系统当前时间,如下:
var now = new date();
now; //2017-07-15T15:04:31.807Z
now.getFullYear(); //2017
now.setFullYear(2017);//设定年份,下面的都可以这样设置
now.getMonth(); //6,注意!!!月份范围是0~11,6表示7月!!
now.getDate(); //15
now.getDay(); //6,这是星期
now.getHours(); //23
now.getMinutes(); //11
now.getSeconds(); //23
now.getMilliseconds(); //49,毫秒
now.getTime(); //1500131686539,时间戳
(new Date(2018, 2, 0)).getDate(); // 求出一个月的天数
如果想要创建一个指定时间的Date对象:
第一种方法是:
var d = new Date(2017,6,15,23,18,30,123);//注意月份
第二种方法是解析字串符:
var d = Date.parse('2015-06-24T19:49:22.875+08:00');//返回时间戳
var d = new Date(1435146562875); //转化时间戳
显示本地时间,也可以显示调整后的UTC时间
var d = new Date();
d.toLocaleString();//2017-07-15 23:25:05,显示的字符串与操作系统设定的格式有关
d.toUTCString();//Sat, 15 Jul 2017 15:26:15 GMT,相差8小时
不厌其烦,注意月份取值范围是0~11。
4 RegExp对象(正则表达式)
正则表达式规范都是通用的,所以python那边也可以重温一下。
4.1 字符描述字符
正则表达式字符描述字符:
\d
:任意数字\D
:匹配任意非数字字符\w
:任意字母或数字 以及 下划符\W
:匹配任意的非单词字符\s
:空格或 Tab 键\S
:匹配任意非空格字符.
:任意字符*
:零个或多个?
:一个或没有+
:至少一个{n}
:n个{n,m}
:n到m个{n,}
:n个以上(a|b)
:a或者b[]
:匹配范围内的字符,字母和数字可以使用-
表示连续的范围,如[a-f0-9]
表示匹配 一个 字符是a
到f
之间的某个字母或1
到9
之间的数字[^...]
:匹配非范围内的字符,如[^1-9]
()
:用于分组^
:用于行头$
:用于结尾\u548c
(和
):指定Unicode字符
4.2 创建正则表达式
JavaScript有两种方式创建一个正则表达式:
第一种是直接通过这样的形式 /正则表达式/
写出来:
var re = /ABC\-001/; //ABC-001
第二种是通过new RegExp('正则表达式')
创建一个RegExp对象(这是使用字串符,要注意双重转义):
var re = new RegExp("ABC\\-001"); //ABC-001
由于第二种方法使用的是字符串,所以在定义
\
符号时,要注意转义问题
RegExp对象的test()
方法用于测试给定的字符串是否符合条件:
re.test("010-12345");//true
4.3 切分字符串
如同python一样,用正则表达式切分字符串比用固定的字符更灵活
'a b c'.split(/\s+/); // ['a', 'b', 'c']
4.4 分组提取
恰当地使用()
分组,正则表达式就可以使用提取子串的强大功能。
在RegExp对象上用exec()
方法提取出子串来,会返回一个Array(第一个元素是正则表达式匹配到的整个字符串,后面的字符串表示匹配成功的子串)。
var re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-12345'); // ['010-12345', '010', '12345']
4.5 贪婪匹配
采用非贪婪匹配只需在后方加上?
符号就可以了:
var re = /^(\d+?)(0*)$/; //\d+后加上?
re.exec('102300'); // ['102300', '1023', '00']
4.6 全局搜索
JavaScript的正则表达式还有几个特殊的标志,最常用的是g,表示全局匹配,语法:
/* 二者等价 */
var re=/[a-zA-Z]+Script/g;
var re =new RegExp("[a-zA-Z]+Script","g");
/* 可多次执行exec()方法来搜索一个匹配的字符串。当我们指定g标志后,每次运行exec(),正则表达式本身会更新lastIndex属性,表示上次匹配到的最后索引 */
var s = 'JavaScript, VBScript, JScript and ECMAScript';
re.exec(s); // ['JavaScript']
re.lastIndex; // 10,上次匹配到的最后索引
re.exec(s); // ['VBScript']
re.lastIndex; // 20
re.exec(s); // ['JScript']
re.lastIndex; // 29
re.exec(s); // ['ECMAScript']
re.lastIndex; // 44
re.exec(s); // null,直到结束仍没有匹配到
因此全局搜索不能使用
/^...$/
限定行头行尾,那样只会最多匹配一次。
5 JSON对象
JSON是JavaScript Object Notation的缩写,它是一种数据交换格式。
JSON实际上是JavaScript的一个子集。几乎所有编程语言都有解析JSON的库,而在JavaScript中,我们可以直接使用JSON,因为JavaScript内置了JSON的解析。
把JavaScript对象变成JSON,就是把这个对象序列化成一个JSON格式的字符串,这样才能够通过网络传递给其他计算机。
如果我们收到一个JSON格式的字符串,只需要把它反序列化成一个JavaScript对象,就可以在JavaScript中直接使用这个对象了。
##5.1 对象序列化
序列化对象,使用JSON.stringify()
,如:
var xiaoming = {
name:"小明"
}
JSON.stringify(xiaoming);//'{"name":"小明"}'
JSON.stringify()
其实可以接受三个参数,第一个对象,第二个参数用于控制如何筛选对象的键值(只是键值),第三个用于输出时按缩进输出。
第二个参数可以输入Array,出指定的属性
也可以传入一个函数,这样对象的每个键值对都会被函数先处理。
var xiaoming = {
"name": "小明",
"age": 14,
"gender": true,
"height": 1.65,
"grade": null,
"middle-school": "\"W3C\" Middle School",
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}
JSON.stringify(xiaoming, ['name', 'skills'], ' ');//只输出name以及skills属性,还有输出缩进
function convert(key, value) {
if (typeof value === 'string') {
return value.toUpperCase();
}
return value;
}
JSON.stringify(xiaoming, convert, ' ');//大写键值,还有输出缩进
5.2 反序列化
拿到一个JSON格式的字符串,我们直接用JSON.parse()
把它变成一个JavaScript对象,如:
JSON.parse('{"name":"小明","age":14}'); // Object {name: '小明', age: 14}
同样的JSON.parse()
也可以接受函数(Array无效),用来转换解析出的属性
var func = function (key,value) {
if(typeof(value) === "string") {
return value.toUpperCase()
}
return value
};
JSON.parse('{"name":"小明","skill":"python"}',func);//{name:"小明",skill:"PYTHON"}
6 promise对象
Promise
是异步编程的一种解决方案,所谓Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise
是一个对象,从它可以获取异步操作的消息。
Promise
对象代表一个异步操作(test()
函数),有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。
当调用已成功函数返回另一个Promise
对象时,会导致本身的状态无效了,由返回的Promise
对象的状态决定其本身的状态。
,如果不设置回调函数如(
then()
,catch()
),Promise内部抛出的错误
下面代码创造了一个Promise实例:
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
promise.then(vaule => console.log(value)).catch(err =>console.log(error))
Promise实例构造函数接受一个操作函数,然后这个操作函数分别接受两个函数,即reject
以及resolve
函数,可以用then
方法分别指定resolved
状态的回调函数,使用catch
指定reject
状态的回调函数。
下面是一个使用Promise对象实现Ajax 操作的例子:
function ajax (method,url,data) {
var promise = new Promise(function(resolve,reject){
var request = new XMLHttpResquest();
request.onreadystatuschange = function(){
if ( request.readyState === 4 ) {
if ( request.status ===200 ) {
resolve(request.reponseText)
} else {
reject(request.status);
}
}
}
request.open(method,url);
request.send(data)
});
return promise
}
var p = ajax('GET', '/api/categories');
p.then(function (text) { // 如果AJAX成功,获得响应内容
log.innerText = text;
}).catch(function (status) { // 如果AJAX失败,获得响应代码
log.innerText = 'ERROR: ' + status;
});