如果浏览器不支持 bind 函数,实现一个函数让其兼容
主要考察bind
方法
this
关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列call
,apply
方法区别: 都是Function
对象内置的方法,挂载在Function
原型下共享方法,它们的第一个参数都是用来更改调用方法中 this
的指向。需要注意的是 bind
是返回新的函数,以便稍后调用,它往往跟事件结合使用,只有触发了事件,才会调用,而apply
、call
则是立即调用原函数const module = {
name: 'itclanCoder',
getName: function() {
return this.name;
},
};
const unboundGetName = module.getName;
console.log(unboundGetName()); // 函数在全局范围内被调用,undefined,这里的this指向的是window,很多面试题在全局范围定义了一个var name = "川川",那么此处便会输出"川川",因为这里全局作用域内没有name,所以是undefined
const boundGetName = unboundGetName.bind(module); // 通过bind改变this的指向,指向module对象
console.log(boundGetName()); // itclanCoder
在上面的示例代码中,将一个方法从对象中拿出来(上面的 getName
就是 module
对象下的一个方法),然后再调用(module.getName
赋值给 unboundGetName
),总期望方法中的 this
是原来的对象(在这里指的是 module
对象,比如在回调中传入这个方法)。
如果不做特殊处理的话,一般会丢失原来的对象。基于这个函数,用原始的对象创建一个绑定函数,巧妙地解决了这个问题(上面使用 bind 后就解决了这个问题,让 this 指向了 module 对象)
// 所要改变的this指向的那个函数.bind(thisArg[, arg1[, arg2[, ...]]])
function.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
: 当绑定函数被调用时,该参数会作为 this
的指向。当使用 new
操作符调用绑定函数时,该参数无效,会被忽略,当使用bind
在 setTimeout
中创建一个函数(作为回调提供)时,作为 thisArg
传递的任何原始值都将转换为object
。如果 bind
函数的参数列表为空,或者 thisArg
是 null
或 undefined
,执行作用域的 this
将被视为新函数的 thisArg
arg1
, arg2
: 当目标函数被调用时,被预置入绑定函数的参数列表中的参数this
值和初始参数bind()
的参数写在 this
后面。当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面,如下所示function list() {
return Array.prototype.slice.call(arguments); // 将类数组转换成真正的数组
}
function addArguments(arg1, arg2) {
return arg1 + arg2
}
var list1 = list(1, 2, 3); // [1, 2, 3]
var result1 = addArguments(1, 2); // 3
// 创建一个函数,它拥有预设参数列表。
var leadingThirtysevenList = list.bind(null, 37);
// 创建一个函数,它拥有预设的第一个参数
var addThirtySeven = addArguments.bind(null, 37);
var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
var result2 = addThirtySeven(5); // 37 + 5 = 42
var result3 = addThirtySeven(5, 10);// 37 + 5 = 42 ,第二个参数会被忽略
setTimeout
一起使用 在默认情况下,使用 window.setTimeout()
时,此时this
关键字会指向 window
(或 global
)对象。当类的方法中需要 this
指向类的实例时,你可能需要显式地把this
绑定到回调函数,这样就不会丢失该实例的引用也就是说,当使用类的方法时需要this
指向类实例,就可以使用bind()
将 this
绑定到回调函数来管理实例
function Bloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// 在 1 秒钟后声明 bloom
Bloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000); // 这里的this原本指向window,但是通过bind方法后,指向Bloomer
};
Bloomer.prototype.declare = function() {
console.log('我有 ' + this.petalCount + ' 朵花瓣!');
};
var flower = new Bloomer();
flower.bloom(); // 1秒后输出 我有 11 朵花瓣
注意
对于事件处理函数和 setInterval
方法也可以使用上面的方法
new
操作符来构造目标函数的实例。当使用绑定函数来构造实例注意this
会被忽略,但是传入的参数仍然可用 如下实例代码所示function Point(x, y) { // 声明构造器Point函数
this.x = x;
this.y = y;
}
Point.prototype.toString = function() { // 构造器Point方法原型下添加toString
return this.x + ',' + this.y;
};
var p = new Point(1, 2);
p.toString(); // '1,2'
var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// 实现中的例子不支持,
// 原生bind方法支持
var YAxisPoint = Point.bind(null, 0/*x*/);
var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'
axisPoint instanceof Point; // true,axisPoint是Point的实例化出来的一对象
axisPoint instanceof YAxisPoint; // true,axisPoint是YAxisPoint实例化出来的一对象
new Point(17, 42) instanceof YAxisPoint; // true // 同上
在上面的示例代码中,Point
和YAxisPoint
是共享原型对象,因此使用 instanceof
运算符判断时为 true
bind()
也可以为需要特定 this
值的函数创造捷径var slice = Array.prototype.slice;
slice.call(arguments);
如果使用 bind()
的话,情况变得更简单
// 与前一段代码的 "slice" 效果相同,下面使用了bind
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
slice(arguments);
在上面的示例代码中,bind()
有很多的使用场景,但是bind()
函数是在 ECMA-262 第五版才被加入;它可能无法在所有浏览器上运行。这就需要我们自己实现 bind()函数了,在面试题中,可以说是屡见不爽,屡见屡面
//在Function的原型上自定义myBind()方法
Function.prototype.myBind = function myBind(context){
//获取要操作的函数
var _this=this;
//获取实参(context除外)
var args=Array.prototype.slice.call(arguments,1);
//判断当前浏览器是否兼容bind()方法
if('bind' in Function.prototype){
//如果浏览器兼容bind()方法,则使用bind()方法,并返回bind()方法执行后的结果
return _this.bind(context,args);
}
//如果不兼容bind()方法,则返回一个匿名函数
return function(){
_this.apply(context,args);
}
}
bind
函数来给一个对象绑定事件attachEvent()
不直接传入回调函数,而是先定义一个匿名函数,然后在函数内部调用回调函数,并利用 call
方法改变 this
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
window.onload = function() {
var btn1 = document.getElementById("btn1");
bind(btn1, "click", function() {
alert(this);
});
};
//定义一个函数bind(),用来为指定元素绑定事件响应函数
/*
* 参数:
* obj 要绑定事件的对象
* eventStr 事件的字符串
* func 回调函数
*/
function bind(obj, eventStr, func) {
//判断是否有addEventListener()方法
if(obj.addEventListener) {
//大部分浏览器兼容的方式,addEventListener是标准浏览器支持的
obj.addEventListener(eventStr, func, false);
} else {
//IE8及以下,注意使用的是on,绑定事件使用的是attachEvent
//obj.attachEvent("on"+eventStr, func);//此方法this为window下面提供解决方法
//统一this 不直接调用func而是在匿名函数内调用
obj.attachEvent("on" + eventStr, function() {
//在匿名函数内调用回调函数 利用call()方法将this改为obj
func.call(obj);
});
}
};
</script>
</head>
<body>
<button id="btn1">btn1</button>
</body>
</html>
以上就是bind
方法使用相关介绍.