重新认识了一下函数
函数的三种角色
一些函数作为对象的属性
length
:形参的个数;name
:函数名;prototype
:类的原型,在原型上定义的方法都是当前这个类的实例的公有方法;__proto__
:把函数当做一个普通对象,指向Function这个类的原型
函数的角色
- 普通函数。它本身是一个普通的函数,执行的时候会形成私有的作用域,然后进行形参赋值、预解析、代码执行、执行完成后内存销毁;
- 类。有自己的实例,也有一个叫做
prototype
的属性是自己的原型,它的实例都可以指向自己的原型; - 普通对象。它作为对象可以有一些自己的私有属性,也可以通过
__proto__
找到Function.prototype
;
call
方法原理
1 | function sum(){ |
一个经典栗子(需要深入理解call
原理和原型链)
1 | function fn1() { |
第二个输出有了前面的基础就很好理解了。前面了解到函数可以作为普通对象,然后有原型链搜索这一过程。
1 | fn2 { |
第二次的call
将fn1.call
这个函数的this
绑定到fn2
上(将fn2
作为普通对象),再将fn1.call
重新执行,此时,fn1.call
函数里面的this就指向了fn2
这个对象了,所以不是重新执行fn1()
,而是重新执行fn2()
。
思考
1 | Array.prototype.slice.call(arguments) || [].slice.call(arguments) |
这个方法用于将类数组对象转化为数组。
call、apply、bind的区别
call
和apply
基本一样,就是传递参数形式不一样
1 | function fn(num1, num2) { |
bind
有点不一样,它会返回函数,而不是立即执行
1 | var tempFn = fn.bind(obj, 1, 2); |
补充一下ES5
的严格模式
1 | -- 严格模式 |
apply
和call
的实现基本一样,就是处理arguments不一样。
1 | if(arguments[1]) { |
自己实现一个bind
1 | function myBind() { |
Function.apply.bind
看一个js
的高级技巧
1 | Promise.resolve([10,20]).then(Function.apply.bind(function(x, y){ |
先不管Promise
1 | var sum = function(x, y) { |
sum.apply(null, [10, 20])
很好理解,bind(sum)
使Function.apply
这个函数里面的this指向了sum
这个函数对象,所以Function.apply.bind(sum, null)
等价于sum.apply.bind(sum, null)
,bind
的使命已经完成了。所以就等价于sum.apply
。
Function.bind.apply
1 | Function.bind.apply(sum, null) |
原理一样的。等价于sum.bind(sum, null)
,就等价于sum
看起来很简单,其实还是有很多东西的,哈哈,是不是感觉收获颇丰啊,不用谢了啦。