关于this的指向问题:
this是JavaScript中的一个关键字,但是又一个相对比较特别的关键字,不像function、var、for、if这些关键字一样,可以很清楚的搞清楚它到底是如何使用的。
this会在执行上下文中绑定一个对象,但是是根据什么条件绑定的呢?在不同的执行条件下会绑定不同的对象,这也是让人捉摸不定的地方。
简单举个例子:
var obj = {
name: "why",
running: function() {
console.log(this.name + " running");
},
eating: function() {
console.log(this.name + " eating");
},
studying: function() {
console.log(this.name + " studying");
}
}
当我们通过obj去调用running、eating、studying这些方法时,this就是指向的obj对象
一般的在全局作用域下,this是指向window
二般的在函数中的使用:
所有的函数在被调用时,都会创建一个执行上下文:这个上下文记录了函数的调用栈、调用的方式、参数信息等,其中this就是一个属性。
一起来看一个问题:给定一个函数,通过不同的方式调用,this竟然是不一样的,
// 定义一个函数
function foo() {
console.log(this);
}
// 1.调用方式一: 直接调用
foo(); // window
// 2.调用方式二: 将foo放到一个对象中,再调用
var obj = {
name: "why",
foo: foo
}
obj.foo() // obj对象
// 3.调用方式三: 通过call/apply调用
foo.call("abc"); // String {"abc"}对象
可以得到这些信息:
1.函数在调用时,JavaScript会默认给this绑定一个值;
2.this的绑定和定义的位置(编写的位置)没有关系;
3.this的绑定和调用方式以及调用的位置有关系;
4.this是在运行时被绑定的;
那么this的绑定规则是什么呢???
- 默认绑定:
所谓的默认绑定就可以认为是独立函数调用,独立的函数调用我们可以理解成函数没有被绑定到某个对象上进行调用;
举一些小例子:
1、普通函数调用
该函数直接被调用,并没有进行任何的对象关联;
这种独立的函数调用会使用默认绑定,通常默认绑定时,函数中的this指向全局对象(window);
function foo() {
console.log(this); // window
}
foo();
2、函数调用链(一个函数又调用另外一个函数)所有的函数调用都没有被绑定到某个对象上;
// 2.案例二:
function test1() {
console.log(this); // window
test2();
}
function test2() {
console.log(this); // window
test3()
}
function test3() {
console.log(this); // window
}
test1();
3、将函数作为参数,传入到另一个函数中
function foo(func) {
func()
}
function bar() {
console.log(this); // window
}
foo(bar);
这里的结果都是window,为什么呢?
原因非常简单,在真正函数调用的位置,并没有进行任何的对象绑定,只是一个独立函数的调用;
- 隐式绑定:
另外一种比较常见的调用方式是通过某个对象进行调用的,也就是它的调用位置中,是通过某个对象发起的函数调用。
隐式绑定有一个前提条件:
必须在调用的对象内部有一个对函数的引用(比如一个属性);
如果没有这样的引用,在进行调用时,会报找不到该函数的错误;
正是通过这个引用,间接的将this绑定到了这个对象上;
案例:通过对象调用函数
foo的调用位置是obj.foo()方式进行调用的,那么foo调用时this会隐式的被绑定到obj对象上
function foo() {
console.log(this); // obj对象
}
var obj = {
name: "why",
foo: foo
}
obj.foo();
- 显示绑定:
JavaScript所有的函数都可以使用call和apply方法(这个和Prototype有关),
二者区别其实非常简单,第一个参数是相同的,后面的参数,apply为数组,call为参数列表;
这两个函数的第一个参数都要求是一个对象,这个对象的作用是什么呢?就是给this准备的。
在调用这个函数时,会将this绑定到这个传入的对象上。
通过call或者apply绑定this对象:
显示绑定后,this就会明确的指向绑定的对象。
function foo() {
console.log(this);
}
foo.call(window); // window
foo.call({name: "why"}); // {name: "why"}
foo.call(123); // Number对象,存放时123
如果我们希望一个函数总是显示的绑定到一个对象上,可以怎么做呢?
=====>bind()函数
两种方式:
1.写一个辅助函数:
这个辅助函数的目的是在执行foo时,总是让它的this绑定到obj对象上
function foo() {
console.log(this);
}
var obj = {
name: "why"
}
function bind(func, obj) {
return function() {
return func.apply(obj, arguments);
}
}
var bar = bind(foo, obj);
bar(); // obj对象
bar(); // obj对象
bar(); // obj对象
2.使用Function.prototype.bind
function foo() {
console.log(this);
}
var obj = {
name: "why"
}
var bar = foo.bind(obj);
bar(); // obj对象
bar(); // obj对象
bar(); // obj对象
- new绑定:
当在js中new一下都做了什么???
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) ;
(3) 执行构造函数中的代码(为这个新对象添加属性) ;
(4) 返回新对象
显示高于隐式,new高于隐式,但是new高于bind,new不能和call()和apply()一起用。
本篇文章仅用于学习记录,参考和摘文于王老师公众号。

被折叠的 条评论
为什么被折叠?



