唐抉的个人博客

前端三件套之JavaScript(三)

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

标准对象

在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. 时区
    3. 1.3. RegExp
    4. 1.4. JSON
  2. 2. 面向对象编程
  3. 3. 浏览器