在JavaScript中一共有四种调用模式:方法调用模式、函数调用模式、构造器调用模式和apply调用模式。这些模式在如何初始化关键参数this上存在差异。
1. 方法调用模式
当一个函数被保存为对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this被绑定到该对象。如:
var myObject = { value:0; increment:function(inc){ this.value += typeof inc === 'number' ? inc : 1; } }; myObject.increment(2) document.writeln(myObject.value); // 3
方法可以使用this去访问对象,所以它能从对象中取值或修改该对象。this 到对象的绑定发生在调用的时候,“迟绑定”。
2. 函数调用模式
当一个函数并非一个对象的属性时,那么它被当作一个函数来调用:
var sum = add(3,4); // sum 的值为7
当函数以此模式调用时,this被绑定到全局对象。这是语言设计上的一个错误。解决的方法是定义一个变量并给它赋值为this。
myObject.double = function(){ var that = this; this.value = 6; var helper = function(){ console.log(that.value); } helper(); } myObject.double(); // 6
3. 构造器调用模式
如果在一个函数前面带上new来调用,那么将创建一个隐藏连接到该函数的prototye成员的新对象,同时this将会被绑定到那个新对象上。
new 前缀也会改变return语句的行为。?
var Quo = function(string){ this.status = string; } Quo.prototype.get_status = function(){ return this.status; } var myQuo = new Quo("confused"); console.log(myQuo.get_status()); // confused
4. Apply调用模式
因为JavaScript是一门函数式的面向对象编程语言,所以函数可以拥有方法。
apply方法接收两个参数。第一个是将被绑定给this的值。第二个就是一个参数数组。
var Quo = function(string){ this.status = string; } Quo.prototype.get_status = function(){ return this.status; } var myQuo = new Quo("confused"); // 自己乱写的add方法 function add(){ var sum = 0; Array.prototype.forEach.call(arguments,function(value,key,array){ sum+=value; }); return sum; } var array = [3,4,5]; var sum = add.apply(null,array); // sum值为7 console.log(sum); var statusObject = { status:'A-OK' } var status = Quo.prototype.get_status.apply(statusObject); console.log(status); // A-OK
注:new 前缀也会改变return语句的行为。
如果函数以在前面加上new前缀的方式来调用,且返回值不是一个对象,则返回this(该新对象)。返回值是对象是则返回该对象!!!!!
1.给类型增加方法
通过Function.prototype增加方法来使得该方法对所有函数可用
Function.prototype.method = function(name,func){ this.prototype[name] = func; return this; }
给Number.prototype添加一个integer方法来根据数字的正负来判断使用Math.ceiling还是Math.floor
Number.method('integer',function(){ return Math[this < 0 ? 'ceiling' : 'floor'](this); });
给String.prototype添加trim方法来移除字符串的末端空格
String.method('trim',function(){ return this.replace(/s+|s+$/g,''); }); console.log('"'+" n ear ".trim()+''); // n ear
记忆
函数可以用对象去记住先前的操作,从而能避免无谓的运算。
var memoizer = function(memo,fundamental){ var shell = function(n){ var result = memo[n]; if(typeof result !== 'number'){ result = fundamental(shell,n) memo[n] = result; } return result; }; return shell; } var fib = memoizer([0,1],function(shell,n){ return shell(n-1)+shell(n-2); }); var res = fib(30);console.log(res);
套用 柯里化
Function.prototype.method = function(name,func){ this.prototype[name] = func; return this; } function add(){ var sum = 0; console.log(arguments); Array.prototype.forEach.call(arguments,function(value,key,array){ sum+=value; }); return sum; } Function.method('curry',function(){ var slice = Array.prototype.slice, args = slice.apply(arguments), that = this; return function(){ return that.apply(null,args.concat(slice.apply(arguments))); // 如果是调用非内置的方法(slice,forEach..)时一定要传个对象 } }); var res = add.curry(1)(2,3,4); console.log(res); // 10