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中的属性 1fire: function () {console.log(this.a)}}var a = 2; // a是定义在全局环境中的变量 2var fireInGrobal = obj.fire;obj.fire();//这里打印-----1fireInGrobal();//你以为是打印的是什么呢??? 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(); // 输出2fireInGrobal.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默认绑定,指向全局windowwindow.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在全局调用打印小红
结果:
小红
小红
小黄
小红
小红
