JS的函数是参数化的。
如果函数挂载在一个对象上,作为对象的一个属性,就称它为对象的方法。当通过这个对象来调用函数的方法。当通过这个对象来调用函数时,该对象就是此次上下文,也就是this的值。用于初始化一个新建对象的函数称为构造函数。
作为函数
作为方法
作为构造函数
通过它们的call()和apply()方法间接调用
如果有一个函数f和一个对象o,可以用以下的代码给o定义一个方法m:
//给o定义m()
o.m = f;
//调用m
o.m();
o.m(x,y)
方法调用和函数调用有一个重要的区别:调用上下文:
var calculator = {//对象直接量
operand1: 1,
operand2: 1,
add:function(){
this.result = this.operand1 + this.operand2;
}
};
calculator.add();
calculator.result; // => 2
如果想访问外部函数的this值 ,需要将this的值保存在一个变量里,这个变量和内部函数都同在一个作用域内,通用常用self来保存this
var o = {//对象o
m:function(){//对象里的方法m()
var self = this; //将this的值保存至一个变量中
console.log(this === o); //true
f(); //调用函数f()
function f(){
console.log(this === o); //false this的值是全局对象或undefined
console.log(self === o); // true self指外部函数的this值
}
}
}
o.m();
如果函数或者方法之前带有关键字new,它就构成构造函数调用。
var o = new Object();
var o = new Object;
//上下等价
call(),apply()
这两个方法都允许显式指定调用所需的this值。也就是说,任何函数都可以作为任何对象的方法来调用,哪怕这个函数不是那个对象的方法。
函数可以定义,也可以调用。
function square(x){ return x*x };
var s = square;
square (4); // 16
s (4); // 16
function add(x,y) {
return x+y;
}
function subtrach(x,y) {
return x - y;
}
function multiply(x,y) {
return x*y;
}
function divide(x,y) {
return x/y;
}
function operate (operator,operand1,operand2) {
return operator ( operand1,operand2);
}
var i = operate(add,operate(add,2,3),operate(multiply,4,5)) //25
function mymodule () {
//模块代码
//这个模块所使用的所有变量都是局部变量
//而不是污染命名空间
}
mymodule(); //不要忘了还要调用这个函数
//也可以定义为匿名函数
(function () {
//mymodule() 函数重写为匿名的函数表达式
//模块代码
}());//结束函数定义并立即调用它
闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量
让外部访问函数内部变量成为可能;
局部变量会常驻在内存中;
可以避免使用全局变量,防止全局变量污染;
理解闭包要了解嵌套函数的词法作用域规则:
var scope = "global scope";//全局变量
function checkscope() {
var scope = 'local scope'; //局部变量
function f() {
return scope; //在作用域中返回这个值
}
return f();
}
checkscope(); //"local scope"
function funA(){
var a = 10; // funA的活动对象之中;
return function(){ //匿名函数的活动对象;
alert(a);
}
}
var b = funA();
b();// 10
var uniqueInteger = (function() {
//函数定义并立即调用
var counter = 0; //函数的私有状态
return function() {
return counter ++;
};
}());
//这段代码定义了一个立即调用函数(函数的开始带有左圆括号),因此是这个函数的返回值赋值给变量uniqueInteger,
//嵌套的函数可以访问作用域内的变量,而且可以访问外部函数中定义的counter变量
像counter一样的私有变量不是只能用在一个单独的闭包内,在同一个外部函数内定义的多个嵌套函数也可以访问它,这多个嵌套函数都共享一个作用域链:
function counter () {
var n = 0;
retur {
counter: function(){
return n++;
},
reset: function () { n = 0 ;}
};
}
var c = counter(), d = counter(); //创建两个计数器
c.count(); // => 0 ;
d.count(); // => 0; 它们互不干扰
c.reset(); //reset() 和 count() 方法共享状态
c.count(); // => 0,因为重置了c
d.count(); //=> 1,没有重置d
function counter (n) { //函数参数n是一个私有变量
return {
get count () {
return n++;
}
set count(m) {
if(m >= n) n = m;
else throw Error ("...")
}
};
}
var c = counter(1000);
c.count // =>1000
c.count //=> 1001
c.count = 2000
c.count // => 2000
c.count = 2000 //=> Error
function constfuncs () {
var funcs = [];
for ( var i = 0; i < 10; i++) {
funcs[i] = function () {
return i ;
};
return funcs;
}
}
var funcs = constfuncs();
funcs[5]();
arguments.length表示传入函数的实参的个数。
下面的代码定义一个名叫check()的函数,从另外一个函数给它传入arguments数组,它比较arguments.length和arguments.callee.
length来判断所传入的实参个数是否正确。
function check (args) {
var actual = args.length; //实参的真实个数
var expected = args.callee.length; //期望的实参个数
if ( actual !== expected)
throw Error("...")
}
function f (x,y,z) {
check (arguments); //检查实参个数和期望的个数是否一致
return x + y = z; //再执行函数的后续
}
每个函数都包含一个prototype属性,这个属性是指向一个对象的引用,这个对象称做为 原型对象。
f.call(o);
f.apply(o);
o.m = f(); //将f存储为o的临时方法
o.m (); //调用它,不传入参数
delete o.m; //将临时方法删除
function trace(o,m) {
var original = o[m]; //在闭包中保存原始方法
o[m] = function () { //定义新的方法
console.log( new Date(), "Entering:", m); //输出日志信息
var result = original.apply(this,arguments); //调用原始函数
console.log(new Date(),"Exiting:", m);
return result ; //返回结果
}
}
这个方法的作用就是将函数绑定至某个对象。当在函数f()上调用bind()方法并传入一个对象o作为参数,这个方法将返回一个新的函数。
function f(y) {
return this.x + y ;
}
var o = { x: 1 }; //将要绑定的对象
var g = f.bind(o); //通过调用 g(x)来调用o.f(x)
g(2); //=> 3
//可以通过如下代码轻易地实现这种绑定:
//返回一个函数,通过调用它来调用o中的方法f(),传递它所有的实参
f(), //传递它所有的实参
function bind (f,o) {
if(f.bind) return f.bind(o); //如果bind()的方法存在,使用bind()
else f.apply(o,arguments);
}
var sum = function(x,y) {
return x+y;
} //返回两个实参的和值
//创建一个类似sum的新函数,但this的值 绑定到Null
var sunc = sum.bind(null,1);
succ(2) // => 3:x绑定到1,并传入2作为实参y
function f(y,z) {
return this.x + y + z; //另外一个做累加计算的函数
}
var g = f.bind({x:1},2); //绑定this 和 y
g(3) // => 6: this.x绑定到1,y绑定到2,z绑定到3
返回一个字符串
var f = new Function("x", "y", "return x*y;");
var f = function(x,y) { return x*y};
将上次的计算结果 缓存起来,这种缓存技巧叫做记忆。
//返回f()的带有记忆功能的版本
//只有当f()的 实参的字符串表示 不相同时它才会工作
function memorize(f){
var cache(); //将值促成在闭包内
return function() {
//将实参转化为字符串形式,并将其用做缓存的键
var key = arguments.length + Array.prototype.koin.call(arguments,",");
if(key in cache) return cache[key];
else return cache[key] = f.apply(this,arguments);
}
}