美文网首页
第2章 函数

第2章 函数

作者: 不系流年系乾坤 | 来源:发表于2016-11-07 15:23 被阅读5次

函数也是对象,使对象不同于其它对象的决定性特点是函数存在一个被称为 [[Call]] 的内部属性。
内部属性无法通过代码访问而是定义了代码执行时的行为。ECMAScript为JavaScript的对象定义了多种内部属性,这些内部属性都用双重中括号来标注

[[Call]]属性是函数独有的,表明该对象可以被执行。由于仅函数拥有该属性,ECMAScript 定义typeof操作符对任何具有[[Call]]属性的对象返回"function"。过去因某些浏览器曾在正则表达式中包含 [[Call]] 属性,导致正则表达式被错误鉴别为函数。

2.1 声明还是表达式

两者的一个重要区别是:函数声明会被提升至上下文(要么是该函数被声明时所在的函数范围,要么是全局范围)的顶部。

2.2 函数就是值

可以像使用对象一样使用函数(因为函数本来就是对象,Function构造函数更加容易说明)。

2.3 参数

函数参数保存在类数组对象 argumentArray.isArray(arguments) 返回 false)中。可以接收任意数量的参数。
函数的 length 属性表明其期望的参数个数。

2.4 重载

大多数面向对象语言支持函数重载,它能让一个函数具有多个签名。函数签名由函数的名字、参数的个数及其类型组成。
而JavaScript可以接收任意数量的参数且参数类型完全没有限制。这说明JavaScript函数根本就没有签名,因此也不存在重载。

function sayMessage(message){
    console.log(message);
}
function sayMessage(){
    console.log("Default Message");
}

sayMessage("Hello!"); // 输出"Default Message";

在Javscript里,当你试图定义多个同名的函数时,只有最后的定义有效,之前的函数声明被完全删除(函数也是对象,变量只是存指针)。

var sayMessage = new Function("message", "console.log(message)");
var sayMessage = new Function("console.log(\"Default Message\");");

sayMessage("Hello!"); 

当然,你可以根据传入参数的数量来模仿重载。

2.5 对象方法

对象的值是函数,则该属性被称为方法。

2.5.1 this对象

JavaScript 所有的函数作用域内都有一个 this 对象代表调用该函数的对象。在全局作用域中,this 代表全局对象(浏览器里的window)。当一个函数作为对象的方法调用时,默认 this 的值等于该对象。
this在函数调用时才被设置。

function sayNameForAll(){
    console.log(this.name);
}

var person1 = {
    name: "Nicholas",
    sayName: sayNameForAll
}

var name = "Jack";

person1.sayName(); // 输出 "Nicholas"
sayNameforAll(); // 输出 "Jack"

2.5.2 改变this

3 种函数方法运行你改变 this 值。

  1. fun.call(thisArg[, arg1[, arg2[, ...]]]);
  2. fun.apply(thisArg, [argsArray]);
  3. fun.bind(thisArg[, arg1[, arg2[, ...]]])

使用 callapply 方法,就不需要将函数加入每个对象——你显示地指定了 this 的值而不是让JavaScript引擎自动指定。

callapply 的不同地方是,call 需要把所有参数一个个列出来,而 apply 的参数需要一个数组或者类似数组的对象(如 arguments 对象)。

bind 是ECMAScript 5 新增的,它会创建一个新函数返回。其参数与 call 类似,而且其所有参数代表需要被永久设置在新函数中的命名参数(绑定了的参数(没绑定的参数依然可以传入),就算调用时再传入其它参数,也不会影响这些绑定的参数)。

function sayNameForAll(label){
    console.log(label + ":" + this.name);
}
var person = {
    name: "Nicholas"
}

var sayNameForPerson = sayNameForAll.bind(person);
sayNameForPerson("Person"); // 输出"Person:Nicholas"

var sayName = sayNameForAll.bind(person, "Jc");

sayName("change"); // 输出"Jc:Nicholas" 因为绑定的形参,会忽略调用时再传入参数

2.6 总结

  • 函数也是对象,所以它可以被访问、复制和覆盖。
  • 函数与其他对象最大的区别在于它们有一个特殊的内部属性 [[Call]],包含了该函数的执行指令。
  • 函数声明会被提升至上下文的顶部。
  • 函数是对象,所以存在一个 Function 构造函数。但这会使你的代码难以理解和调试,除非函数的真实形式要直到运行时才能确定的时候才会利用它。

相关文章

网友评论

      本文标题:第2章 函数

      本文链接:https://www.haomeiwen.com/subject/epsouttx.html