《JavaScript面向对象精要》之二:函数

函数也是对象,使对象不一样于其它对象的决定性特色是函数存在一个被称为 [[Call]] 的内部属性。正则表达式

相似于[[Call]] 这种内部属性没法经过代码访问,他只是定义了代码执行时的行为。数组

ECMAScript为JavaScript的对象定义了多种内部属性,这些内部属性都用双重中括号来标注浏览器

[[Call]] 属性是函数独有的,代表该对象能够被执行。因为仅函数拥有该属性,ECMAScript 定义 typeof 操做符对任何具备 [[Call]] 属性的对象返回 "function"app

过去因某些浏览器曾在正则表达式中包含 [[Call]] 属性,致使正则表达式被错误鉴别为函数。函数

2.1 声明仍是表达式

函数有两种字面形式:函数声明跟函数表达式。ui

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

2.2 函数就是值

函数是JavaScript的一大重点。spa

基本上只要是可使用其余引用值的地方,你就可使用函数。也就是说,你能够像使用对象同样使用函数(由于函数原本就是对象)。指针

2.3 参数

JavaScript函数另外一个独特之处在于你能够给函数传递任意数量的参数却不形成错误。调试

这是由于函数参数保存在类数组对象 arguments中。

如同一个普通JavaScript数组,arguments能够自由增加来包含任意个数的值,这些值可经过数字索引来引用。

虽然arguments相似数组,可是Array.isArray(arguments) 返回 false

最后须要注意两点:

  • arguments对象自动存在于函数中,也就是说,函数的命名参数不过是为了方便,并不真的限制了该函数可接受参数的个数。
  • 但JavaScript也没忽视那些命名参数,函数的 length 属性代表其指望的参数个数。

2.4 重载

大多数面向对象语言支持函数重载,它能让一个函数具备多个签名。函数签名由函数的名字、参数的个数及其类型组成。

而 JavaScript 能够接收任意数量的参数且参数类型彻底没有限制。这说明 JavaScript 函数根本就没有签名,所以也不存在重载。

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

sayMessage("Hello!"); // 输出"Default Message";
复制代码

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

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 构造函数。但这会使你的代码难以理解和调试,除非函数的真实形式要直到运行时才能肯定的时候才会利用它。
相关文章
相关标签/搜索