1.创建函数
函数也是对象。每个函数都是Function的实例,都与其他引用类型一样具有属性和方法。
- function关键字:
//语法格式:
function fn(){};
- 函数表达式
//语法格式:
var fn = function(){};
函数名仅仅是指向对象的指针,因此函数名与包含对象指针的其他变量没有什么不同。
不带圆括号的函数名是访问函数指针,而不是调用函数。
2.没有重载
- 由于不存在函数签名的特性,所以ECMAscript函数也就不能重载。
- 只会出现后定义的同名函数覆盖先定义的函数的情况。
// js函数不能重载
var add = function addSome(num) {
return num + 100;
}
add = function addSome(num) {
return num + 200;
}
console.log(add(100));//300
3.函数声明与函数表达式
- 在解析器解析js代码时,会先读取函数声明,使其在执行任何代码前可用;函数表达式只有在代码执行到所在行才会被真正解释执行。
- 简单理解就是:函数声明创建的Function实例具有函数提升的特性。
alert(sum(1,1));//2,函数提升,虽然声明在后,但是依然可以先调用后声明
function sum(num1,num2){
return num1 + num2;
}
console.log(sum1(10,10));//sum1 is not a function
var sum1 = function(num1,num2){
return num1 + num2;
}
4.作为值的函数
- 比较典型的就是回调函数。
- 因为函数名本身就是变量,所以函数也可以作为值传递给另一个函数。
- 也可以将函数作为另一个函数的结果返回。
// 可以作为参数传递函数,也可以将一个函数作为另一个函数的返回值
function fn(funct){
return function fun(){
console.log('作为返回值的函数');
}
}
function funct() {
console.log( '1');
}
fn(funct());//1
var result = fn();
result();//作为返回值的函数
4.1 函数作为返回值的用处
根据某个对象属性对数组排序时,传递给sort()的比较函数:
// 2.函数作为返回值在sort方法中的用法
function compareFun(prooertyName){
return function compare(object1, object2){
value1 = object1[prooertyName];
value2 = object2[prooertyName];
if(value1 < value2){
return -1;
}else if(value1 > value2){
return 1;
}else{
return 0;
}
}
}
// 测试一下:
var data = [{
name : '张三',
age : 12
},
{
name: '李四',
age: 20
}
]
data.sort(compareFun('age'));
console.log(data);//0: {name: "张三", age: 12}
//1: { name: "李四", age: 20 }
5.函数内部属性
- arguments:arguments是一个类数组(伪数组)对象,包含着传入函数的所有参数;主要用途是保存函数参数。
该对象还有一个名为callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
// 1.阶乘可以通过递归函数实现
function fn(num){
if(num <= 1){
return 1;
}else{
return num * fn(num - 1)
}
}
var result = fn(5);
console.log(result);//120
// 但是这样写的弊端在于,函数的执行和函数名耦合度较高
// 这时可以用arguments.callee属性来解决
// 2.改进后的阶乘函数
function fn(num){
if(num <= 1){
return 1;
}else{
//arguments.callee()指向拥有该arguments对象的函数:fn()
return num * arguments.callee(num - 1);
}
}
var result = fn(5);
console.log(result);//120
- this:this引用的是函数据以执行的环境对象,当在网页的全局作用域下调用函数时,this指向的是window。
- caller:函数对象属性,该属性中保存调用当前函数的引用(简单理解就是谁调用了这个函数),如果是在全局作用域下调用该函数,caller值为null。
// =====this=====
// 全局作用域下this指向window对象
function test(){
console.log(this);
}
test();//Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
//关于caller属性
// caller属性
function testFn(){
console.log(testFn.caller);
testFn1();
function testFn1(){
// testFn调用了该函数,caller保存的是引用testFn
//这里也可以使用arguments.callee.caller
console.log(testFn1.caller);//ƒ testFn()
}
}
testFn();//全局作用域下返回null
callee和caller小结:
简单理解:callee指向包含拥有某个arguments对象的函数;caller指向调用了该函数的函数。
5.1 严格模式下caller和callee
- 严格模式下访问arguments.callee会报错;
- ES5定义了arguments.caller属性,严格模式下访问会报错,非严格模式下始终是undefined;
- 严格模式下不能为函数的caller属性赋值。
6.函数属性和方法
每个函数都具有的属性:length和prototype。
- length属性:表示函数希望接收的的命名参数的个数。
// length属性表示函数接收的命名参数个数
function fn1(){
console.log(fn1.length);
}
function fn2(a,b){
console.log(fn2.length);
}
fn1();//0
fn2();//2
- prototype原型对象:保存着所有实例方法,不可被枚举(详细说明请看后续)。
每个函数都具有的方法:apply、call、bind;
这三个方法的作用在于:修改函数的this指向,扩充函数作用域。
- apply():可以调用函数,接收两个参数:this指向、参数数组(或者直接是arguments对象)
//语法格式
fn.apply(this指向,[arg1,arg2....])
// 1.apply():调用函数,修改函数的this指向,接收数组形式的参数
function fn(num1,num2){
return num1 + num2;
}
function fn1(num1,num2){
// 调用fn函数,并将fn函数this指向改为指向fn1
return fn.apply(this,arguments);
}
console.log(fn1(10, 10));//20
- call():作用和apply()方法一样,不同之处在于其接收第二个参数的格式不同,call方法接受的参数都是直接传递进来的,apply接受的第二个参数以数组的形式传递。
// 2.call():调用函数,修改this指向,参数直接传递给call
function callFn(num1,num2){
return num1 * num2;
}
function callFn1(num1,num2){
// 修改this指向,调用callFn函数,参数直接传入
return callFn.call(this,num1,num2);
}
console.log(callFn1(10,10));//100
注意:在严格模式下,未指定环境对象就调用函数,this指向不一定是window对象,除非把函数添加到某个对象或者调用apply或call方法,否则this值就是undefined。
- bind():修改this指向,但是不会调用函数,传参方式与call方法一致。
供学习交流使用,如有不足的地方,欢迎评论区交流。
业精于勤,荒于嬉,祝大家学习更上一层楼。