【JS】普通函数、箭头函数、构造函数的区别
函数隶属于对象,据有[[Call]]
属性的对象都为“function”(typeof判断类型的关键);
函数对象支持[[Call]]
、[[Construct]]
每个构造函数必须是一个函数对象,想要对某个对象使用new,就得确保对象据有[[Construct]]
,每个支持[[Construct]]
的对象必须支持[[Call]]
调用方式不同,普通函数直接调用,构造函数用new调用
作用不一样,构造函数用来创建新的实例对象
this指向不同,普通函数指向window,构造函数this指向它创建的实例对象
箭头函数没有[[Construct]]
,不能使用new关键字,不能用作构造函数。
设计者想设计一种简短且不绑定this的函数,所以不让箭头函数具有[[Construct]]
方法。
箭头函数中的 this、super、arguments 及 new.target 这些值由外围最近一层非箭头函数决定。
(1)、语法更简洁
(2)、箭头函数不会创建自己的this,它的this指向定义时外层执行环境的this,箭头函数中this的指向在它被定义的时候就已经确定了,之后永远不变。
(3)、箭头函数继承而来的this,永远不变。
(4)、.call()
、.apply()
、.bind()
无法改变箭头函数的this指向
(5)、箭头函数不能作为构造函数使用。
(6)、箭头函数没有自己的arguments。
(7)、箭头函数没有原型prototype,let a=()=>{} //a.prototype 是 undefined
。
(8)、箭头函数不能用作Generator函数,不能使用yeild关键字
补充:
函数直接声明
function fname(){}
函数表达式声明
let fname = function(){}
这样的函数没有名称,也称为匿名函数
也可以提供函数名,且可以用于函数内部指代其本身
let fname = function fun(n) {return n+fun(n-1)}
构造函数声明
let fname = new Fun(){}
箭头函数
let fname = () => {}
函数声明会被提升至当前所在函数范围内的顶部。
注意:
(1)、变量提升只是提升声明变量,却未被定义(访问后面定义的变量为undefined);
(2)、函数的提升是整个已经被声明和被定义的函数(可以访问后面定义的函数)。
在函数内可以用arguments[i]
找出传入的参数,i是参数的序数编号。
使用arguments可以获取除了声明参数之外的参数,这在事先不知道会需要多少参数传递给函数时十分有用。
arguments对象是类数组对象,有一个索引编号和length属性,并不拥有所有array对象的操作方法
Array.isArray(arguments) //false
Array.prototype.slice.call(arguments)
可以把arguments转化为数组
默认参数:undefined,可以手动设置
箭头函数也可以指定默认参数
值:具有某种类型的数据
引用:可用来获取特定数据的值
值类型:能直接方法的数据类型。
引用类型:借助引用才能被访问的数组类型。
参数为函数,返回函数
比如快排sort()
形参赋值先于函数提升。
js允许表达式作为参数
函数作用域是可以访问上级作用域下的标志符。
外部作用域无法访问函数内部的任意内容。避免了函数作用域中的标志符不与全局作用域的标志符产生冲突。
我们在全局作用域下额外的添加了新的标志符。
对“隐藏”起来的代码,我们还必须显示地通过函数名才能执行里面的代码。
(function foo(){ … })():由于函数声明被包含在一对( ) 括号内部,因此成为了一个函数表达式,通过在末尾加上另外一个( )可以立即执行这个函数。
第一个( )将函数声明变成函数表达式
说明不会有函数提升。
第二个( )执行了这个函数。
还可以写成(function(){…}()),两者一致的。
值的初始化:
js在定义变量的时候就完成了内存分配
通过函数调用分配内存:
有些函数调用结果是分配对象内存的let n = new Date()
有些方法分配新变量或者新对象a=[1],b=[2],c=a.concat(b)
堆内存:存储引用数据类型值
栈内存:提供js代码执行的环境和存储基本类型值
使用值
使用值的过程实际上是对分配内存的进行读取与写入操作,读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。