对JavaScript中this指针的新理解分享


Posted in Javascript onJanuary 31, 2015

一直以来对this的理解只在可以用,会用,却没有去深究其本质。这次,借着《JavaScript The Good Parts》,作了一次深刻的理解。(所有调试都可以在控制台中看到,浏览器F12键)

下面我们一起来看看这个this吧。

在我们声明一个函数时,每个函数除了有定义时的parameters(形参),自身还会有额外的两个参数,一个是this,一个是arguments(实参)。arguments就是函数实际接受到的参数,是一个类数组。arguments我只做个简略的介绍,重点我们放在this指针上。

在面向对象变成中,this十分重要,它的值取决于调用的模式。而在JavaScript中,一共有4中调用模式:方法调用模式、函数调用模式、构造函数调用模式、apply调用模式。

方法调用模式

当一个函数是作为一个对象的属性时,我们通常称这个函数是这个对象的一个方法。当这个方法被调用时,this就会指向该方法所属对象。

<script type="text/javascript">

    var people = {

        name : "Yika",

        sayName : function(){

            console.log(this.name);   //"Yika"

                        //this已经绑定在了people对象上了

        }

    }

    people.sayName();

</script>

如栗子所示,this指向了sayName对象,这种通过this取得所属对象上下文的方法,就是公共方法。(publice method)

函数调用模式

当一个函数被调用时并非某个对象上的方法,那么它就是作为一个函数被调用的。

这种模式调用,this会指向window对象,即使这个函数或许是在外部函数里调用的,我们来看栗子。

<script type="text/javascript">

    var name = "window-Yika";

    var people = {

        name : "people-Yika",

        student : function(){

            console.log(this);   //这里的this绑定的是对象people

            function sayName(){

                var name = "sayName-Yika";

                console.log(this.name); //window-Yika




//即使sayName函数本身和它所在的people对象都有name值,但是this是指向window的

            };

            sayName();

        }

    }

    people.student();

</script>

这样一看,是不是大概知道该怎么解决JavaScript这个“设计错误"了呢。

是的只要在student函数里面,也就是第6行,将this缓存起来。然后再将this通过变量转移到sayName函数里就可以解决啦!

var people = {

        name : "people-Yika",

        student : function(){

            var self = this; //将this缓存起来

            function sayName(){

                var name = "sayName-Yika";

                console.log(self.name);  //"people-Yika",此时的self指向的是people对象

            };

            sayName();

        }

    }

构造函数调用模式

JavaScript里一讲到构造函数,脑海里就会有:“函数名大写!调用的时候要用new操作符!” 函数名大写好理解,是为了规范统一构造函数的命名。可是你有没有深究过为什么要用new呢?如果在一个函数前面带上new来调用,那么函数后台会创建一个指向该函数prototype的新对象,同时this也绑定在新对象上。JavaScript是一门基于原型继承的语言,对原型prototype不是很清楚的同学可以自己去查一下资料,我重点放在this上面。

我们先来看看构造函数一般长什么样子。

<script type="text/javascript">

    function People(name){

        this.name = name;    //这里的this,用new调用后便指向了新对象Yika



 this.sayName = function(){

        
console.log(this.name);  //输出

    
}

    }

var Yika = new People("Yika");  

   Yika.sayName();  //输出“Yika" ,因为Yika是通过new调用得来的,this都绑定在了Yika对象上。

</script>

乍一看,好像不是好懂,怎么刚才在函数里的this是指向window,现在不用缓存就可以指向People函数呢?

没关系,刚才不是说函数通过new调用,会在背地里自己做“做坏事”么,我们一起看看到底做了哪些事。

<script type="text/javascript">

    function People(name){

        var that = {};   //坏事一:自己生成一个对象

        that.name = name;

        that.sayName = function(){

            console.log(that.name);

        };

        return that;    //坏事二,自己会改变return的行为,return刚生成的对象

    }

    var Yika = People("Yika"); //这里可以省略new,模仿调用new操作符

    Yika.sayName(); //和刚才一样输出"Yika"

</script>

这样看就明白清楚了吧,new不仅会生成一个对象,而且还会自动return这个对象,这样自然this便指向了这个新对象。

千万记得要用 new 去调用构造函数,不然出了问题,是没有警告的,所有大写约定还是十分有必要的。

Apply调用模式

apply方法让我们构建一个参数数组传递给调用函数,也允许我们改变this值。

function.apply(this绑定的值, arguments参数数组)

apply可以说的东西太多了,我这里只举个的栗子来帮助大家理解:

<script type="text/javascript">

    function People(name){

        this.name = name;

        this.sayName = function(){

            console.log(this.name);   //sayName这个方法是属于People构造函数的

        }

    }

    function Student(name){

        People.apply(this, arguments);//借用构造函数的集成方式,就是在Student构造函数里,通过apply调用People构造函数,并改变People的this值

                                      //这样每次创建Student实例时,都会调用People构造函数

    }

    var student = new Student("Yika");

    student.sayName(); //输出“Yika”

</script>

我们可以通过apply轻易的修改函数的this绑定对象,和apply相似的方法call也有一样的效果,有兴趣的同学可以自己搜索学习一下。

好了,总算讲完改变this的四种调用模式了,方法调用模式和构造函数调用模式会用的更多,也会更重要一点,而函数调用模式,我们则要学会避开其中的陷阱。

若有错误,请及时反映,我会尽快纠正,以防误导他人,谢谢!

Javascript 相关文章推荐
使用jQuery.Validate进行客户端验证(初级篇) 不使用微软验证控件的理由
Jun 28 Javascript
javascript文件中引用依赖的js文件的方法
Mar 17 Javascript
BootStrap智能表单实战系列(四)表单布局介绍
Jun 13 Javascript
JS实现动态增加和删除li标签行的实例代码
Oct 16 Javascript
JS中用childNodes获取子元素换行会产生一个子元素
Dec 08 Javascript
Bootstrap源码解读按钮(5)
Dec 23 Javascript
javascript 中null和undefined区分和比较
Apr 19 Javascript
详解Angular系列之变化检测(Change Detection)
Feb 26 Javascript
使用js实现将后台传入的json数据放在前台显示
Aug 06 Javascript
Vue.js点击切换按钮改变内容的实例讲解
Aug 22 Javascript
Vue指令指令大全
Feb 09 Javascript
用Vue.js在浏览器中实现裁剪图像功能
Jun 18 Javascript
IE下支持文本框和密码框placeholder效果的JQuery插件分享
Jan 31 #Javascript
有效提高JavaScript执行效率的几点知识
Jan 31 #Javascript
JavaScript日期时间与时间戳的转换函数分享
Jan 31 #Javascript
JavaScript监听和禁用浏览器回车事件实例
Jan 31 #Javascript
JavaScript编程中容易出BUG的几点小知识
Jan 31 #Javascript
JavaScript实现的双向跨域插件分享
Jan 31 #Javascript
JavaScript判断变量是否为空的自定义函数分享
Jan 31 #Javascript
You might like
一台收音机,让一家人都笑逐颜开!
2020/08/21 无线电
Apache2 httpd.conf 中文版
2006/12/06 PHP
Json_encode防止汉字转义成unicode的方法
2016/02/25 PHP
PHP生成word文档的三种实现方式
2016/11/14 PHP
Prototype Array对象 学习
2009/07/19 Javascript
用JS写的一个TableView控件代码
2010/01/23 Javascript
jquery属性过滤选择器使用示例
2013/06/18 Javascript
jquery 漂亮的删除确认和提交无刷新删除示例
2013/11/13 Javascript
节点的插入之append()和appendTo()的用法介绍
2014/01/13 Javascript
js和jquery使按钮失效为不可用状态的方法
2014/01/26 Javascript
js取得html iframe中的元素和变量值
2014/06/30 Javascript
使用jQuery实现验证上传图片的格式与大小
2014/12/03 Javascript
JS设置网页图片vspace和hspace属性的方法
2015/04/01 Javascript
jquery实现的蓝色二级导航条效果代码
2015/08/24 Javascript
通过Tabs方法基于easyUI+bootstrap制作工作站
2016/03/28 Javascript
Vue.js 父子组件通讯开发实例
2016/09/06 Javascript
vue-resource + json-server模拟数据的方法
2017/11/02 Javascript
使用淘宝镜像cnpm安装Vue.js的图文教程
2018/05/17 Javascript
使用electron将vue-cli项目打包成exe的方法
2018/09/29 Javascript
[00:23]DOTA2群星共贺开放测试 25日无码时代来袭
2013/09/23 DOTA
[03:46]DAC趣味视频-中文考试.mp4
2017/04/02 DOTA
两个元祖T1=('a', 'b'),T2=('c', 'd')使用匿名函数将其转变成[{'a': 'c'},{'b': 'd'}]的几种方法
2019/03/05 Python
python3 小数位的四舍五入(用两种方法解决round 遇5不进)
2019/04/11 Python
Python实现堡垒机模式下远程命令执行操作示例
2019/05/09 Python
Django框架视图层URL映射与反向解析实例分析
2019/07/29 Python
晨会主持词
2014/03/17 职场文书
企业宗旨标语
2014/06/10 职场文书
咖啡店创业计划书
2014/08/15 职场文书
学校党委副书记个人对照检查材料思想汇报
2014/09/28 职场文书
2016国庆节67周年红领巾广播稿
2015/12/18 职场文书
大学生学习十八届五中全会精神心得体会
2016/01/05 职场文书
《好妈妈胜过好老师》:每个孩子的优秀都是有源头的
2020/01/03 职场文书
关于flex 上下文中自动 margin的问题(完整例子)
2021/05/20 HTML / CSS
MySQL如何使用使用Xtrabackup进行备份和恢复
2021/06/21 MySQL
Vue项目打包、合并及压缩优化网页响应速度
2021/07/07 Vue.js
Beekeeper Studio开源数据库管理工具比Navicat更炫酷
2022/06/21 数据库