this默认指向方法所属的对象,当然你可以任意指定一个函数的this。
this所属的对象,其实就是这个方法所处的一个上下文环境。怎么理解上下文这个东西,举个例子,你去自助餐厅吃饭,当你发生吃饭这个动作时,这个自助餐厅就赋予你一个上下文环境,你想吃什么,只要这里有,你就能随便吃,上下文环境为你提供一个拿来即用的环境,这个环境在js中通常就是一个对象。
//举例,想想以下问题:
function foo(a,b){
this.a = a;
this.b = b;
}
想想当执行foo函数时,this代表了谁。
如果只在script标签内书写了这么一段代码,我们知道foo是属于window对象的,那这里的this指的当然就是windows对象;当你执行foo(1,2)时你会发现window对象对了a、b两个属性。
这里的this就是foo所属的对象obj ,当foo执行后,给obj添加了两个属性。此时obj就是你的上下文,他可以任意获取obj内的任意元素。
//再如:
var obj = {
foo: function(a, b) {
this.a = a;
this.b = b;
},
num: 3
}
obj.foo(2, 3);
console.log(obj);
//你会发现输出:
{ foo: [Function: foo], num: 3, a: 2, b: 3 }
这里的this就是foo所属的对象obj ,当foo执行后,给obj添加了两个属性。此时obj就是你的上下文,他可以任意获取obj内的任意元素。
甚至我们可以这样写:
function foo() {}
foo.bar = function(a, b) {
this.a = a;
this.b = b;
}
foo.bar(2, 3)
console.log(foo);
//输出结果:
{ [Function: foo] bar: [Function], a: 2, b: 3 }
//我们发现foo多了两个属性
我们还可以这样使用
所以方法所在的对象,就是它的上下文,他能提取这个所在对象的任意元素,也就是this的指向。
var fnArr = [];
fnArr.push(function() {
this.push(3);
this.push(4);
})
fnArr[0]();
console.log(fnArr)
//输出结果:
[ [Function], 3, 4 ]
//我们发现数组多了两个元素,此时整个数组就是他的上下文环境,他可以通过this任意获取数组里边的元素,或者操作这个数组。
所以方法所在的对象,就是它的上下文,他能提取这个所在对象的任意元素,或者操作这个对象,这个对象就是this的指向。重要的事情说三遍。
到这里,可能有些人会提出使用new 关键字时的this指向问题。
function Foo(a,b){
this.a = a;
this.b = b;
}
如果你不去new 这个实例,此时的this就指代window对象,应为在非严格模式下的浏览器环境下这个函数理所当然属于window,他当然可以从window这个上下文随意获取元素,这个问题,我们之前已经探讨过了。
你可以这样写代码:
function a(){ this.alert(1)}
当然没人会这么写,应为此时的this或者Window是可以省略的,但是你不能否认即使是最简单的alert方法也是你从上下文中获取的。
回到之前的;
如果直接执行这个类(其实就是个函数)
var foo = Foo(2,3); 此时的foo是undefined,应为函数压根没有返回值,而window却多了两个属性。
我们通常这样去new一个实例:
var foo = new Foo(2,3);
先看看new干了什么,我们模拟一个mynew方法:
function A(a, b) {
this.a = a;
this.b = b;
}
function myNew(fn, ...args) {
let obj = {};
obj.__proto__ = fn.prototype;
fn.call(obj, ...args);
return obj;
}
let a = myNew(A, 2, 3);
此时的a对象和new出来的a对象是一样的。new一个对象时,首先构造了一个空对象,再将对象的__proto__指向函数(类就是个函数)的原型,最后执行函数再将this绑定在obj上,这样就形成了一个函数的实例。
说到这里我们就引出了任意绑定this的概念。
举个例子:
你家的孩子要搭积木,你这里有好多包积木玩具,你一般会拿一包给他,当然你也能拿任意多包给他,此时放在他面前的积木就是他搭积木这个动作的上下文,他想拿方块拿方块,想拿三角拿三角。这个上下文就是你赋予他的,可以是任意品牌的积木。
反映在js中,我们可以指定任意新的对象作为this的指向,而此时需要使用bind,call,apply三个方法;
bind用于绑定一个this:、
当此函数执行时,this就是bind函数的参数,如 foo.bind({a:1,b:2}),之后foo执行的时候this就是{a:1,b:2},bind内的参数可以使任意的对象,当然它可以是一个变量。
call和apply会直接绑定this并执行:
call(this对象,参数一,参数二,…) apply(this新对象,[参数一,参数二]),这两个方法第一个都是新的this对象,从第二个参数开始,call以多个参数形式传参,apply以数组形式传参,区别仅此而已。