this的六大场景
1. 全局上下文
2. 直接调用函数
3. 对象.方法的形式调用
4. DOM事件绑定(特殊)
5. new构造函数绑定
6. 箭头函数
1. 全局上下文 全局上下文默认this指向window, 严格模式下指向undefined。
2. 直接调用函数 this相当于全局上下文的情况。
3.对象.方法的形式调用 this指向这个对象/方法
4. DOM事件绑定
onclick和addEventerListener中 this 默认指向绑定事件的元素。 IE比较奇异,使用attachEvent,里面的this默认指向window。
5. new+构造函数
此时构造函数中的this指向实例对象。
- 箭头函数
箭头函数没有this, 因此也不能绑定。里面的this会指向当前最近的非箭头函数的this,找不到就是window(严格模式是undefined)。
let obj = {
a: function() {
let do = () => {
console.log(this);
}
do();
}
}
obj.a(); // 找到最近的非箭头函数a,a现在绑定着obj, 因此箭头函数中的this是obj
优先级: new > call、apply、bind > 对象.方法 > 直接调用。
- call/bind/apply
call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔,直接放到后面
apply 的所有参数都必须放在一个数组里面传进去
bind 除了返回是函数以外,它 的参数和 call 一样
- 模拟实现一个 bind 的效果
bind所做的事情:
1. 对于普通函数,绑定this指向
2. 对于构造函数,要保证原函数的原型对象上的属性不能丢失
Function.prototype.bind = function (context, ...args) {
// 异常处理
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
// 保存this的值,它代表调用 bind 的函数
var self = this;
var fNOP = function () {};
var fbound = function () {
self.apply(this instanceof self ?
this :
context, args.concat(Array.prototype.slice.call(arguments)));
}
fNOP.prototype = this.prototype;
fbound.prototype = new fNOP();
return fbound;
}
也可以这么用 Object.create 来处理原型:
Function.prototype.bind = function (context, ...args) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;
var fbound = function () {
self.apply(this instanceof self ?
this :
context, args.concat(Array.prototype.slice.call(arguments)));
}
fbound = Object.create(this.prototype);
return fbound;
}
-
call/apply 函数
//大佬的代码
Function.prototype.call = function (context) {
var context = context || window;
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args +')');
delete context.fn
return result;
}
不过我认为换成 ES6 的语法会更精炼一些:
Function.prototype.call = function (context, ...args) {
var context = context || window;
context.fn = this;
var result = eval('context.fn(...args)');
delete context.fn
return result;
}
类似的,有apply的对应实现:
Function.prototype.apply = function (context, args) {
let context = context || window;
context.fn = this;
let result = eval('context.fn(...args)');
delete context.fn
return result;
}