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
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Music Recommendation and Discovery
Òscar Celma / Springer / 2010-9-7 / USD 49.95
With so much more music available these days, traditional ways of finding music have diminished. Today radio shows are often programmed by large corporations that create playlists drawn from a limited......一起来看看 《Music Recommendation and Discovery》 这本书的介绍吧!