关于javascript:你真的了解箭头函数和普通函数吗

8次阅读

共计 4256 个字符,预计需要花费 11 分钟才能阅读完成。

1. 箭头函数

ES6中容许应用箭头函数 => 来定义函数,箭头函数相当于匿名函数,并且简化了函数定义。

例:

const add = (x, y) => x + y
const fn = (name) => ({name})

个性:

  • 语法简洁,代码量少。
  • 没有本人的 this,它会继承外层作用域的 this
  • 不能作为构造函数,不能用 new 关键字创建对象实例,也不能用作构造函数。
  • 不能应用 arguments 对象,它没有本人的 arguments 对象,会继承外层作用域的 arguments
  • 适宜短小的函数、或者作用回调函数

2. 一般函数

函数的定义形式通常有三种,函数申明形式 函数表达式、应用 Function 构造函数;

2.1、函数申明形式

function add(a, b) {return a + b}

2.2、函数表达式

const fn = function(name) {return { name}
}

2.3、应用 Function 构造函数

const sum = new Function("num1", "num2", "return num1 + num2")

2.4、三种形式的区别

次要从 作用域 效率 加载程序 来辨别

2.4.1、作用域

函数申明、函数表达式申明、Function() 应用的都是 局部变量

var name = "我是全局变量 name"
// 申明式
function a() {
  var name = "我是函数 a 的 name"
  return name;
}
console.log(a()) // 我是函数 a 的 name


// 表达式
var b = function() {
  var name = "我是函数 b 的 name";return name;
}
console.log(b()) // 我是函数 b 的 name


// Function 构造函数
var c = new Function("const name =' 我是函数 c 的 name';return name;")
console.log(c()); // 我是函数 c 的 name
2.4.2、执行效率

Function() 构造函数效率要低于其余两种形式,尤其是在循环中,因为构造函数每执行一次都要从新编译,并生成新的函数对象

2.4.2、加载程序

函数申明式在 JavaScript 编译时就会加载到作用域中,而其余两种形式则是在代码执行时加载,在定义之前调用它,会返回 undefined

console.log(typeof f) // function
console.log(typeof c) // undefined
console.log(typeof d) // undefined

function f() {return "f"}

var c = function() {return "c"}
console.log(typeof c) // function

var d = new Function("return'd'");
console.log(typeof d) // function

2.5、函数的参数

2.5.1、arguments

arguments 对象的 length 属性显示实参的个数,函数的 length 属性显示形参的个数。

function sum(x, y) {console.log(arguments.length) // 3
  return x + 1;
}
sum(1, 2, 3);
console.log(sum.length); // 2
2.5.1、同名参数

非严格模式下,函数中能够呈现同名形参,而且只能拜访最初一个呈现的形参

function sum(x, x, x) {return x;}
console.log(sum(1, 2, 3)); // 3

严格模式下会抛出语法错误 SyntaxError: Duplicate parameter name not allowed in this context

2.6、函数的返回值

默认所有的函数都有返回值,没有 return 时,默认返回内容为 undefined

function sum1(x, y) {var total = x + y;}
console.log(sum1()); // undefined

function sum2(x, y) {return x + y;}
console.log(sum2(1, 2)); // 3

如果函数调用时,后面加了 new 前缀,且返回值不是一个对象,则返回 this,如果是一个对象,则返回该对象

function Book() {this.bookName = "JS 深入浅出"}
var book = new Book();
console.log(book); // Book {bookName: "JS 深入浅出"}
console.log(book.constructor); // [Function: Book] 

function Book() {return { bookName: "JS 深入浅出"};}
var book = new Book();
console.log(book); //  {bookName: "JS 深入浅出"}
console.log(book.constructor); // [Function: Book] 

2.7、匿名函数

匿名函数是一种在 JavaScript 中定义的函数形式,他没有给函数起一个具体的名称,匿名函数通常在须要时间接定义应用,而不须要事后命名,这种函数在语法上与一般函数相似,只是省略了函数名。
用处:

  • 函数表达式,将匿名函数赋值给变量,能够创立函数表达式,这使得函数能像其余数据类型一样贮存在变量中
const add = function(a, b) {return a + b;}
console.log(add(3, 5)); // 8
  • 作为参数传递,用于回调或特定操作
setTimeout(function() {console.log("Delayed message")
}, 1000) 
  • 立刻执行函数,能够创立一个公有作用域
(function() {console.log("IIFE executed")
})();
  • 函数属性,将匿名函数调配给对象属性,已创建对象的办法
const obj = {sayHello: function() {console.log("Hello")
 }
}
obj.sayHello(); // Hello

总之,匿名函数是一种在须要时长期创立函数的形式,实用于须要传递函数、作为参数、创立公有作用域、动静定义函数时;

一般函数的个性:

  • 领有本人的 this: 一般函数在调用时会有本人的this 上下文,this 的值取决于函数被调用的形式
  • 能够作为构造函数:一般函数能够通过 new 关键字创建对象实例,用作构造函数。
  • 能够应用 arguments 对象:一般函数领有本人的 arguments 对象,用于获取函数参数。
  • 语法绝对简单:须要 function 关键字来定义

3. 箭头函数与一般函数的区别

let fn = (name) => {console.log(name);
}

let fn2 = function(name) {console.log(name);
}

console.log(fn);
console.log(fn2);

看起来,箭头函数少了 caller arguments prototype

3.1、申明形式不同

  • 申明一个一般函数须要 function 来实现,并且应用 function 既能够申明成一个具名函数,也能够申明成一个匿名函数
  • 申明一个箭头函数则只有应用箭头就能够了
  • 箭头函数只能申明匿名函数,但能够通过表达式的形式让箭头函数具名

3.2、箭头函数没有 prototype(原型)

const a = () => {};
console.log(a.prototype); // undefined

const b = () => {};
console.log(b.prototype); // {constructor: f}

3.3、箭头函数不能当成一个构造函数

let fn = (value) => value;
const f = new fn("hi"); // Uncaught TypeError: fn is not a constructor

new 实现原理:

  • 创立一个新对象
  • 将该对象的原型链连贯到构造函数的原型对象上,使其继承构造函数的属性和办法
  • 将构造函数中的 this 指向新创建的对象
  • 执行构造函数外部的代码,给新对象增加属性和办法
  • 如果构造函数没有返回其余对相干,则返回新创建的对象;如果构造函数返回了一个非根本类型的值,则返回这个对象,否则还是返回新创建的对象;
function myNew(fn, ...args) {
  // 创立一个新对象
  let target = {};

  // 将这个空对象的 __proto__指向构造函数的原型
  target.__proto__ = fn.prototype;

  // 将 this 指向空对象
  let res = fn.apply(target, args)

  // 对构造函数返回值做判断,而后返回
  return res instanceof Object ? res : target;
}

因为箭头函数没有本人的 this,他的 this 是外层执行环境的 this,且指向不会产生扭转。并且箭头函数没有原型 prototype,没法让他的实例的 proto 指向箭头函数的原型,所以构造函数无奈作为构造函数。

3.4、箭头函数不反对 new.target

new 是从构造函数生成实例对象的命令,ES6new 命令引入了一个 new.target 属性,这个属性个别用在构造函数中,返回 new 调用的那个构造函数,如果构造函数不是通过 new 命令或者 Reflect.connstruct() 调用的,new.target 会返回 undefined,所以这个属性能够用来确定构造函数是怎么调用的;

function fn() {console.log("fnc", new.target);
}

fn(); // fn: undefined
new fn(); // fn: [Function: fn]

// 箭头函数的 this 指向全局对象时
let fn2 = () => {console.log("fn2", new.target);
}
fn2; // Uncaught SyntaxError: new.target expression is not allowed here

// 箭头函数 this 指向一般函数时
function func() {let test = () => {console.log(new.target); // 指向函数 func: [Function: func]
  }
  test();}

new func();
  • new.target 属性个别用在构造函数中,返回 new 调用的那个构造函数;
  • 箭头函数的 this 指向全局对象,在箭头函数中应用 new.target 会报错
  • 箭头函数的 this 指向一般函数,它的 new.target 就是指向改一般函数的援用
正文完
 0