作为js中一个很难解释清楚的概念,this的问题一直困扰着前端的初学者们,在不同的语境里,this的含义不同,那么究竟怎么理解js中的this呢?
全局环境下
- this指向window node环境指向global
- 普通函数里的this 指向window 严格模式下指向undefined
function f() {
console.log(this === window);
}
f() // true
function f() {
'use strict';
console.log(this === undefined);
}
f() // true
构造函数里 指的是实例
var Obj = function (p) {
this.p = p;
};
var 0 = new Obj('hello');
0.p // 'hello'
对象的方法里,指的是引用它的对象 且不能被继承
var obj ={
foo: function () {
console.log(this);
}
};
obj.foo() // obj
// 情况一
(obj.foo = obj.foo)() // window
// 情况二
(false || obj.foo)() // window
// 情况三
(1, obj.foo)() // window
很难理解吧,上面代码中,obj.foo就是一个值。这个值真正调用的时候,运行环境已经不是obj了,而是全局环境,所以this不再指向obj。
可以这样理解,JavaScript 引擎内部,obj和obj.foo储存在两个内存地址,称为地址一和地址二。
obj.foo()这样调用时,是从地址一调用地址二,因此地址二的运行环境是地址一,this指向obj。
但是,上面三种情况,都是直接取出地址二进行调用,这样的话,运行环境就是全局环境,因此this指向全局环境。上面三种情况等同于下面的代码
// 情况一
(obj.foo = function () {
console.log(this);
})()
// 等同于
(function () {
console.log(this);
})()
// 情况二
(false || function () {
console.log(this);
})()
// 情况三
(1, function () {
console.log(this);
})()
不能被继承指的是
var a = {
p: 'Hello',
b: {
m: function() {
console.log(this.p);
}
}
};
a.b.m() // undefined
箭头函数中的this
箭头函数中的this指向它所在的执行上下文的this
function person() {
setTimeout(() => {
console.log(this);
}, 1000)
}
const Person = new person(); // Person
let a = () => {
console.log(this); // window
}
call apply bind改变this指向
call apply bind的区别
- call apply绑定this之后会立刻执行,bind返回绑定后的函数
- call的参数是一个一个的参数,apply是一个数组,bind的参数也是一个数组
实现一个call
Function.prototype.call = (ctx, ...args) => {
const context = ctx || window;
let symbol = Symbol();
context[symbol] = this;
let res = context[symbol](args);
delete context[symbol];
return res
}
实现一个apply
Function.prototype.apply = (ctx, ...args) {
const context = ctx || window;
let symbol = Symbol();
context[symbol] = this;
let res = context[symbol](args);
delete context[symbol];
return res
}
实现一个bind
Function.prototype.bind = (context, ...args) => {
const ctx = context || window;
const fn = this;
return function() {
return fn.apply(ctx, args);
}
}