函数调用,方法调用,构造函数调用
1、方法不过是对象的属性恰好是函数而已
2、一个非方法的函数调用会将全局对象作为接收者,将this绑定到全局对象上。而严格模式下会将this变量的默认值改为undefined
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function hello() { return 'hello ' + this.username; }
function hi() { 'use strict'; return 'hi ' + this.username; } var obj = { hello: hello, hi: hi, username: 'bob' } console.log(obj.hello()); console.log(hello());
console.log(obj.hi()); console.log(hi());
|
3、构造函数调用将一个全新的对象作为this变量的值,并隐式返回这个新对象作为调用结果。构造函数主要职责是初始化该新对象。
高阶函数
1、高阶函数无非是那些将函数作为参数或返回值的函数
2、使用数组map
方法,可以完全消除循环,仅使用一个局部函数就可以实现对元素的逐个转换
1 2 3 4 5 6
| var names = ['fred','Wilma','Pebbles']; var upper = names.map(function(name) { return name.toUpperCase(); });
console.log(upper);
|
3、使用call、apply
去调用函数时,如果函数中没有引用this变量,则可以简单的将第一个参数设为null
1 2 3 4 5 6 7 8 9 10 11
| function ave() { var sum = 0, len = 0; for (var i = 0, len = arguments.length; i < len; i++) { sum += arguments[i]; } return sum / len; }
console.log(ave.call(null, 1, 2, 3)); console.log(ave.apply(null, [1, 2, 3]));
|
永远不要修改arguments对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function callMethod(obj, method) { var shift = [].shift; shift.call(arguments); shift.call(arguments); return obj[method].apply(obj, arguments); }
var obj = { add: function(x, y) { return x+y; } };
callMethod(obj,'add',1,2);
|
该函数出错的原因是arguments
对象并不是函数参数的副本。所有的命名参数都是arguments
对象中对应索引的别名。
即使通过shift方法移除arguments
对象中的元素之后,obj
仍然是arguments[0]
的别名,method
仍然是arguments[1]
的别名。
这意味着我们似乎是在提取obj['add']
,但实际上是在提取17[25]
。引擎将17
转换为Number对象并提取其25
属性(该属性不存在),结果产生undefined
,然后试图提取undefined
的apply
属性并将其作为方法来调用,因此报错。
严格模式下,函数参数不支持对其arguments
对象取别名。
1 2 3 4 5 6 7 8 9 10 11 12 13
| function strict(x) { 'use strict'; arguments[0] = 'modified'; return x === arguments[0]; }
function nonstrict(x) { arguments[0] = 'modified'; return x === arguments[0]; }
console.log(strict('unmodified')); console.log(nonstrict('unmodified'));
|
也就是,在严格模式下,arguments对象只是参数的一个副本,之后的修改不影响参数值。
例外情况:传入的是对象(或数组)的引用,函数内arguments
修改的是对象的属性,则参数会同时被修改【这点不管在严格模式还是非严格模式都一样】
1 2 3 4 5 6 7
| function strict(obj) { 'use strict'; arguments[0].name = 'hehe'; console.log(obj.name); }
strict({name: 'haha'});
|
因此,永远不要修改arguments对象是更为安全的。通过一开始复制参数中的元素到一个真正的数组的方式,很容易避免修改arguments对象,如下:
1
| var args = [].slice.call(arguments);
|
bind方法
1、**bind()**方法创建的是一个新的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var siteDomain = 'baidu'; var paths = ['image', 'music', 'cloud'];
function simpleURL(protocol, domain, path) { return protocol + '://' + domain + '/' + path; }
var urls = paths.map(function(path) { return simpleURL('http', siteDomain, path); });
var urls2 = paths.map(simpleURL.bind(null, 'http', siteDomain));
console.log(simpleURL === simpleURL.bind(null));
console.log(urls); console.log(urls2);
|
传入null或undefined作为接收者的参数来实现函数柯里化