javascript中的this继续聊
栏目: JavaScript · 发布时间: 5年前
内容简介:这是javascript作用域系列文章,感兴趣的同学请保持关注。上回说到,函数的调用方式分四种情况:
这是javascript作用域系列文章,感兴趣的同学请保持关注。
上次回顾
目录
上回说到,函数的调用方式分四种情况:
- 作为一个函数进行的调用
- 作为一个对象的方法进行的调用
- 作为构造器进行的调用
- 通过apply()、call()函数进行的调用
上次说了前两种情况,其实(1)是(2)的一种特殊情况,
即当作为一个函数调用的时候,就是作为window对象的一个方法进行调用
一个小栗子进行简单回顾
var heroName = "郭靖"; function hero1() { console.log(this.heroName); } var HERO1 = { heroName: "黄蓉", hero1:hero1 }; HERO1.hero1();//=>黄蓉 hero1();//=>郭靖
都是执行hero1()方法,同样都是输出this.heroName,却得到了不同的结果
this的指向是在函数执行的时候定义的,而不是在函数创建时定义的
基于上面的栗子,我们再看一个栗子
var heroObj = { heroName: "郭靖", heroFoo: { heroName: "黄蓉", hero: function() { console.log(this.heroName); } } }; heroObj.heroFoo.hero();//=>黄蓉 var h = heroObj.heroFoo.hero; h();//=>郭靖
为了直观表达我们做一下改动
//部分代码省略 window.heroObj.heroFoo.hero();//=>黄蓉 var h = heroObj.heroFoo.hero; window.h();//=>郭靖
输出的结果是相同的,我要表达的内容也很就很直观明显了,
这些对象和方法,最终都会挂载到window对象下,我们看这一句
window.heroObj.heroFoo.hero();//=>黄蓉
hero()中的this是指向调用它的对象,那是哪个对象调用的hero()呢?
这是个问题
这是个问题?
这不是个问题
this指向的是最后调用它的对象
上面的栗子
window.heroObj.heroFoo.hero();//=>黄蓉
最后调用hero()的是heroFoo,所以hero()中this指向了heroFoo对象
var h = heroObj.heroFoo.hero; window.h();//=>郭靖
最后调用h()的是window对象,所以hero()中this指向了window对象
综上
this的指向是在函数执行的时候定义的,而不是在函数创建时定义的,this指向的是最后调用它的对象
this继续聊
下面讨论剩下的两种情况
函数作为构造器进行调用
之前在介绍面向对象的时候, 谈一谈javascript面向对象 ,讨论过,使用构造函数来创建对象
function Hero(name, nickname, skill) { this.name = name; this.nickname = nickname; this.doSth = function() { return skill }; } const hero = new Hero("黄药师", "东邪", "碧海潮生曲"); console.log(hero);
我们还说到,使用自定义构造器构造一个对象需要四步
- 创建一个新对象
const hero = new Hero("黄药师", "东邪", "碧海潮生曲");
- 将构造函数的作用域赋给新对象,设置原型链(因此this就指向了这个新对象hero)
hero.__proto__=Hero.prototype;
- 执行构造函数Hero中的代码(为这个新对象hero添加属性和方法)
- 返回新对象hero
说this指向hero,Hero内所有针对this的操作,都会发生在hero上面
console.log(hero.name);//=>黄药师 console.log(hero.nickname);//=>东邪 console.log(hero.doSth());//=>碧海潮生曲
构造函数是不需要return的,
return在普通函数中也不是必须存在的,我们知道,在普通函数中,如果没有手动return ,会默认return undefined
但是如果在构造函数中使用了return,会存在一些坑
我们一起来填坑
我们把上面的栗子进行简化
function Hero(name) { this.heroName = name; return 123 } const hero = new Hero("郭靖"); console.log(hero.heroName);//=>郭靖
function Hero(name) { this.heroName = name; return null } const hero = new Hero("郭靖"); console.log(hero.heroName);//=>郭靖
function Hero(name) { this.heroName = name; return undefined } const hero = new Hero("郭靖"); console.log(hero.heroName);//=>郭靖
不再进行一一列举,上面return的都是基本数据类型
继续看
数组类型
function Hero(name) { this.heroName = name; return [] } const hero = new Hero("郭靖"); console.log(hero.heroName);//=>undefined
object类型
function Hero(name) { this.heroName = name; return { heroName: "黄蓉" }; } const hero = new Hero("郭靖"); console.log(hero.heroName);//=>黄蓉
funciton类型
function Hero(name) { this.heroName = name; return function(){} } const hero = new Hero("郭靖"); console.log(hero.heroName);//=>undefined
funciton升级
function Hero(name) { this.heroName = name; return (function() { return {heroName:''} })() } const hero = new Hero("郭靖"); console.log(hero.heroName);//=>黄蓉
总结一下
构造函数会改版this的指向,指向通过new实例化出来的对象
构造函数中不需要return,当存在return时,一下几点需要注意
- 当return的是基本数据类型时,返回不变
- 当return的没有返回时,默认返回undefined,返回不变
- 当return的是引用类型时,返回的是这引用类型
函数通过apply()、call()进行调用
之前在讲面向对象的时候,对call进行过讨论, javascript 面向对象之一篇文章搞定call()方法
它们两个也是用来改变this的指向的,
为什么要改变this的指向呢?
看一个栗子
const hero1 = { name: "欧阳锋", doSth: function (skill) { console.log(`${this.name}学习${skill}`); } }; const hero2 = { name: "洪七公" }; hero1.doSth('九阴真经')//=>欧阳锋学习九阴真经
执行了hero1对象下面的doSth方法,并传入参数“九阴真经”,最后输出=>欧阳锋学习九阴真经
结合上面的介绍讲解,我们知道,doSth中的this是指向的hero1,这个没问题吧
好了,现在hero2下面有一个“洪七公”,“洪七公”也想调用hero1下面的doSth方法,怎么办呢?
const hero1 = { name: "欧阳锋", doSth: function (skill) { console.log(`${this.name}学习${skill}`); } }; const hero2 = { name: "洪七公" }; hero1.doSth.call(hero2, "降龙十八掌");//=>洪七公学习降龙十八掌
doSth是由hero1调用的,默认情况下doSth中的this指向的是hero1,但是使用了call,所以,this的指向变了,指向了call方法中的第一个参数hero2,
apply呢?apply和call很是类似
const hero1 = { name: "欧阳锋", doSth: function(skill, favourite) { console.log(`${this.name}学习${skill}`); console.log(`${this.name}喜欢${favourite}`); } }; const hero2 = { name: "洪七公" }; hero1.doSth.apply(hero2, ["降龙十八掌", "吃鸡"]); hero1.doSth.call(hero2, "降龙十八掌", "吃鸡");
这两种写法等效,只是传入的参数格式略有不同
hero1.doSth.apply(hero2, ["降龙十八掌", "吃鸡"]); hero1.doSth.call(hero2, "降龙十八掌", "吃鸡");
补充bind
bind也可以改变this的指向,在用法上和call和apply略有不同,bind的使用更加灵活
const hero1 = { name: "欧阳锋", doSth: function(skill, favourite) { console.log(`${this.name}学习${skill}`); console.log(`${this.name}喜欢${favourite}`); } }; const hero2 = { name: "洪七公" }; const foo = hero1.doSth.bind(hero2, "降龙十八掌", "吃鸡"); foo();
之前说的call和apply都是立即执行,而bind不会立即执行,需要手动执行,所以bind的使用更加灵活
不止于此
上面的foo方法在调用的时候可以额外的传入参数
const hero1 = { name: "欧阳锋", doSth: function(skill, favourite, q, n, b) { console.log(`${this.name}学习${skill}`);//=>洪七公学习降龙十八掌 console.log(`${this.name}喜欢${favourite}`);//=>洪七公喜欢吃鸡 console.log(q, n, b);//=>1 2 3 } }; const hero2 = { name: "洪七公" }; const foo = hero1.doSth.bind(hero2, "降龙十八掌", "吃鸡"); foo(1, 2, 3);
今天的主要内容就是在函数的调用中,this的指向会被改变,我们要留意里面的坑,
当然我们也可以通过一些手段改变this的指向。
END
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。