你不知道的JS读书笔记2—this对象
来源:互联网 发布:淘宝会员等级表 编辑:程序博客网 时间:2024/05/22 08:11
本文是在《你不知道的JS》上阅读了其他的资料之后整理的。
this是很重要的一个对象,它不指向它本身不指向它的作用域,它指向函数调用所处的位置。需要分析函数的调用栈,调用位置就是调用栈中当前函数的上一个函数。
比如如下代码:
function foo(){ console.log(this.a);}var a = 2;var obj = { a : 1, foo: foo}obj.foo(); // 1 调用栈为 obj->foo,所以this指向objvar bar = obj.foo;foo(); // 2 foo在全局作用域下被调用,所以this指向全局作用域bar(); // 2 bar其实就是foo,所以调用栈就是foo,this指向全局作用域
首先函数的调用方式大致分为普通函数调用,作为对象方法调用,call/apply调用,new构造器调用。我们分别来说这几种情况下this的指向问题,以及几种调用情况共存时候的优先级。
new绑定
new一个对象的具体过程如下:
1. 新创建一个对象;
2. 建立这个对象与原型链的联系;
3. 将这个新对象绑定this;
4. 如果没有返回的对象,就自动返回this。
所以用new创建出来的函数,this都指向这个新建的实例。
function foo(){ this.a = 2; this.hello = function(){ console.log(this.a); } } var bar = new foo(); bar.hello(); // 2
正常情况下,foo函数中的this指向全局作用域,但是new的操作强行将新创建的bar对象绑定this。new绑定的优先级是最高的。
显示绑定
直接用apply或者call的方式强行指定this对象。
function foo(){ console.log(this.a);}var a = 2;var obj = { a : 1};var obj2 = { a : 10};foo.call( obj ); // 1 强制将this指向obj对象foo.call( obj2 ); // 10 强制将this指向obj2对象foo(); //2
这里仍然有个问题,foo的this可以被改变的。下面这种硬绑定的方法可以在一般情况下,foo的this固定。
function foo(){ console.log(this.a);}var obj = { a : 1};var obj1 = { a : 10};function bar(){ return foo.apply(obj, arguments) ;}bar(); // 1bar.apply(obj1); // 1 this仍然指向obj,未改变
ES5中封装了bind函数,去实现上述的功能。简单的实现版本如下
Function.prototype.bind = function(context){ var self = this; return function(){ return self.apply(context, arguments); } }
另外,在原生JS中,有些接口本来就能做this的设置,比如forEach, map, every, some, map, filter等。显示绑定的优先级仅次于new绑定。
隐式绑定
当函数作为对象的方法被调用时,this指向这个调用的对象。没什么特别之处,按照调用栈来看就好。优先级次之。需要注意的是,当多个属性嵌套时,使用最近原则。
function foo(){ console.log(this.a);}var a = 2;var obj = { a : 1, foo: foo, obj2: obj2}var obj2 = { a : 2, foo: foo}obj.obj2.foo(); // 2 调用栈为 obj->obj2->foo,所以this指向obj2
默认绑定
就是普通函数的调用。需要说明的是,在非严格模式下,this指向全局对象window,而严格模式下,this指向undefined。优先级最低。如果绑定null或者undefined,应用的是默认绑定规则。
箭头函数
我们先来看个例子。
var point = { x : 0, y : 0, moveTo : function(x, y) { // 内部函数 var moveX = function(x) { this.x = x;//this 绑定到了哪里? }; // 内部函数 var moveY = function(y) { this.y = y;//this 绑定到了哪里? }; moveX(x); moveY(y); }};point.moveTo(1, 1);point.x; //==>0point.y; //==>0x; //==>1y; //==>1
这个例子看起来不是上面四个规则中的任何一个。 point.moveTo是以对象属性方法的方式调用的,当moveTo函数内部this应该指向point对象。当它并没有直接在moveTo函数内部直接调用this,而是在内部又定义了两个函数变量moveX,moveY,将两个匿名函数赋值给它们。那匿名函数内部的this应该指向point.moveTo? ………..(此时省略N个字,具体的原因谁能说说) 总之,this的绑定对象莫名其妙地绑定了全局变量。
为了避免这种情况的发生,一般经典的做法为:
var point = { x : 0, y : 0, moveTo : function(x, y) { var that = this; // 内部函数 var moveX = function(x) { that.x = x; }; // 内部函数 var moveY = function(y) { that.y = y; } moveX(x); moveY(y); }};point.moveTo(1, 1);point.x; //==>1point.y; //==>1
另外,ES6出来了一个箭头函数,不仅是形式上的简化,它还严格符合词法作用域。可以替换平时写代码时加的var that = this
。
var point = { x : 0, y : 0, moveTo : function(x, y) { // 内部函数 var moveX = x => {this.x = x;}; // 内部函数 var moveY = y => {this.y = y;}; moveX(x); moveY(y); }};point.moveTo(1, 1);point.x; //==>1point.y; //==>1
参考资料:
https://github.com/getify/You-Dont-Know-JS 你不知道的JS
http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html JavaScript的this用法
https://www.ibm.com/developerworks/cn/web/1207_wangqf_jsthis/ 深入浅出 JavaScript 中的 this
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this MDN this
- 你不知道的JS读书笔记2—this对象
- 你不知道的JS-读书笔记(三)--this和对象原型
- 你不知道的JS读书笔记3—对象与类
- 你不知道的JS读书笔记5—原型继承
- 你不知道的JS-读书笔记(四)--混合对象类
- 你不知道的JS-读书笔记(一)--作用域
- 你不知道的JS-读书笔记(五)--原型[Prototype]
- this和对象——源自《你所不知道的JavaScript》
- 你不知道的JS读书笔记1—闭包&作用域
- 你不知道的JS读书笔记4—原型与原型链
- [图解] 你不知道的 JavaScript - “this”
- [图解] 你不知道的 JavaScript - “this”
- 【图解】你不知道的 javascript “this”
- javascript你不知道的This
- 《你不知道的javascript(上卷)》——读书笔记
- 《你不知道的JavaScript(上卷)》读书笔记
- 读书笔记-你不知道的JavaScript(上)
- 《你不知道的JavaScript》读书笔记一
- mac上搭建php工作环境
- Redis内部原理
- cocoapods安装第三方库
- OOP面向对象三大特点
- row_number() OVER(PARTITION BY)函数介绍
- 你不知道的JS读书笔记2—this对象
- 插入排序
- 百度webuploader点击反应太慢解决方案
- SQL2012不允许保存更改的解决办法
- 玩转Android上透明状态栏,全屏显示以及沉浸模式(Immersive Mode)
- java 笔记 this关键字与构造函数
- C#设计模式--原型模式
- Docker学习总结(1)——Docker实战之入门以及Dockerfile(一)
- jvm基础-内存管理