this的定义
函数一旦创建就有this属性
this指向本身
this指向实际调用的对象
译为“这”
this的绑定方法
①默认绑定
当一个函数没有明确的调用对象的时候,也就是单纯作为独立函数调用的时候,将对函数的this使用默认绑定:绑定到全局的window对象
例子
function girl(){
console.log(this);
}
//全局调用
girl();//widows对象
例子
function fire () {
// 我是被定义在函数内部的函数哦!
function innerFire() {
console.log(this === window)
}
innerFire(); // 独立函数调用
}
fire(); // 输出true
谨记:
- 一个函数没有明确的调用对象,默认绑定
- 凡是函数作为独立函数调用,无论它的位置在哪里,它的行为表现,都和直接在全局环境中调用无异
②隐式绑定
当函数被一个对象“包含”的时候,我们称函数的this被隐式绑定到这个对象里面了,这时候,通过this可以直接访问所绑定的对象里面的其他属性,比如下面的name属性
例子:
//第一种函数在对象内部
var name = "小红"
var girl = {
name:"小米",
detail:function()
{
console.log("姓名:"+this.name);
}
}
girl.detail();//姓名:小米
//第二种函数在对象外部
var name = "小红"
function detail()
{
console.log("姓名:"+this.name);
}
var girl = {
name:"小米",
detail:detail
}
girl.detail();//姓名:小米
谨记:
1. this是动态绑定的,或者说是在代码运行期绑定而不是在书写期
2. 函数于对象的独立性, this的传递丢失问题
**
- 隐式绑定下,作为对象属性的函数,对于对象来说是独立的
解释:
在上文中,函数虽然被定义在对象的内部中,但它和“在对象外部声明函数,然后在对象内部通过属性名称的方式取得函数的引用”,这两种方式在性质上是等价的(而不仅仅是效果上)
定义在对象内部的函数只是“恰好可以被这个对象调用”而已,而不是“生来就是为这个对象所调用的”
(这点在隐式绑定this丢失问题中可说明)
- 在一串对象属性链中,this绑定的是最内层的对象
例子:
var obj = {
a: 1,
obj2: {
a: 2,
obj3: {
a:3,
getA: function () {
console.log(this.a)
}
}
}
}
obj.obj2.obj3.getA(); // 输出3
隐式绑定this丢失问题
例子:
var obj = {
a: 1, // a是定义在对象obj中的属性 1
fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量 2
var fireInGrobal = obj.fire;
obj.fire();
//这里打印-----1
fireInGrobal();
//你以为是打印的是什么呢??? 1吗?
//不不不,打印的是 2
上面这段简单代码的有趣之处在于:
obj.fire()与fireInGrobal()打印结果不一样, 这个于obj中的fire函数的引用( fireInGrobal)在调用的时候,行为表现(输出)完全看不出来它就是在obj内部定义的,不会指向obj对象,其原因在于:这个函数赋值的过程无法把fire所绑定的this也传递过去。我们隐式绑定的this丢失了!! 从而 fireInGrobal调用的时候取得的this不是obj,而是window
③硬绑定/显式绑定
基于上面隐式绑定this丢失的问题,在这是我们想this指向不丢失,可以使用下面的方法
call/apply
- call的基本使用方式: fn.call(object)
fn是你调用的函数,object参数是你希望函数的this所绑定的对象。
- fn.call(object)的作用:
1.即刻调用这个函数(fn)
2.调用这个函数的时候函数的this指向object对象
- apply与call使用很像,细微差别自行了解
例子:
var obj = {
a: 1, // a是定义在对象obj中的属性
fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量
var fireInGrobal = obj.fire;
fireInGrobal(); // 输出2
fireInGrobal.call(obj); // 输出1
但是,我们其实不太喜欢这种每次调用都要依赖call的方式,我们更希望:能够一次性 返回一个this被永久绑定到obj的fireInGrobal函数,这样我们就不必每次调用fireInGrobal都要在尾巴上加上call那么麻烦了。
var obj = {
a: 1, // a是定义在对象obj中的属性
fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量
var fn = obj.fire;
var fireInGrobal = function () {
fn.call(obj) //硬绑定
}
fireInGrobal(); // 输出1
bind
call和bind的区别是:
在绑定this到对象参数的同时:
1.call将立即执行该函数
2.bind不执行函数,只返回一个可供执行的函数
例子:**
var obj = {
a: 1, // a是定义在对象obj中的属性
fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量
var fn = obj.fire;
var fireInGrobal = fn.bind(obj);
fireInGrobal(); // 输出1
在隐式绑定下:函数和只是暂时住在“包含对象“的旅馆里面,可能过几天就又到另一家旅馆住了
在显式绑定下:函数将取得在“包含对象“里的永久居住权,一直都会”住在这里“
④构造函数绑定
执行new操作的时候,将创建一个新的对象,并且将构造函数的this指向所创建的新对象
例子:
function Lover(name) {
this.name = name;
this.sayName = function () {
console.log("我的老婆是" + this.name);
};
}
var name = "小白";
var xiaoHong = new Lover("小红");
xiaoHong.sayName();//我的老婆是小红
测验
例1
题目:
function a() {
function b() {
console.log(this);
function c() {
"use strict";
console.log(this);
}
c();
}
b();
}
a();
分析:
function a() {
function b() {
console.log(this);//默认绑定
function c() {
"use strict";//严格模式
console.log(this);//this 变为 undefined
}
c();
}
b();
}
a();
例2
题目:
var name = "小白";
function special() {
console.log("姓名:" + this.name);
}
var girl = {
name: "小红",
detail: function () {
console.log("姓名:" + this.name);
},
woman: {
name: "小黄",
detail: function () {
console.log("姓名:" + this.name);
},
},
special: special,
};
girl.detail();
girl.woman.detail();
girl.special();
分析:
girl.detail();
执行girl对象下面的detail方法,即this隐式绑定,指向该方法的对象
得出:小红
girl.woman.detail();
执行woman对象下面的detail方法,即this隐式绑定,指向该方法的对象
得出:小黄
girl.special();
指向special属性,属性值指向special函数,已在全局声明
虽然special函数里面的this是隐式绑定
但是this指向实际调用该方法的对象,即为girl对象
例3
题目:
var name = "小红";
function a() {
var name = "小白";
console.log(this.name);
}
function d(i) {
return i();
}
var b = {
name: "小黄",
detail: function () {
console.log(this.name);
},
bibi: function () {
return function () {
console.log(this.name);
};
},
};
var c = b.detail;
b.a = a;
var e = b.bibi();
a();
c();
b.a();
d(b.detail);
e();
分析:
a();
全局调用a函数,a中的this默认绑定,指向全局window
window.name=“小红”
c();
函数c是变量名,由对象b中的detail方法赋值,detail方法是一个函数
(错误想法:执行b对象下detail方法,即隐式绑定,this指向方法的对象——b)----隐式绑定this丢失
相当于普通函数赋值给c,函数产生动作console.log(this.name),赋值给c,与b无关
也就是说c函数产生动作console.log(this.name)
c是在全局调用,打印小红
b.a();
先看b里面没有a方法,但仔细观察b.a = a;
意思是给b定义了a属性,再a赋值,给b对象一个a方法
b.a()就相当于调用b对象的a方法,this指向调用函数的对象b,打印小黄
d(b.detail);
b.detail作为d的参数,detail方法给了d,d在全局调用
打印小红
e();
b里面的bibi是一个闭包(自学闭包,很重要!)
e=b.bibi 与 e=b.bibi() 不一样
e=b.bibi() 相当于bibi()方法赋给了e,e在全局调用
打印小红
结果:
小红
小红
小黄
小红
小红