高级程序3 JS函数看书笔记
# JS函数
# 基本概念:
函数既对象 还可以当成参数
定义
声明 ->
function name() {}
与函数表达式语句相比存在变量提升 没有return语句 返回undefined (有时候称为过程) 不能出现在 if() for()表达式 ->
var name = function() {}
构造函数 ->
var f = new Function(“x”, “y”,”renturn x*y;”);
可以传入任意数量的实参,最后个实参所表示的文本是函数体对于函数来说,只有函数声明会被提升到顶部,而函数表达式不会被提升
IIFE: 意思是立即调用函数表达式
(function(){})()
!function(){}()
解析器不再以函数声明的方式处理函数a,而是作为一个函数表达式处理作用域 -> JavaScript采用 词法作用域 函数的执行依赖于变量的作用域,这个作用域是在函数定义时决定的而不是函数调用的时候决定的,函数内部的状态不仅包括函数的代码逻辑还必须引用当前的作用域链。
闭包 -> 函数对象可以通过作用域链关联起来 函数嵌套在其他函数定义中,这样就可以访问他们在定义事所处的作用域中的任何变量
* 在函数内部创建新的函数; * 新的函数在执行时,访问了函数的变量对象; 其实就是实现了“私有属性”和“私有方法” 好处,使一个变量长期存在于内存中,防止全局变量污染 闭包在外部函数里无法访问this(this的值随着调用栈变化) 解决 -> 使用var self = this
aruments与之类似
# 调用
作为函数 ->
f() Math.max() a.sort()
非严格模式下this 指向全局对象
定义并调用一个函数来确定当前脚本运行时是否为严格模式
var strict = (function() { return !this;}())
作为方法 ->
o.m = f; o.m()
与普通函数调用不同的是 this指向调用的对象o
复杂的属性访问表达式
customer.surname.toUppperCase();
f().m()
-> 在f()调用结束后继续调用返回值中的m()方法链 -> 当返回值是一个对象,这个对象还可以再调用其他的方法,这种调用序列称为方法链,当方法并不需要返回值时最好返回this,在api设计中如果一直采用这种方式,使用api就可以采用链式调用,只需要指定一次调用的对象
$("$header").map(function(){ return this.id; }.get().sort())
shape.setX(100).setY(100).setSize(50)
this 是一个关键字,不是变量也不是属性名,不允许给this赋值 关键字this没有作用域限制,嵌套函数不会从调用他的函数中继承this, 如果嵌套函数作为方法调用this指向调用他的对象,作为函数调用this不是 全局对象就是undefined.
作为构造函数 -> 如果函数或者方法调用之前带有关键字new,他就构成构造函数
- 构造函数跟普通的函数调用以及方法调用的区别在于实参处理 调用上下文 返回值不同
实参处理 -> 如果构造函数没有形参可以省略实参列表和圆括号
调用上下文 -> 构造函数创建一个新的空对象,这个对象继承自构造函 数的prototype属性。构造函数视图初始化这个新创建的空对象,并将这 个对象用做其调用上下文,因此构造函数可以使用this关键字来引用这个 新的对象。 在表达式
new o.m()
中,调用上下文并不是o间接调用 -> 通过**call()和apply()**方法调用
- **call()和apply()**第一个参数是要调用用对象的母对象,它是调用上下文,在函数体内通过this来获得对它的引用。
f.call(o) 相当于 o.m = f; o.m; delete o.m;
- 在ECMAScript5 中,call()和apply()的第一个参数都会变成this的值,如果是null和undefined都会被全局对象代替,而其他值都会被相应的包装对象所代替
- call()和apply的不同在于call()第一个参数之后的参数就是要传入函数的参数,apply()第一个参数之后是数组,
f.call(0,x,y); f.apply(o,[x,y])
apply()传入的参数可以使类数组对象(arguments)也可以是真实数组。
- **call()和apply()**第一个参数是要调用用对象的母对象,它是调用上下文,在函数体内通过this来获得对它的引用。
# 实参跟形参
- 可选形参
- 当函数传入的实参比声明时指定的形参个数要少的时候 -> 剩下的形参都为undefined,应当给省略的形参设置一个默认的值。而且需要将可选的形参放在实参列表最后,同时在函数定义中使用
/*optional*/
来强调形参时可选的, es6 使用 ·function(x = 1)
来实现默认参数,特点:不能使用同名参数,且默认参数是惰性的。
- 当函数传入的实参比声明时指定的形参个数要少的时候 -> 剩下的形参都为undefined,应当给省略的形参设置一个默认的值。而且需要将可选的形参放在实参列表最后,同时在函数定义中使用
- 可变的实参对象跟实参对象
- 当函数传入的实参比声明时指定的形参个数要多的时候 -> 标识符arguments是指向实参对象的引用,实参对象是一个类数组对象。
可以通过
argument[0]
类似的方式来获取参数,argument.length
获 取参数的个数。 - 可接受任意个数的实参的函数叫做,不定实参函数 但是参数个数不能为0
- arguments不是真正的数组,可以认为是一个对象,只是碰巧有以数字为索引的属性
- callee和caller属性 callee可以再匿名函数中递归的调用自身
- 当函数传入的实参比声明时指定的形参个数要多的时候 -> 标识符arguments是指向实参对象的引用,实参对象是一个类数组对象。
可以通过
var factorial = function(x){ if(x <= 1) return 1; return x * arguments.callee(x-1); }
* caller属性可以访问调用栈, 也就是this的指向
- 将对象属性作为实参 为了不用去记函数参数的顺序,采用名/值得方法传参
- 实参类型 因为JavaScript在必要的时候会进行类型转换,所以实际运算上会出错
- typescript
# 作为值得函数
例子简单的计算器函数功能,自定义排序 自定义函数属性
# 作为命名空间
在函数内部命名的变量不会污染全局空间
# 函数的属性,方法和构造函数
属性
length属性 函数的length属性指的是期望的参数的数量(形参), 可以用arguments.length 跟 arguments.callee 来判断参入参数的个数是否正确.(在非严格模式下)。 在指定了默认参数之后,函数的length属性,将返回没有指定默认值的参数的个数,如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。
prototype属性 这个属性指向一个对象的引用,这个对象称之为原型对(prototype),当函数用作构造函数的时候,新创建的对象会从原型对象上继承属性。
方法
- call()apply()
- bind() 当在函数f()上调用bind()方法并传入一个对象o作为参数,这个方法将返回一个新的函数(以函数调用的方式)调用的新函数会被原始的函数f()当做o的方法来调用。传入的新函数的任何实参都将传入原始函数。
function f(y) { return this.x + y; }
var o = { x : 1 };
var g = f.bind(o);
g(2) // => 3
----------完整的实现绑定------------
function bind(f,o) {
if (f.bind) return f.bind(o)
else return function() {
renturn f.apply(o,arguments);
}
}
2
3
4
5
6
7
8
9
10
11
bind()应用 -> 柯里化(currying): 除了第一个实参外传入bind()的实参也会绑定到this。
var sum = function(x, y) { renturn x + y };
var succ = sum.bind(null, 1)
succ(2) // => 3 x绑定到1并传入2作为实参y
2
3
这个方式柯里化可以用 闭包加上apply实现:
if(!Function.prototype.bind){
var self = this, boundArgs = arguments;
return function() {
var args = [], i;
for(i = 1; i < boundArgs.length; i++ ) args.push(*);
for(i = 0; i < arguments.length; i++ ) args.push(*);
renturn self.apply(o, args);
};
}
2
3
4
5
6
7
8
9
- **toString()**方法 返回一个字符串,大部分函数返回函数完整源码,内置函数返回一个类似“[native code]”的字符串作为函数体
Function()构造函数 Function()构造函数不需要通过传入实参以指定函数名,Function()构造函数创建一个匿名函数
Function()构造函数允许JavaScript在运行是动态的创建并编译函数
每次调用Function构造函数都会解析函数体,并创建新的函数对象,相比之下嵌套函数跟函数定义表达式则不会每次执行时都编译。
Funtionc()构造函数创建的函数并不是使用词法作用域,相反函数体的代码的编译总是会在顶层函数(全局作用域)执行,可以将Function()构造函数认为是在全局作用域中的eval(),eval()可以在自己的私有作用域内定义新的变量和函数。
可调用对象 可调用对象是一个对象可以在函数调用表达式当中调用这个对象。所有的函数都是可以调用的,但是并非所有的可调用对象都是函数。 列子: Windows.alert() 和 Doucument.getElemntById(),RegExp
# 函数式编程
主要思想是把运算过程尽量写成一系列嵌套的函数调用
- 高阶函数
map()和reduce() **map()**创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
**reduce()**方法对数组中的每个元素执行一个由您提供的**reducer**函数(升序执行),将其结果汇总为单个返回值。
- this对象是在运行时基于函数的执行环境绑定的,匿名函数的执行环境具有全局性,其this指向window