唐抉的个人博客

前端三件套之JavaScript(三)

字数统计: 5.8k阅读时长: 27 min
2022/11/01

标准对象

在JavaScript的世界里,一切皆是对象。但某些对象与其他对象不太一样。为了区分对象的类型,通常用typeof操作符获取对象的类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
console.log(typeof 123);
console.log(typeof NaN);
console.log(typeof 'str');
console.log(typeof true);
console.log(typeof undefined);
console.log(typeof Math.abs);
console.log(typeof null);
console.log(typeof []);
console.log(typeof {});

/*运行结果如下:
number
number
string
boolean
undefined
function
object
object
object
*/

注意,null、Array的类型都是object,若用typeof将无法区分出null、Array和object。

包装对象

除了这些类型外,JavaScript还提供了包装对象。Numberbooleanstring都有包装对象。包装对象用new创建:

1
2
3
4
5
6
7
8
9
10
11
var n=new Number(123);
var b=new Boolean(true);
var s=new String('str');
console.log(n);
console.log(b);
console.log(s);
/*运行结果如下:
Number (123)
Boolean (true)
String ('str')
*/

虽然包装对象看上去和原来的值一样,但类型已经变为object了,用===与原始值比较会返回false

1
2
3
4
5
6
7
8
9
10
11
var n=new Number(123);
var b=new Boolean(true);
var s=new String('str');
console.log(n===123);
console.log(b===true);
console.log(s==='str');
/*运行结果如下:
false
false
false
*/

因此,要注意以下几点:

  • 不要使用new Number()new Boolean()new String()创建包装对象
  • parseInt()parseFloat()来转换任意类型的number
  • Sting()来转换任意类型到string,或直接调用某个对象的toString()方法,只有nullundedined没有toString()方法,number对象调用toString()要写成:123..toString();(123).toStirng();
  • 通常不用把任意类型转换为boolean再判断
  • typeof可以判断出numberbooleanstringfunctionundefined
  • 判断Array要用Array.isArray(arr)
  • 判断null要用myvar===null
  • 判断某个全局变量是否存在用typeof window.myvar==='undefined'
  • 函数内部判断某个变量是否存在用typeof myvar==='undefined'

Date

在JavaScript里,Date对象用来表示日期和时间。

用Date获取系统时间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var now=new Date();
console.log(now);//显示当前的时间
console.log(now.getFullYear());//显示今年
console.log(now.getMonth());//显示这个月,月份范围是0~11,10表示11月
console.log(now.getDate());//显示今天多少号
console.log(now.getDay());//显示今天星期几
console.log(now.getHours());//显示现在几时,24小时制
console.log(now.getMinutes());//显示现在是多少分钟
console.log(now.getSeconds());//显示现在是多少秒
console.log(now.getMilliseconds());//显示现在是多少毫秒
console.log(now.getTime());//以number形式表示的时间戳

/*运行结果如下:
Tue Nov 01 2022 11:01:14 GMT+0800 (中国标准时间)
2022
10
1
2
11
1
14
217
1667271674217
*/

当前时间是浏览器从本机操作系统获取的时间所以不一定准确。

若要创建一个指定日期和时间的Date对象,可以用:

1
2
3
4
5
var d=new Date(2015,5,19,20,15,30,123);
console.log(d);
/*运行结果如下:
Fri Jun 19 2015 20:15:30 GMT+0800 (中国标准时间)
*/

第二种创建一个指定日期和时间的方法是解析一个符号ISO 8601格式的字符串:

1
2
3
4
5
6
7
8
var d=Date.parse('2015-06-24T19:49:22.875+08:00');
console.log(d);//返回时间戳
var dd=new Date(d)//时间戳转Date
console.log(dd);
/*运行结果如下:
1435146562875
Wed Jun 24 2015 19:49:22 GMT+0800 (中国标准时间)
*/

时区

Date对象表示的时间总是按浏览器所在时区显示的,不过既可以显示本地时间,也可以显示调整后的UTC时间:

1
2
3
4
5
6
7
8
9
10
var d=Date.parse('2015-06-24T19:49:22.875+08:00');
console.log(d);
var dd=new Date(d)
console.log(dd.toLocaleString());//显示的字符串与操作系统设定的格式有关
console.log(dd.toUTCString());//UTC时间与本地时间相差8小时
/*运行结果如下:
1435146562875
2015/6/24 19:49:22
Wed, 24 Jun 2015 11:49:22 GMT
*/

获取当前时间戳:

1
2
3
4
5
6
7
8
if(Date.now){
console.log(Date.now());
}else{//老版本IE没有now()方法
console.log(new Date().getTime());
}
/*运行结果如下:
1667272652007
*/

练习题

小明为了和女友庆祝情人节,特意制作了网页,并提前预定了法式餐厅。小明打算用JavaScript给女友一个惊喜留言,结果女友并未出现。小明非常郁闷,请你帮忙分析他的JavaScript代码有何问题:

1
2
3
4
var today = new Date();
if (today.getMonth() === 2 && today.getDate() === 14) {
alert('亲爱的,我预定了晚餐,晚上6点在餐厅见!');
}

修改后的代码如下:

1
2
3
4
5
//分析:JavaScript中getMonth() 实际时间为0~11,数值为2时,实际月份为3。
var today = new Date();
if (today.getMonth() === 1 && today.getDate() === 14) {
alert('亲爱的,我预定了晚餐,晚上6点在餐厅见!');
}

RegExp

JavaScript有两种方式创建一个正则表达式:

第一种是直接通过/正则表达式/写出来,第二种是通过new RegExp(正则表达式)创建一个RegExp对象。

1
2
3
4
5
6
7
8
var re1=/ABC\-001/;
var re2=new RegExp('ABC\\-001');
console.log(re1);
console.log(re2);
/*运行结果如下:
/ABC\-001/
/ABC\-001/
*/

判断正则表达式是否匹配:

1
2
3
4
5
6
7
8
9
var re=/^\d{3}\-\d{3,8}$/;
console.log(re.test('010-12345'));
console.log(re.test('010-1234x'));
console.log(re.test('010 12345'));
/*运行结果如下:
true
false
false
*/

切分字符串

用正则表达式切分字符串:

1
2
3
4
console.log('a b  c , ; ; d'.split(/[\s\,\;]+/));
/*运行结果如下:
(4) ['a', 'b', 'c', 'd']
*/

分组

正则表达式用()表示要提取的分组,可以提取子串。若正则表达式种定义了组,就可以在RegExp对象上用exec()方法提取出子串来:

1
2
3
4
5
6
7
var re=/^(\d{3})-(\d{3,8})$/;
console.log(re.exec('010-12345'));
console.log(re.exec('010 12345'));
/*运行结果如下:
(3) ['010-12345', '010', '12345', index: 0, input: '010-12345', groups: undefined]
null
*/

exec()方法在匹配成功后会返回一个Array,第一个元素是正则表达式匹配到的整个字符串,后面的字符串表示匹配成功的子串。在匹配失败是返回null

正则表达式可以直接识别合法的世界,但无法做到完全识别日期:

1
2
3
4
5
6
7
8
var re1=/^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-0]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-0]|3[0-9]|4[0-9]|5[0-9]|[0-9])$/;
console.log(re1.exec('11:43:59'));
var re2=/^(0[1-9]|1[0-2]|[0-9])-(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[0-9])$/;
console.log(re2.exec('2-30'));//2-30号不存在,应该返回null
/*运行结果如下:
(4) ['11:43:59', '11', '43', '59', index: 0, input: '11:43:59', groups: undefined]
(3) ['2-30', '2', '30', index: 0, input: '2-30', groups: undefined]
*/

贪婪匹配

正则匹配默认是贪婪匹配。在需要培贪婪匹配的语句后加问号?,可以让该语句采用非贪婪匹配。

全局搜索

JavaScript的正则表达式有几个特殊的标志,最常用的是全局匹配g

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var s='JavaScript,VBScript,JScript and ECMAScript';
var re=/[a-zA-Z]+Script/g;//使用全局匹配
console.log(re.exec(s));
console.log(re.lastIndex);

console.log(re.exec(s));
console.log(re.lastIndex);

console.log(re.exec(s));
console.log(re.lastIndex);

console.log(re.exec(s));
console.log(re.lastIndex);

console.log(re.exec(s));//直至结束都没有匹配到
/*运行结果如下:
(1) ['JavaScript', index: 0, input: 'JavaScript,VBScript,JScript and ECMAScript', groups: undefined]
10
(1) ['VBScript', index: 11, input: 'JavaScript,VBScript,JScript and ECMAScript', groups: undefined]
19
(1) ['JScript', index: 20, input: 'JavaScript,VBScript,JScript and ECMAScript', groups: undefined]
27
(1) ['ECMAScript', index: 32, input: 'JavaScript,VBScript,JScript and ECMAScript', groups: undefined]
42
null
*/

JavaScript的正则表达式还可以指定i标志,表示忽略大小写;m标志表示执行多行匹配。

练习题

请尝试写一个验证Email地址的正则表达式。版本一应该可以验证出类似的Email:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var re = /^([a-z\.0-9])+@+([a-z0-9]+\.+[a-z]{3})$/;

// 测试:
var
i,
success = true,
should_pass = ['someone@gmail.com', 'bill.gates@microsoft.com', 'tom@voyager.org', 'bob2015@163.com'],
should_fail = ['test#gmail.com', 'bill@microsoft', 'bill%gates@ms.com', '@voyager.org'];
for (i = 0; i < should_pass.length; i++) {
if (!re.test(should_pass[i])) {
console.log('测试失败: ' + should_pass[i]);
success = false;
break;
}
}
for (i = 0; i < should_fail.length; i++) {
if (re.test(should_fail[i])) {
console.log('测试失败: ' + should_fail[i]);
success = false;
break;
}
}
if (success) {
console.log('测试通过!');
}
/*运行结果如下:
测试成功!
*/

版本二可以验证并提取出带名字的Email地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
var re = /^<?([a-zA-Z]+\s?[a-zA-Z]+)>?\s?([a-zA-Z]*@[a-zA-Z]+\.[a-zA-Z]+)$/;

// 测试:
var r = re.exec('<Tom Paris> tom@voyager.org');
if (r === null || r.toString() !== ['<Tom Paris> tom@voyager.org', 'Tom Paris', 'tom@voyager.org'].toString()) {
console.log('测试失败!');
}
else {
console.log('测试成功!');
}
/*运行结果如下:
测试成功!
*/

JSON

JSON是一种数据交换格式,字符集必须是UTF-8。为了统一解析,JSON的字符串规定必须用双引号"",Object的键也必须用双引号""

JavaScript内置了JSON的解析,把任何JavaScript对象序列化成一个JSON格式的字符串,才能通过网络传递给其他计算机。

序列化

JSON.stringify()把JavaScript对象序列化成JSON格式的字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
var person={
name:'zhangsan',
age:18,
gender:true,
height:1.65,
grade:null,
'middel-school':'No.1 Middle School',
skills:['JavaScript','Java','Python','Lisp']
};
var s=JSON.stringify(person);
console.log(s);
/*运行结果如下:
{"name":"zhangsan","age":18,"gender":true,"height":1.65,"grade":null,"middel-school":"No.1 Middle School","skills":["JavaScript","Java","Python","Lisp"]}*/

JSON.stringify()还可以通过参数来控制按缩进输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var s=JSON.stringify(person,null,' ');
console.log(s);
/*运行结果如下:
{
"name": "zhangsan",
"age": 18,
"gender": true,
"height": 1.65,
"grade": null,
"middel-school": "No.1 Middle School",
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}*/

其第二个参数用于控制如何筛选对象的键值,如:

1
2
3
4
5
6
7
8
9
10
11
12
var s=JSON.stringify(person,['name','skills'],' ');
console.log(s);
/*运行结果如下:
{
"name": "zhangsan",
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}*/

还可以往第二个参数里传入一个函数,使得对象的每个键值对都会被函数先处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function convert(key,value){
if(typeof value==='string'){
return value.toUpperCase();
}
return value;
}
var s=JSON.stringify(person,['name','skills'],' ');
console.log(s);
/*运行结果如下:
E:\node.exe .\test.js
{
"name": "ZHANGSAN",
"age": 18,
"gender": true,
"height": 1.65,
"grade": null,
"middel-school": "NO.1 MIDDLE SCHOOL",
"skills": [
"JAVASCRIPT",
"JAVA",
"PYTHON",
"LISP"
]
}*/

除此之外,还可以给person对象定义一个toJSON()的方法,直接返回序列化数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var person={
name:'zhangsan',
age:18,
gender:true,
height:1.65,
grade:null,
'middel-school':'No.1 Middle School',
skills:['JavaScript','Java','Python','Lisp'],
toJSON:function(){
return{
'Name':this.name,
'Age':this.age
};
}
};
var s=JSON.stringify(person);
console.log(s);
/*运行结果如下:
{"Name":"zhangsan","Age":18}*/

反序列化

把一个JSON格式的字符串,用JSON.parse()把它变成一个JavaScript对象:

1
2
3
4
5
6
7
8
9
console.log(JSON.parse('[1,2,3,true]'));
console.log(JSON.parse('{"name":"zhangsan","age":14}'));
console.log(JSON.parse('true'));
console.log(JSON.parse('123.45'));
/*运行结果如下:
(4) [1, 2, 3, true]
{name: 'zhangsan', age: 14}
true
123.45*/

JSON.parse()还可以接收一个函数,用来转换解析出的属性:

1
2
3
4
5
6
7
8
9
var obj=JSON.parse('{"name":"zhangsan","age":14}',function(key,value){
if (key==='name'){
return value+' classmate';
}
return value;
});
console.log(JSON.stringify(obj));
/*运行结果如下:
{"name":"zhangsan classmate","age":14}*/

面向对象编程

在JavaScript种不区分类和实例的概念,而是通过原型(prototype)来实现面向对象编程。所谓的继承关系是把对象的原型指向另一个对象。

以下是创建原型继承的一种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var Student={
name:'Robot',
heighe:1.2,
run:function(){
console.log(this.name+' is running...');
}
};
function createStudent(name){
var s=Object.create(Student);
s.name=name;
return s;
}
var zhangsan=createStudent('ZhangSan');
zhangsan.run();
console.log(zhangsan.__proto__===Student);
/*运行结果如下:
ZhangSan is running...
true*/

创建对象

除了直接用{...}创建一个对象外,JavaScript还可以用构造函数的方法来创建对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//定义构造函数
function Student(name){
this.name=name;
this.hello=function(){
console.log('Hello, '+this.name+'!');
}
}
//调用构造函数,返回一个对象
var zhangsan=new Student('ZhangSan');
console.log(zhangsan.name);
zhangsan.hello();
/*运行结果如下:
ZhangSan
Hello, ZhangSan!*/

注意:若不写newstudent就是一个普通函数,它返回undefined,若写了newstudent就是一个构造函数,它绑定的this指向新创建的对象,并默认返回this

new Student()创建的对象还从原型上获得了一个constructor属性,它指向函数Student本身:

1
2
3
4
5
6
7
8
console.log(zhangsan.constructor===Student.prototype.constructor);
console.log(Student.prototype.constructor===Student);
console.log(Object.getPrototypeOf(zhangsan)===Student.prototype);
/*运行结果如下:
true
true
true
*/

上述代码主要描述以下关系:

若要让通过构造函数创建的对象共享一个hello函数,将函数放到这些对象共同的原型Student.prototype上即可:

1
2
3
4
5
6
7
8
9
10
11
function Student(name){
this.name=name;
}
Student.prototype.hello=function(){
console.log('Hello, '+this.name+'!');
};
var zhangsan=new Student('ZhangSan');
zhangsan.hello();
/*运行结果如下:
Hello, ZhangSan!
*/

构造函数的首字母应当大写,普通函数首字母应当小写。

可以编写一个函数,在内部封装所有的new操作:

1
2
3
function createStudent(props){
return new Student(props||{})
}

练习题

请利用构造函数定义Cat,并让所有的Cat对象有一个name属性,并共享一个方法say(),返回字符串'Hello, xxx!'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Cat(name) {
this.name=name;
}
Cat.prototype.say=function(){
return 'Hello, '+this.name+'!';
}
// 测试:
var kitty = new Cat('Kitty');
var doraemon = new Cat('哆啦A梦');
if (kitty && kitty.name === 'Kitty'
&& kitty.say
&& typeof kitty.say === 'function'
&& kitty.say() === 'Hello, Kitty!'
&& kitty.say === doraemon.say
) {
console.log('测试通过!');
} else {
console.log('测试失败!');
}
/*运行结果如下:
测试通过!
*/

原型继承

JavaScript的原型继承实现方式为:

  1. 定义新的构造函数,并在内部用call()调用希望“继承”的构造函数,并绑定this
  2. 借助中间函数F实现原型链继承,最好通过封装的inherits函数完成;
  3. 继续在新的构造函数原型上定义新方法。

现有一构造函数Student

1
2
3
4
5
6
7
//Student的构造函数
function Student(props){
this.name=props.name||'Unnamed';
}
Student.prototype.hello=function(){
console.log('Hello, '+this.name+'!');
}

Student的原型链如下:

现在要基于Student扩展出PrimaryStudent。因此先定义新的构造函数PrimaryStudent

1
2
3
4
5
//新构造函数
function PrimaryStudent(props){
Student.call(this.props);
this.grade=props.grade||1;
}

利用空函数F来修改原型链,使得PrimaryStudent指向Student.prototype

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//Student的构造函数
function Student(props){
this.name=props.name||'Unnamed';
}
Student.prototype.hello=function(){
console.log('Hello, '+this.name+'!');
}

//新构造函数PrimaryStudent
function PrimaryStudent(props){
Student.call(this,props);//调用Student构造函数,绑定this变量
this.grade=props.grade||1;
}
//空函数F
function F(){
}
F.prototype=Student.prototype;//将F的原型指向Student.prototype
PrimaryStudent.prototype=new F();//将PrimaryStudent的原型指向一个新的F对象
PrimaryStudent.prototype.constructor=PrimaryStudent;//将PrimaryStudent原型的构造函数指向PrimaryStudent
PrimaryStudent.prototype.getGrade=function(){//在PrimaryStudent原型的构造函数上定义方法
return this.grade;
};
var lisi=new PrimaryStudent({//创建lisi
name:'lisi',
grade:3
});
console.log(lisi.name);
console.log(lisi.grade);

//验证原型
console.log(lisi.__proto__===PrimaryStudent.prototype);
console.log(lisi.__proto__.__proto__===Student.prototype);

//验证继承关系
console.log(lisi instanceof PrimaryStudent);
console.log(lisi instanceof Student);

/*运行结果如下:
lisi
3
true
true
true
true
*/

此时的新型原型链如下:

如果把整个继承动作用一个inherits()函数封装起来,还可以隐藏空函数F的定义,inherits()函数可以复用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Student的构造函数
function Student(props){
this.name=props.name||'Unnamed';
}
Student.prototype.hello=function(){
console.log('Hello, '+this.name+'!');
}

//新构造函数PrimaryStudent
function PrimaryStudent(props){
Student.call(this,props);//调用Student构造函数,绑定this变量
this.grade=props.grade||1;
}
function inherits(Child,Parent){
var F=function(){};
F.prototype=Parent.prototype;
Child.prototype=new F();
Child.prototype.constructor=Child;
}
inherits(PrimaryStudent,Student);//实现原型继承链
PrimaryStudent.prototype.getGrade=function(){//绑定其他方法到PrimaryStudent原型
return this.grade;
};
var lisi=new PrimaryStudent({//创建lisi
name:'lisi',
grade:3
});
console.log(lisi.name);
console.log(lisi.grade);
/*运行结果如下:
lisi
3
*/

class继承

class定义

ES6中引入了新的关键字class,使类的定义更简单。

class定义Student类并创建一个对象如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Student{
constructor(name){
this.name=name;
}
hello(){
console.log('Hello, '+this.name+'!');
}
}
var lisi=new Student('Lisi');
lisi.hello();
/*运行结果如下:
Hello, Lisi!
*/

原型继承

可以通过extends实现原型继承:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Student{
constructor(name){
this.name=name;
}
hello(){
console.log('Hello, '+this.name+'!');
}
}

class PrimaryStudent extends Student{
constructor(name,grade){
super(name);//用super调用父类的构造方法
this.grade=grade;
}
myGrade(){
console.log('I am at grade '+this.grade);
}
}
var lisi=new PrimaryStudent('Lisi',3);
lisi.hello();
lisi.myGrade();
/*运行结果如下:
Hello, Lisi!
I am at grade 3
*/

不是所有的浏览器都支持ES6的class,当浏览器不支持时,需要Babel这个工具把class代码转换为传统的prototype代码。

练习题

请利用class重新定义Cat,并让它从已有的Animal继承,然后新增一个方法say(),返回字符串'Hello, xxx!'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Animal {
constructor(name) {
this.name = name;
}
}

class Cat extends Animal{
constructor(name){
super(name);
}
say(){
return 'Hello, '+this.name+'!';
}
}
// 测试:
var kitty = new Cat('Kitty');
var doraemon = new Cat('哆啦A梦');
if ((new Cat('x') instanceof Animal)
&& kitty
&& kitty.name === 'Kitty'
&& kitty.say
&& typeof kitty.say === 'function'
&& kitty.say() === 'Hello, Kitty!'
&& kitty.say === doraemon.say)
{
console.log('测试通过!');
} else {
console.log('测试失败!');
}
/*运行结果如下:
测试通过!
*/

浏览器

目前主流的浏览器分为以下几种:

  • IE6-11:国内用的最多的IE浏览器,从IE10开始支持ES6标准
  • Chrome:Google出品的基于Webkit内核浏览器,由于Chrome一经安装就时刻保持自升级,因此不用管它的版本,最新版肯定支持ES6
  • Safari:Apple的Mac系统自带的基于Webkit内核浏览器,从OSX 10.7 Lion自带的6.1版本开始支持ES6
  • Firefox:Mozilla自研的Gecko内核,也是时刻保持自升级。
  • 移动设备上目前IOS和Android两大阵营分别主要使用Apple的Safari和Google的Chrome,两种都是Webkit核心,最新版本均支持ES6

浏览器对象

JavaScript可以获取浏览器提供的很对对象,并进行操作。

window

window对象不但充当全局作用域,而且表示浏览器窗口。

window对象有innerWidthinnerHeight属性,可以获取浏览器窗口的内部宽度和高度。内部宽高是指出去菜单栏、工具栏、边框等占位元素后,用于显示页面的净宽高。IE<=8版本的浏览器不支持这一特性:

1
2
3
4
console.log('window inner size: '+window.innerWidth+'x'+window.innerHeight);
/*运行结果如下:
window inner size: 987x752
*/

与之对应的,还有一个outerWidthouterHeight属性,可以获取浏览器窗口的整个宽高。

navigator对象表示浏览器的信息,最常用的属性包括:

  • navigator.appName:浏览器名称
  • navigator.appVersion:浏览器版本
  • navigator.language:浏览器设置的语言
  • navigator.platform:操作系统类型
  • navigator.userAgent:浏览器设定的user-Agent字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
console.log('appName='+navigator.appName);
console.log('appVersion='+navigator.appVersion);
console.log('language='+navigator.language);
console.log('platform='+navigator.platform);
console.log('userAgent='+navigator.userAgrnt);
/*运行结果如下:
appName=Netscape
Users/Administrator/Desktop/test.js:1
appVersion=5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.26
Users/Administrator/Desktop/test.js:2
language=zh-CN
Users/Administrator/Desktop/test.js:3
platform=Win32
Users/Administrator/Desktop/test.js:4
userAgent=undefined
*/

注意,由于navigator的信息很容易被用户修改,所以常用JavaScript对不存在属性返回unfinded的特性,计算浏览器的信息是否又被改动:

1
var width=window.innerWith||document.body.clientWidth;

screen

screen对象表示屏幕的信息,常用的属性有:

  • screen.width:屏幕宽度,以像素为单位
  • screen.height:屏幕高度,以像素为单位
  • sreen.colorDepth:返回颜色位数,如8、16、24
1
2
3
4
console.log('Screen size='+screen.width+'x'+screen.height);
/*运行结果如下:
Screen size=1440x900
*/

location

location对象表示当前页面的URL信息。一个完整的URL可以用location.href获取。要获取URL各部分的值,可以这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//如URL:http://www.example.com:8080/path/index.html?a=1&b=2#TOP
console.log(location.protocol);
console.log(location.host);
console.log(location.post);
console.log(location.pathname);
console.log(location.search);
console.log(location.hash);
/*运行结果如下:
http
www.example.com
8080
/path/index.html
a=1&b=2
TOP
*/

要加载一个新页面,可以调用location.assign()方法,要重新加载当前页面,可以调用location.reload()方法:

1
2
3
4
5
if(confirm('要重新加载当前页'+location.href+'?')){
location.reload();
}else{
location.assign('/');//设置一个新的URL地址
}

document

document对象表示当前页面。由于HTML在浏览器中以DOM形式表示为树形结构,document对象就是整个DOM树的根节点。

document的title属性是从HTML文档中的<title>...</title>读取的,但其也可以动态改变:

1
document.title='helloJavaScript!';//修改浏览器窗口标题

若要查找DOM树的某个节点,需要从document对象开始查找。最常用的方法是根据ID和Tag Name。

有一HTML数据如下:

1
2
3
4
5
6
7
8
<dl id="drink-menu" style="border:solid 1px #ccc;padding:6px;">
<dt>摩卡</dt>
<dd>热摩卡咖啡</dd>
<dt>酸奶</dt>
<dd>北京老酸奶</dd>
<dt>果汁</dt>
<dd>鲜榨苹果汁</dd>
</dl>

用document对象提供的getElementById()getElementsByTagName()可以按ID获得一个DOM节点和按Tag名称获得一组DOM节点:

1
2
3
4
5
6
7
8
9
10
11
var menu=document.getElementById('drink-menu');
var drinks=document.getElementsByTagName('dt');
var i,s;
s='提供的饮料有:';
for(i=0;i<drinks.length;i++){
s=s+drinks[i].innerHTNL+',';
}
console.log(s);
/*运行结果如下:
提供的饮料有:摩卡,酸奶,果汁,
*/

document对象还有一个cookie属性,可以获取当前页面的Cookie:

1
console.log(document.cookie);

由于JavaScript能读到页面的Cookie,而用户的登录信息通常也存在Cookie中,且HTML页面中允许引入第三方的JavaScript代码。为了防止第三方的JavaScript直接能获取网站的用户登录信息,服务器在设置Cookie时可以使用httpOnly,以防止被JavaScript读取。IE浏览器从IE6 SP1开始支持。

history

history对象保持了浏览器的历史记录,JavaScript可以调用history对象的back()forward(),相当于用户点击了浏览器的后退或前进按钮。在任何情况都不应该使用history这个对象。

CATALOG
  1. 1. 标准对象
    1. 1.1. Date
    2. 1.2. 时区
      1. 1.2.1. 练习题
    3. 1.3. RegExp
      1. 1.3.1. 切分字符串
      2. 1.3.2. 分组
      3. 1.3.3. 贪婪匹配
      4. 1.3.4. 全局搜索
      5. 1.3.5. 练习题
    4. 1.4. JSON
      1. 1.4.1. 序列化
      2. 1.4.2. 反序列化
  2. 2. 面向对象编程
    1. 2.1. 创建对象
      1. 2.1.1. 练习题
    2. 2.2. 原型继承
    3. 2.3. class继承
      1. 2.3.1. class定义
      2. 2.3.2. 原型继承
      3. 2.3.3. 练习题
  3. 3. 浏览器
    1. 3.1. 浏览器对象
      1. 3.1.1. window
      2. 3.1.2. navigator
      3. 3.1.3. screen
      4. 3.1.4. location
      5. 3.1.5. document
      6. 3.1.6. history