Skip to content
本页目录

Function 函数

JS 的函数是一个 Function 对象(typeof function(){} === 'function'(function(){}).constructor === Function

构造函数

Function() 动态创建函数,它只能创造全局执行的函数

JS
const sum = new Function('a', 'b', 'return a + b');
// 等同于
const function sum(a, b) {
  return a + b;
}
const sum = new Function('a', 'b', 'return a + b');
// 等同于
const function sum(a, b) {
  return a + b;
}

实例属性

  • name 函数名称
  • displayName 函数的显示名称
  • length 函数期望参数数量,ES6 支持了默认参数与 rest 参数,这个值可能不准确

实例方法

  • apply
  • call
  • bind

函数类型

  • 函数声明
JS
function foo() { }
function foo() { }
  • 函数表达式
JS
let foo = function() { }
let foo = function() { }
  • 匿名函数
JS
function() { }
function() { }
  • 箭头函数
JS
let foo = () => { }
let foo = () => { }
  • 构造函数
JS
let foo = new Function('a', 'b', 'return a + b');
let foo = new Function('a', 'b', 'return a + b');

ES6 相关

  • 增加了参数默认值
  • 参数变量不可被再次声明
  • 参数可使用解构赋值
  • 指定参数默认值后,length 属性失真
  • 设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。
  • 增加了 rest 参数(...变量名取代原有 arguments注意,arguments 是类数组对象,转为数组方法有:
    • Array.prototype.slice.call(arguments)
    • [].slice.call(arguments)
    • Array.from(arguments)
    • [...arguments]
  • 增加了箭头函数
  • try{ } catch(err) { } 可以省略 catch 参数,即 try{ } catch { }

箭头函数

箭头函数注意点

  1. 函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象
  2. 不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误,所以也没用 prototype 属性
  3. 不可以使用 arguments 对象,该对象在函数体内不存在。可以用 rest 参数代替
  4. 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数

关于第一点

JS
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);	// 指向定义时的对象,即foo
  }, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);	// 指向定义时的对象,即foo
  }, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
JS
function foo() {
  setTimeout(function() {
    console.log('id:', this.id);	// 执行时已经变为 window 下的普通函数
  }, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 21
function foo() {
  setTimeout(function() {
    console.log('id:', this.id);	// 执行时已经变为 window 下的普通函数
  }, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 21

箭头函数不使用场景

因为箭头函数是定义时确定了 this 指向

  1. 对象内的方法定义
    以下这种情况,this 会指向 window,因为对象没有单独的作用域,所以 this 在定义时就指向了最近的外层,即 window
JS
const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}
const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

高阶函数

高阶函数名字听着高大上,其实它只是一个函数,接收函数作为参数或将函数作为输出返回。常用到的回调函数或者闭包都是高阶函数。

1. 作为参数

我们日常使用的回调函数所在的函数,就是个高阶函数,还有一些数组的遍历方法的参数,也是传入函数,例如:mapreduce

JS
[].map(function(item, index, arr) {
  return item;
})
[].map(function(item, index, arr) {
  return item;
})

2. 作为返回值

JS
function bar(){
  return function (){
			
  }
}
function bar(){
  return function (){
			
  }
}

问题

1. 箭头函数相较传统函数有什么差异

  • 写法简洁
  • this 指向
  • 不能作为构造函数,所以也没用 prototype 属性
  • 没有 arguments 对象
  • 使用 call,apply,bind 不会改变箭头函数中的 this 指向
    • 当对箭头函数使用 callapply 方法时,只会传入参数并调用函数,并不会改变箭头函数中 this 的指向。
    • 当对箭头函数使用 bind 方法时,只会返回一个预设参数的新函数,并不会改变这个新函数的 this 指向。

示例:

JS
window.name = "window_name";

let f1 = function () {
  return this.name;
};
let f2 = () => this.name;

let obj = { name: "obj_name" };

console.log(f1.call(obj));      //obj_name
console.log(f2.call(obj));      // window_name
console.log(f1.apply(obj));     // obj_name
console.log(f2.apply(obj));     // window_name
console.log(f1.bind(obj)());    // obj_name
console.log(f2.bind(obj)());    // window_name
window.name = "window_name";

let f1 = function () {
  return this.name;
};
let f2 = () => this.name;

let obj = { name: "obj_name" };

console.log(f1.call(obj));      //obj_name
console.log(f2.call(obj));      // window_name
console.log(f1.apply(obj));     // obj_name
console.log(f2.apply(obj));     // window_name
console.log(f1.bind(obj)());    // obj_name
console.log(f2.bind(obj)());    // window_name