JavaScript-函数、标准对象

JavaScript-函数、标准对象

1. 函数

1. 定义函数

  • 函数就和Java中的方法是一样的,说白了,就是一系列语句的集合,我们可以提取出来实现复用!

在JavaScript中,定义函数的方式如下:

1
2
3
4
5
6
7
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
  • function指出这是一个函数定义;
  • abs是函数的名称;
  • (x)括号内列出函数的参数,多个参数以,分隔;
  • { ... }之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。

函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。

因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。

如果没有return语句,函数执行完毕后也会返回结果,只是结果为undefined。

第二种定义函数的方式如下:

1
2
3
4
5
6
7
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};

在这种方式下,function (x) { … }是一个匿名函数,它没有函数名。但是,这个匿名函数赋值给了变量abs,所以,通过变量abs就可以调用该函数。

上述两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个;,表示赋值语句结束。

2. 调用函数

调用函数时,按顺序传入参数即可:

1
2
abs(10); // 返回10
abs(-9); // 返回9

由于JavaScript允许传入任意个参数而不影响调用,因此传入的参数比定义的参数多也没有问题,虽然函数内部并不需要这些参数:

1
2
abs(10, 'blablabla'); // 返回10
abs(-9, 'haha', 'hehe', null); // 返回9

传入的参数比定义的少也没有问题:

1
abs(); // 返回NaN

要避免收到undefined,可以对参数进行检查:

1
2
3
4
5
6
7
8
9
10
11
function abs(x) {
//类型比较,和抛出异常~
if (typeof x !== 'number') {
throw 'Not a number';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
  • arguments 它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。利用arguments,你可以获得调用者传入的所有参数。也就是说,即使函数不定义任何参数,还是可以拿到参数的值:
1
2
3
4
5
6
7
8
9
10
11
function abs() {
if (arguments.length === 0) {
return 0;
}
var x = arguments[0];
return x >= 0 ? x : -x;
}

abs(); // 0
abs(10); // 10
abs(-9); // 9
  • rest参数(ES6新引入的rest参数):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}

foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]

foo(1);
// 结果:
// a = 1
// b = undefined
// Array []

rest参数只能写在最后,前面用…标识,从运行结果可知,传入的参数先绑定a,b 多余的参数以数组的形式给变量rest,所以,不再需要arguments我们就获取了全部的参数。

如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。

2. 变量作用域

在JavaScript中,用var申明的变量实际上是有作用域的。

  1. 如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量:
1
2
3
4
5
6
7
8
9
10
    <script>
'use strict';
function f() {
var x = 1;
x = x+1;
}
x= x+2;
</script>

// ReferenceError! 无法在函数体外引用变量x
  1. 如果两个不同的函数各自申明了同一个变量,那么该变量只在各自的函数体内起作用。换句话说,不同函数内部的同名变量互相独立,互不影响:
1
2
3
4
5
6
7
8
9
10
11
'use strict';

function foo() {
var x = 1;
x = x + 1;
}

function bar() {
var x = 'A';
x = x + 'B';
}
  1. 由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行
1
2
3
4
5
6
7
8
9
'use strict';

function foo() {
var x = 1;
function bar() {
var y = x + 1; // bar可以访问foo的变量x!
}
var z = y + 1; // ReferenceError! foo不可以访问bar的变量y!
}

如果内部函数和外部函数的变量名重名怎么办?来测试一下:

1
2
3
4
5
6
7
8
9
10
11
function foo() {
var x = 1;
function bar() {
var x = 'A';
console.log('x in bar() = ' + x); // 'A'
}
console.log('x in foo() = ' + x); // 1
bar();
}

foo();

结果如下

1
2
3
foo()
x in foo() = 1
x in bar() = A

这说明了JavaScript的函数在查找变量的时候从自身函数定义开始,从“内”往“外”查找。如果内部函数定义了与外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量。

3. 变量的提升

JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:

1
2
3
4
5
6
7
8
9
'use strict';

function foo() {
var x = 'Hello, ' + y;
console.log(x);
var y = 'Bob';
}

foo();

虽然是strict模式,但语句var x = ‘Hello, ‘ + y;并不报错,原因是变量y在稍后申明了。

但是console.log显示Hello, undefined,说明变量y的值为undefined。这正是因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。

对于上述foo()函数,JavaScript引擎看到的代码相当于:

1
2
3
4
5
6
function foo() {
var y; // 提升变量y的申明,此时y为undefined
var x = 'Hello, ' + y;
console.log(x);
y = 'Bob';
}

由于JavaScript的这一怪异的“特性”,我们在函数内部定义变量时,请严格遵守“在函数内部首先申明所有变量”这一规则。最常见的做法是用一个var申明函数内部用到的所有变量:

1
2
3
4
5
6
7
8
9
10
function foo() {
var
x = 1, // x初始化为1
y = x + 1, // y初始化为2
z, i; // z和i为undefined
// 其他语句:
for (i=0; i<100; i++) {
...
}
}

3.1 全局作用域

  • 不在任何函数内定义的变量就具有全局作用域。
  • 实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性。
1
2
3
4
5
'use strict';

var course = 'Learn JavaScript';
alert(course); // 'Learn JavaScript'
alert(window.course); // 'Learn JavaScript'

由于函数定义有两种方式,以变量方式var foo = function () {}定义的函数实际上也是一个全局变量,因此,顶层函数的定义也被视为一个全局变量,并绑定到window对象:

1
2
3
4
5
6
7
8
'use strict';

function foo() {
alert('foo');
}

foo(); // 直接调用foo()
window.foo(); // 通过window.foo()调用

进一步大胆地猜测,我们每次直接调用的alert()函数其实也是window的一个变量:

1
2
3
4
5
6
7
8
9
window.alert('调用window.alert()');
// 把alert保存到另一个变量:
var old_alert = window.alert;
// 给alert赋一个新函数:
window.alert = function () {}
alert('无法用alert()显示了!');
// 恢复alert:
window.alert = old_alert;
alert('又可以用alert()了!');

3.2 局部作用域

由于JavaScript的变量作用域实际上是函数内部,我们在for循环等语句块中是无法定义具有局部作用域的变量的:

1
2
3
4
5
6
7
8
'use strict';

function foo() {
for (var i=0; i<100; i++) {
//
}
i += 100; // 仍然可以引用变量i
}

为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:

1
2
3
4
5
6
7
8
9
10
'use strict';

function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
// SyntaxError: Uncaught ReferenceError: i is not defined
i += 1;
}

4. 常量

由于var和let申明的是变量,如果要申明一个常量,在ES6之前是不行的,我们通常用全部大写的变量来表示“这是一个常量,不要修改它的值

1
var PI = 3.14;

ES6标准引入了新的关键字const来定义常量,const与let都具有块级作用域:

1
2
3
4
5
'use strict';

const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果!
PI; // 3.14

5. 方法

在一个对象中绑定函数,称为这个对象的方法。

在JavaScript中,对象的定义是这样的:

1
2
3
4
5
6
7
8
9
10
11
var xiaoming = {
name : "小明",
birth : 1990,
age: function(){
var y = new Date().getFullYear();
return y - this.birth;
}
};

xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是30,明年调用就变成31了

绑定到对象上的函数称为方法,和普通函数也没啥区别,但是它在内部使用了一个this关键字,这个东东是什么?

在一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量,所以this.birth可以拿到xiaoming的birth属性。

6. 标准对象

在JavaScript的世界里,一切都是对象。

但是某些对象还是和其他对象不太一样。为了区分对象的类型,我们用typeof操作符获取对象的类型,它总是返回一个字符串:

1
2
3
4
5
6
7
8
9
typeof 123; // 'number'
typeof NaN; // 'number'
typeof 'str'; // 'string'
typeof true; // 'boolean'
typeof undefined; // 'undefined'
typeof Math.abs; // 'function'
typeof null; // 'object'
typeof []; // 'object'
typeof {}; // 'object'

6.1 时间

在JavaScript中,Date对象用来表示日期和时间。要获取系统当前时间,用:

1
2
3
4
5
6
7
8
9
10
11
var now = new Date();
now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST)
now.getFullYear(); // 2015, 年份
now.getMonth(); // 5, 月份,注意月份范围是0~11,5表示六月
now.getDate(); // 24, 表示24号
now.getDay(); // 3, 表示星期三
now.getHours(); // 19, 24小时制
now.getMinutes(); // 49, 分钟
now.getSeconds(); // 22, 秒
now.getMilliseconds(); // 875, 毫秒数
now.getTime(); // 1435146562875, 以number形式表示的时间戳

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

1
2
3
var d = new Date();
d.toLocaleString(); //本地时间
d.toUTCString(); //调整后的UTC时间:

7. 面向对象编程

JavaScript,java…..面向对象编程:JavaScript有些区别!

  • 类:模板
  • 对象:具体的实例

7.1 proto继承

在JavaScript中这个叫做原型(proto):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
'use strict';

var Student = {
name : "zhuuu",
age : 3,
run : function () {
console.log(this.name + "run...")
}
};


var bird = {
fly : function () {
console.log(this.name + "飞")
}
}

var xiaoming = {
name : "xiaoming"
};

//小明的原型是 bird
xiaoming.__proto__ = bird ;

7.2 class继承

class关键字:es6引入

下面定义一个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>

//定义一个学生的类
class Student{

constructor(name){
this.name = name;
}

hello(){
alert("hello")
}

}

var xiaoming = new Student("xiaoming")
var xiaohong = new Student("xiaohong")

</script>

继承:

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
//定义一个学生的类
class Student{

constructor(name){
this.name = name;
}

hello(){
alert("hello");
}

}


class xiao extends Student{
constructor(name,grade) {
super(name);
this.grade = grade;
}

mygrade(){
alert("我是小学生");
}
}

var xiaoming = new Student("xiaoming");
var xiaohong = new Student("xiaohong",1);

7.3 原型链

在JavaScript中,每个函数都有一个prototype属性,这个属性指向函数的原型对象。

所以 Object.prototype.proto 的值为 null 跟 Object.prototype 没有原型,其实表达了一个意思。

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2019-2022 Zhuuu
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信