这个系列是我读冴羽老师博客的感悟,
加入了个人的解读和练习题的解答
MDN 对 bing 的定义
bind()方法会创建一个新函数。当这个函数被调用时,bind()的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数
bind 函数的两个特点:
1.返回一个函数
2.可以传入参数
例子 1:
1
2
3
4
5
6
7
8
9
10
|
var foo = {
value: 1,
}
function bar() {
console.log(this.value)
}
var bindFoo = bar.bind(foo)
bindFoo() //1
|
第一版
1
2
3
4
5
6
|
function myBind(context) {
var self = this
return function () {
return self.apply(context)
}
}
|
刚才的定义中提到 bind 还支持传参数来看个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
var foo = {
value: 1,
}
function bar(name, age) {
console.log(this.value)
console.log(name)
console.log(age)
}
var bindFoo = bar.bind(foo, 'daisy')
bindFoo('18')
// 1
// daisy
// 18
|
第二版
1
2
3
4
5
6
7
8
9
|
function myBind(context) {
var self = this
var args = Array.prototype.slice.call(arguments, 1)
return function () {
var bindArgs = Array.prototype.slice.call(arguments)
return self.apply(context, args.concat(bindArgs))
}
}
|
此时到了最难的部分,bind 还有一个特性:
一个绑定函数也能使用 new 操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
来看例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
var value = 2
var foo = {
value: 1,
}
function bar(name, age) {
this.habit = 'shopping'
console.log(this.value)
console.log(name)
console.log(age)
}
bar.prototype.friend = 'kevin'
var bindFoo = bar.bind(foo, 'daisy')
var obj = new bindFoo('18')
// undefined 提供的this值被忽略
// daisy 调用bind时的参数被一起提供了
// 18
console.log(obj.habit)
console.log(obj.friend)
// shopping
// kevin
|
第三版
1
2
3
4
5
6
7
8
9
10
|
function myBind(context) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1)
var fBound = function(){
var bindArgs = Array.prototype.slice.call(arguments)
return self.apply(this instanceOf fBound? this : context, args.concat(bindArgs))
}
fBound.prototype = this.prototype;
return fBound;
}
|
但是在这个写法中,我们直接将 fBound.prototype = this.prototype,
我们直接修改 fBound.prototype 的时候,也会直接修改绑定函数的 prototype。
这个时候,我们可以通过一个空函数来进行中转:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function myBind(context) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1)
var fNop = function(){}
var fBound = function(){
var bindArgs = Array.prototype.slice.call(arguments)
return self.apply(this instanceOf fNop? this : context, args.concat(bindArgs))
}
fNop.prototype = this.prototype;
fBound.prototype = new fNop()
return fBound;
}
|
以后要在生产环境中使用时,我们再补上对参数和函数名字的判断
第四版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
Function.prototype.bind = Function.prototype.bind || function(context) {
if (typeof this !== "function") {
throw new Error(this + ".bind is not a function!")
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNop = function(){}
var fBound = function() {
var bindArgs = Array.prototype.slice.call(arguments)
return self.apply(this instanceOf fNop? this : context, args.concat(bindArgs))
}
fNop.prototype = this.prototype;
fBound.prototype = new fNop();
return fBound;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
const bind = function (newThis) {
const self = this
const args = Array.prototype.slice.call(arguments, 1)
const resultFn = function () {
const args2 = Array.prototype.slice.call(arguments)
self.apply(this instanceof resultFn ? this : newThis, args.concat(args2))
}
resultFn.prototype = self.prototype
return resultFn
}
Function.prototype.bind2 = bind
function test1() {
const testFn = function () {
console.log(this, arguments)
}
const bindFn = testFn.bind2(
{
name: 'Neo',
},
123
)
bindFn(456)
}
function test2() {
const a = function (name, age) {
this.name = name
this.age = age
}
a.prototype.sayHi = function () {
console.log('hi')
}
const aaa = a.bind2(undefined, 'Neo', 20)
const object = new aaa()
console.log('object', object)
console.log(a.prototype.isPrototypeOf(object))
console.log(typeof object.sayHi === 'function')
}
test1() //测试 bind api是否正常
test2() //测试 bind 是否支持new
|