JaveScript(函数篇 I)


\(update : 2022.1.20\)

学习原文

怎么说 , 鸽了好多天 , 要坚持.

\(c\) 的函数差不多 , 但很多细节不一样.


\(① : 函数的定义与调用\)

function abs(x){
	if(x>=0){
		return x;
	}else{
		return -x;
	}
}

这里 function 指明了是一个函数定义 ; abs 是函数名 ; x 代表函数参量 ;

同时作者又指出了函数在 JavaScript 中仅仅是一个对象 , 函数名 abs 可以是指向该函数的变量

所以函数又有了如下定义

var abs = function(x){
	if(x >= 0){
		return x;
	}else {
		return -x;
	}
}; // 要注意这里有一个分号 , 因为是赋值.

二者等价 , 直接调用即可. //例如 abs(-3) ;

注意函数一遇到 return 就会返回结果 , 一个函数没有 return 的话 , 返回的就是 undefined .

接下来就是传参的问题

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

拿上文的 abs 函数举例 

abs(3,'blabla') // 结果为3
abs(-1,'fdas',232) //结果为1

那么如果参数少了呢?

那么要看这个参数在函数里面又没有用到 , 有用到的话函数自动返回 NaN , 否则就没有影响.

下面讲到了 arguments : "JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array" 

注意传入的所有参数 , 有下列的例子.

var abs = function(){
	if(arguments.length == 0) 
		return 0;
	var x = arguments[0];
	return x>=0?x:-x;
};
abs() // 0
abs(3) // 3
abs(-3) // 3

注意这里函数连传入的参数定义都没有 , 但你只要用函数传入了参数 , 就可以用arguments调用出来.

接下来 rest 参数的介绍

原文举了一个很鲜明的例子来介绍了 rest 的作用

function foo(a, b) {
    var i, rest = [];
    if (arguments.length > 2) {
        for (i = 2; i

\(③ : 方法\)

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

先给出一个例子

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

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

注意第一个返回值是将函数整体的语句返回 , 而第二个返回值则是函数运行之后的返回值.

new Date().getFullYear() // 返回今年年份.

这里出现了一个新的关键字 "this" .

在一个方法的内部 (这个前提很重要) , this 是一个特殊的变量 , 它始终指向当前的对象 .

接下来有几个特殊的例子

//注意这里可以将函数拆开写
function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}
var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25, 正常结果
getAge(); // NaN

这里我们主要注意 NaN 的情况 , 这里我们单独调用了getAge函数 , 而不是用xiaoming对象中的方法 , 而单独的函数内部调用了 this , 这个 this 指向的是全局对象 .

同样有一个例子
var fn = xiaoming.age; // 先拿到xiaoming的age函数
fn(); // NaN

这里照样是 NaN , 要保证 this 指向正确,必须用obj.xxx()的形式调用!(obj 即对象的意思)

不过在 strict 模式下返回的就不是 NaN . 
它会让 this 指向 undefined .

又有一个例子 :
'use strict';
var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - this.birth;
        }
        return getAgeFromBirth();
    }
};
xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined

这种操作叫做方法重构
原因是在 age 方法内的 this 才指向对象 xiaoming , 但你函数内部又定义个函数 , 这时候的指针又指向   undefined 了 .

这时候利用这个特征 , 我们提出解决方法
'use strict';
var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var that = this; // 在方法内部一开始就捕获this
        function getAgeFromBirth() {
            var y = new Date().getFullYear();
            return y - that.birth; // 用that而不是this
        }
        return getAgeFromBirth();
    }
};
xiaoming.age(); // 25
你看直接在方法内部存一下 this 就行了.

接下来作者引入了 apply , 它可以指定函数的 this 指向哪个对象 , 这样就不一定在 方法 里面才去用 this.

举个例子

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空

要注意它和函数绑定使用 , 且它接受两个参数 , 第一个是绑定 this 的变量 , 第二个是 Array , 里面装着函数的参数.

另一个与apply()类似的方法是call(),唯一区别是:
apply()把参数打包成Array再传入;
call()把参数按顺序传入.

Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5

因为一般的函数调用不用 this (无对象) , 把 this
 绑定 null 即可.

装饰器 (为什么这样子叫我也不知道)

利用 apply() , 我们可以动态改变函数

提出问题 :我们想统计一下代码一共调用了多少次parseInt()
//parseInt()是本身就有的一个函数 , 可解析一个字符串 , 并返回一个整数.

'use strict';

var count = 0;
var oldParseInt = parseInt; // 保存原函数

window.parseInt = function () {
    count += 1;
    return oldParseInt.apply(null, arguments); // 调用原函数
};
// 测试:
parseInt('10');
parseInt('20');
parseInt('30');
console.log('count = ' + count); // 3

但我没搞懂为什么一定要用apply.