一些误解
- 指向自身?(并不是所有时候都指向自身)
- 作用域问题?(this并不一定指向函数的作用域,并且在任何时候都不指向函数的词法作用域)
- this到底是什么?(this是运行时绑定的并不是在编写时绑定,他的上下文取决于函数调用时的各种条件和函数声明的位置没有任何关系,只取决于函数的调用方式)
this的指向
- 全局范围使用this和全局函数调用都指向全局对象(在严格模式下undefined)
- 方法调用内this指向调用对象
- new绑定调用构造函数,在函数内部指向新创建的对象
- 通过call、apply显式的的设置this对象,指向设置的对象
关于call、apply、bind
var links = document.querySelectorAll('nav li');
for (var i = 0; i < links.length; i++) {
console.log(this); // [object Window]}
有时候我们需要根据实际的需求来变化代码的作用域,就需要
call、apply、bind动态的传入函数引用。
var links = document.querySelectorAll('nav li');
for (var i = 0; i < links.length; i++) {
(function () {
console.log(this);
}).call(links[i]);
}
其中.call(scope, arg1, arg2, arg3)输入单个参数,而.apply(scope, [arg1, arg2])输入数组作为参数。在ES5中引入了bind方法,bind()并不触发函数,它仅仅是在函数触发前绑定值。
nav.addEventListener('click', toggleNav.bind(scope, arg1, arg2), false);
在不需要调用的时候就可以传递参数,函数并没被触发,scope可以被改变,且参数在等着传递。
其它
bind源码
if(!('bind' in Function.prototype)){
Function.prototype.bind = function(){
var fn = this,
context = arguments[0],
args = Array.prototype.slice.call(arguments, 1);
return function(){
return fn.apply(context, args.concat(arguments));
}
}
}
bind()方法通常被用在上下文丢失的场景下,例如面向对象和事件处理。之所以要这么做,是因为节点的addEventListener方法总是为事件处理器所绑定的节点的上下文中执行回调函数,这就是它应该表现的那样。但是,如果你想要使用高级的面向对象技术,或需要你的回调函数成为某个方法的实例,你将需要手动调整上下文。这就是bind方法所带来的便利之处。
bind源码中调用了Array的slice方法,我们知道arguments对象并不是一个真正的数组,而是一个类数组对象,虽然具有length属性,并且值也能够被索引,但是它们不支持原生的数组方法,例如slice和push。但是,由于它们具有和数组类似的行为,数组的方法能够被调用和劫持,因此我们可以通过类似于上面代码的方式达到这个目的,其核心是利用call方法。
网友评论