以前说了模拟实现 call 和 apply,下面就来实现 bind,首先先看一下定义 bind 定义app
bind()方法建立一个新的函数,在 bind()被调用时,这个新函数的 this 被 bind 的第一个参数指定,其他的参数将做为新函数的参数供调用时使用。函数
根据定义咱们尝试写一下post
Function.prototype.binds = function(con) {
var fn = this;
var args = Array.prototype.slice.call(arguments, 1);
return function() {
return fn.apply(con, args);
};
};
复制代码
咱们来测试一下上面的函数测试
var obj = {
value: "zhangsan"
};
function foo(name, age) {
console.log(this.value); //zhangsan
console.log(name); // name
console.log(age); // undefined
}
var f = foo.binds(obj, "name");
f(19);
复制代码
age
输出的跟咱们预期的不太一致,这是由于咱们没有处理返回函数的参数,用 concat 把参数合并在一块儿就能够了。优化
Function.prototype.binds = function(con) {
var fn = this;
var args = Array.prototype.slice.call(arguments, 1);
return function() {
return fn.apply(con, args.concat(Array.prototype.slice.call(arguments)));
};
};
复制代码
上面简单实现了函数的 bind,不过咱们来看一下 bind 与构造函数相遇会怎么样ui
var obj = {
value: "zhangsan"
};
function Foo(name, age) {
console.log(this.value); //undefined
console.log(name);
console.log(age);
}
var f = Foo.bind(obj, "name");
new f(19);
复制代码
上面 this.value
的输出为 undefined
,这是由于 调用绑定函数时做为 this 参数传递给目标函数的值。 若是使用 new 运算符构造绑定函数,则忽略该值。this
另外做为构造函数是能够获取到绑定 bind 函数的 prototype
的spa
function Foo() {
console.log(this.gender); //male
}
Foo.prototype.gender = "male";
var f = Foo.bind(null, "name");
new f();
复制代码
下面就是来实现上面两点:prototype
instanceof
function Foo() {
if (!(this instanceof Foo)) {
throw Error("请经过new调用");
}
}
Foo();
复制代码
function create(con) {
var f = function() {};
f.prototype = con;
return new f();
}
function Par(name) {
this.name = name;
}
Par.prototype.getName = function() {
return this.name;
};
function Chi(name, age) {
Par.call(this, name);
this.age = age;
}
Chi.prototype = create(Par.prototype);
Chi.prototype.constructor = Chi;
Chi.prototype.getDetails = function() {
var n = this.getName();
console.log(n, this.age);
};
var d = new Chi("zhangsan", 16);
d.getDetails();
复制代码
OK,上面两点解决后咱们再来实现一版code
Function.prototype.binds = function(con) {
var fn = this;
var args = Array.prototype.slice.call(arguments, 1);
var f = function() {};
if (this.prototype) {
f.prototype = this.prototype;
}
var result = function() {
return fn.apply(
this instanceof result ? this : con,
args.concat(Array.prototype.slice.call(arguments))
);
};
result.prototype = new f();
return result;
};
复制代码
观察上面的不难发现 bind 调用的必须是函数,而经过继承咱们可能会调用到 bind 因此这里显示报错一下
var obj = Object.create(Function.prototype);
console.log(obj.bind);
复制代码
另外对于咱们上面定义的binds
确定不太优雅,污染了命名空间,这里能够判断一下若是存在 bind
就用 bind
不然在定义
if (!Function.prototype.bind) {
Function.prototype.bind = function(con) {
if (typeof this !== "function") {
throw new TypeError(
"Function.prototype.bind - what is trying to be bound is not callable"
);
}
var fn = this;
var args = Array.prototype.slice.call(arguments, 1);
var f = function() {};
if (this.prototype) {
f.prototype = this.prototype;
}
var result = function() {
return fn.apply(
this instanceof result ? this : con,
args.concat(Array.prototype.slice.call(arguments))
);
};
result.prototype = new f();
return result;
};
}
复制代码