ECMAScript5面向对象技术(2)--函数
在javascript中,函数其实就是对象。使函数不同于其他对象的决定性特点是函数存在一个被称为[[call]]的内部属性。内部属性无法通过代码访问而是定义了代码执行时的行为。ecmascript为javascript的对象定义了多种内部属性,这些内部属性都用双重中括号来标注。
[[call]]属性是函数独有的,表明该对象可以被执行。由于仅函数又有该属性,ecmascript定义typeof
操作符对任何具有[[call]属性的对象返回"function"。
创建函数的方式
- 函数声明,以function关键字开头,后面跟着函数的名字。函数的内容放在大括号内;
function add(v1, v2) { return v1 + v2; }
- 函数表达式,function关键字后面不需要加上函数的名字。这种函数被称为匿名函数,因为函数对象本身没有名字。取而代之的函数表达式通常会被一个变量或属性引用。函数表达式的赋值通常在最后有一个分号,就如同其他对象的赋值一样;
var add = function(v1, v2) { return v1 + v2; };
- 函数的构造函数(不建议使用,体验差,调试困难)。
var add = new function("v1", "v2", "return v1 + v2;");
函数就是值
我们可以像使用对象一样使用函数,也可以将它们赋给变量,在对象中添加它们,将它们当成参数传递给别的函数,或从别的函数中返回。基本上只要是可以使用其他引用值的地方,就可以使用函数。
function sayhi() { console.log("hi!"); } sayhi(); // outputs "hi!" var sayhi2 = sayhi; sayhi2(); // outputs "hi!"
参数
javascript函数的另一个独特之处在于你可以给函数传递任意数量的参数却不造成错误。那是因为函数参数实际上被保存在一个被称为arguments的类似数组(arguments对象不是一个数组的实例)的对象中;
arguments对象自动存在于函数中。也就是说,函数的命名参数不过是为了方便,并不真的限制了该函数可接受参数的个数;
函数期望的参数个数保存在函数的length属性中。
function reflect(value) { return value; } console.log(reflect("hi!")); // "hi!" console.log(reflect("hi!", 25)) // "hi!" console.log(reflect.length) // 1 reflect = function() { return arguments[0]; } console.log(reflect("hi!")); // "hi!" console.log(reflect("hi!", 25)) // "hi!" console.log(reflect.length) // 0
重载
大多数面向对象语言支持函数重载,它能让一个函数具有多个签名。javascript函数可以接受任意数量的参数且参数类型完全没有限制。这说明javascript函数其实根本没有签名,因此也不存在重载。在javascript里,当试图定义多个同名的函数时,只有最后定义的有效,之前的函数声明被完全删除,只使用最后那个。
function say(msg) { console.log(msg); } function say() { console.log("default message"); } say("hello"); // 输出"default message" javascript函数没有签名这个事实不意味着不能模仿函数重载,可以使用arguments对象获取传入的参数个数并决定怎么处理。
function say(msg) { if(arguments.length === 0) { msg = "default message"; } console.log(msg); } say("hello"); //输出"hello!"
对象方法
如果对象属性的值是函数,则该属性被称为方法。
this对象
javascript所有的函数作用域内都有一个this对象代表调用该函数的对象。在全局作用域中,this代表全局对象。当一个函数作为对象的方法被调用时,默认this的值等于那个对象。
var person = { name : "tom", sayname : function() { console.log(this.name); } }; person.sayname(); //输出"tom"改变this
在javascript中,函数会在各种不同上下文中被使用,它们必须到哪都能正常工作。一般this会被自动设置,但是可以改变它的值来完成不同的目标。有3种函数方法允许你改变this的值(记住函数的对象,而对象可以有方法,所以函数也有)。
- call()方法
第一个参数指定函数执行时this的值,其后的所有参数都是需要被传入函数的参数。
function sayname(label) { console.log(label + ":" + this.name); } var person1 = { name : "tom" }; var person2 = { name : "bob" } var name = "peter"; sayname.call(this, "global"); //global:peter sayname.call(person1, "person1");//person1:tom sayname.call(person2, "person2");//person2:bob
- apply()方法
工作方式和
call()
完全一样,只接受两个参数:this的值,一个数组。function sayname(label) { console.log(label + ":" + this.name); } var person1 = { name : "tom" }; var person2 = { name : "bob" } var name = "peter"; sayname.apply(this, "global"); //global:peter sayname.apply(person1, "person1"); //person1:tom sayname.apply(person2, "person2"); //person2:bob
- bind()方法
bind
方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。function sayname(label) { console.log(label + ":" + this.name); } var person = { name : "tom" }; //create a function just for person1 var saynameforperson = sayname.bind(person1); saynameforperson1("person"); // "person:tom"