函数的种类
第一种,普通函数:用 function 关键字定义的函数。
function foo() {
// code
}
第二种,箭头函数:用 => 运算符定义的函数。
箭头函数没有自己的 this,arguments,super 或 new.target 。并且不能用作构造函数。
通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定 this ),他们的第一个参数会被忽略。
不绑定 arguments,arguments 只是引用封闭作用域内的 arguments 。
箭头函数没有 prototype 属性。
const foo = () => {
// code
}
第三种,方法:在 class 中定义的函数。
class C {
foo() {
// code
}
}
第四种,生成器函数:用 function* 定义的函数。
function* foo() {
// code
}
第五种,类:用 class 定义的类,实际上也是函数。
class Foo {
constructor() {
// code
}
}
第六/七/八种,异步函数:普通函数、箭头函数和生成器函数加上 async 关键字。
async function foo() {
// code
}
const foo = async () => {
// code
}
箭头函数与普通函数的区别
- 外形不同
- 箭头函数都是匿名函数:普通函数可以有匿名函数,也可以有具名函数,但是箭头函数都是匿名函数。
- 箭头函数不能用于构造函数,不能使用 new 。普通函数可以用于构造函数,以此创建对象实例。
箭头函数中的 this 指向不同:
在普通函数中, this 总是指向调用它的对象,如果用作构造函数, this 指向创建的对象实例。箭头函数本身不创建 this ,也可以说箭头函数本身没有 this ,但是它在声明时可以捕获其所在上下文的 this 供自己使用。注意: this 一旦被捕获,就不再发生变化。
var webName = "hello";
let func = () => {
console.log(this.webName); // 'hello'
}
func();
var name = "hello";
function wrap() {
this.name = "world";
let funct = () => {
console.log(this.name); // 'world'
}
func();
}
let en = new wrap();
箭头函数结合 call() , apply() 方法调用一个函数时,只传入一个参数对于 this 没有影响。
- 箭头函数不绑定 arguments ,取而代之用 rest 参数解决 ```javascript function A(a){ console.log(arguments); } A(1,2,3,4,5,8); // [1, 2, 3, 4, 5, 8, callee: ƒ, Symbol(Symbol.iterator): ƒ]
let B = (b)=>{ console.log(arguments); } B(2,92,32,32); // Uncaught ReferenceError: arguments is not defined
let C = (…c) => { console.log(c); } C(3,82,32,11323); // [3, 82, 32, 11323]
5. 箭头函数不能 Generator 函数,不能使用 yeild 关键字。
6. 箭头函数不具有 prototype 原型对象。
7. 箭头函数不具有 super 。
8. 箭头函数不具有 new.target 。
<a name="c4c9a0d277879cd3c4b33401ecf7f04a"></a>
# 立即执行函数
此类函数没有声明,在一次执行过后即释放。适合做初始化工作。
```javascript
(function () {
var a = 123;
var b = 234;
console.log(a + b);
}())
// 第一种写法
(function () {}())
// 第二种写法
(function (){})()
// 只有表达式才能被执行符号执行
function () {
console.log('a');
}();
// 上面这段代码不能被执行,因为这个是函数声明
// 能被执行符号执行的表达式会自动放弃函数名称,也就是一个表达式能被执行后就会忽略这个表达式的名字
var test = function() {
console.log('a');
}();
// 在控制台里输入test,输出undefined
js中的全局函数
- decodeURI() :解码某个编码的 URI
- decodeURIComponent() :解码一个编码的 URI 组件
- encodeURI() :把字符串编码为 URI
- encodeURIComponent():把字符串编码为 URI 组件
- escape():对字符串进行编码
- eval():计算 js 字符串,并把它作为脚本代码来执行
- isFinite() :检查某个值是否为有穷大的数
- isNaN():检查某个值是否是数字
- Number():把对象的值转换为数字
- parseFloat():解析一个字符串并返回一个浮点数
- parseInt():解析一个字符串并返回一个整数
- String():把对象的值转换为字符串
- unescape():对由 escape() 编码的字符串进行解码
函数柯里化
维基百科上说道:柯里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个的参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
简单demo:
// 普通的 add 函数
function add(x, y) {
return x + y;
}
// 柯里化后
function curryingAdd(x) {
return function(y) {
return x + y;
}
}
add(1, 2); // 3
curryingAdd(1)(2); // 3
柯里化的好处:
- 参数复用 ```javascript // 正常正则验证字符串 reg.test(txt)
// 函数封装后 function check(reg, txt) { return reg.test(txt); }
check(/\d+/g, ‘test’); // false check(/[a-z]+/g, ‘test’); // false
// 柯里化后 function curryingCheck(reg) { return function(txt) { return reg.test(txt); } }
var hasNumber = curryingCheck(/\d+/g) var hasLetter = curryingCheck(/[a-z]+/g) hasNumber(‘test1’) // true hasNumber(‘testtest’) // false hasLetter(‘212121’) // false
2. 提前确认
3. 延迟运行:bind 实现的机制实际上就是柯里化。
封装一个实现柯里化的函数
```javascript
function curry(fn, args) {
var length = fn.length; // 函数参数的长度
// 闭包保存参数列表
args = args || [];
return function() {
// 获取参数列表。
var _args = args.slice(0);
Array.prototype.push.apply(_args, Array.prototype.slice.call(arguments))
if (_args.length < length) {
// 如果传入的参数列表长度还没有超过函数定义时的参数长度,就 push 新的参数到参数列表中保存起来。
// 自己调用自己,将保存的参数传递到下一个柯里化函数。
return curry.call(this, fn, _args);
}
else {
// 如果传入的参数列表长度已经超过函数定义时的参数长度,就执行。
return fn.apply(this, _args);
}
}
}
function sum(a, b, c) {
return a+b+c;
}
const add = curry(sum)
console.log(add(1,2)(3))
柯里化的性能:
- 存取 arguments 对象通常要读存取命名参数要慢一点
- 一些老版本的浏览器在 arguments.length 的实现上是相当慢的
- 使用 fn.apply() 和 fn.call() 通常比直接调用 fn() 稍微慢点
- 创建大量嵌套作用域和闭包函数会带来花销,无论是内存还是速度上
new的模拟实现
new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象类型之一。
- 生成一个新对象
- 链接到原型
- 绑定 this ,函数体执行
- 如果函数返回的是对象,返回这个对象,否则返回自己生成的对象
function objectFactory() {
var obj = new Object();
var Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
var ret = Constructor.apply(obj, arguments);
return typeof ret === 'object' ? ret : obj;
};
参考链接: