函数的属性和方法

JavaScript 中的函数是对象,因此函数也有属性和方法。

属性

每个函数都包含两个属性:lengthprototype

length

length 属性表示函数希望接收的命名参数的个数,如下面的例子所示。

function sayName(name){
    console.log(name);
}

function sum(num1, num2){
    return num1 + num2;
}

function sayHi(){
    console.log("hi");
}

console.log(sayName.length);      // 1
console.log(sum.length);          // 2
console.log(sayHi.length);        // 0

prototype

对于 JavaScript 中的引用类型而言,prototype 是保存它们所有实例方法的真正所在。换句话说,诸如 toString()valueOf() 等方法实际上都保存在 prototype 名下,只不过是通过各自对象的实例访问罢了。在创建自定义引用类型以及实现继承时,prototype 属性的作用是极为重要的。在 ECMAScript 5 中,prototype 属性是不可枚举的,因此使用 for-in 无法发现。

方法

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

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

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

但是,如果我们给xiaoming绑定一个函数,就可以做更多的事情。比如,写个age()方法,返回xiaoming的年龄:

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

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

绑定到对象上的函数称为方法,和普通函数也没啥区别。

每个函数都包含两个非继承而来的方法:apply()call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内 this 对象的值。

apply

虽然在一个独立的函数调用中,根据是否是strict模式,this指向undefinedwindow,不过,我们还是可以控制this的指向的!

要指定函数的this指向哪个对象,可以用函数本身的apply方法,它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array参数数组,表示函数本身的参数。

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, 参数为空

call

另一个与apply()类似的方法是call(),唯一区别是:

  • apply()把参数打包成Array再传入;

  • call()把参数按顺序传入。

比如调用Math.max(3, 5, 4),分别用apply()call()实现如下:

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

对普通函数调用,我们通常把this绑定为null

apply()和call()

在使用 call() 方法的情况下,callSum() 必须明确地传入每一个参数。结果与使用 apply() 没有什么不同。至于是使用 apply() 还是 call(),完全取决于你采取哪种给函数传递参数的方式最方便。如果你打算直接传入 arguments参数 对象,或者包含函数中先接收到的也是一个数组,那么使用 apply() 肯定更方便;否则,选择 call() 可能更合适。(在不给函数传递参数的情况下,使用哪个方法都无所谓。)

扩充函数赖以运行的作用域

事实上,传递参数并非 apply()call() 真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域。下面来看一个例子。

window.color = "red";
var o = { color: "blue" };

function sayColor(){
    console.log(this.color);
}
sayColor();     // "red"

o.sayColor = sayColor;
o.sayColor();   // "blue"

加上apply

window.color = "red";
var o = { color: "blue" };

function sayColor(){
    console.log(this.color);
}
sayColor();                // red

sayColor.call(this);       // red
sayColor.call(window);     // red
sayColor.call(o);          // blue

sayColor() 也是作为全局函数定义的,而且当在全局作用域中调用它时,它确实会显示 "red",因为对 this.color 的求值会转换成对 window.color 的求值。而 sayColor.call(this)sayColor.call(window),则是两种显式地在全局作用域中调用函数的方式,结果当然都会显示 "red"。但是,当运行 sayColor.call(o) 时,函数的执行环境就不一样了,因为此时函数体内的 this 对象指向了 o,于是结果显示的是 "blue"

使用 call()apply() 来扩充作用域的最大好处,就是对象不需要与方法有任何耦合关系。在第一个版本中,我们是先将 sayColor() 函数放到了对象 o 中,然后再通过 o 来调用它的;而在这里重写的例子中,就不需要先前那个多余的步骤了。

装饰器

利用apply(),我们还可以动态改变函数的行为。

JavaScript的所有对象都是动态的,即使内置的函数,我们也可以重新指向新的函数。

现在假定我们想统计一下代码一共调用了多少次parseInt(),可以把所有的调用都找出来,然后手动加上count += 1,不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的parseInt()

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210718075512944.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzUzNjk4MzM2,size_16,color_FFFFFF,t_70#pic_center)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值