JavaScript中的this
来源:互联网 发布:免费的sql数据库 编辑:程序博客网 时间:2024/06/16 10:44
运行环境
JavaScript代码主要有两种运行环境,一种是常用的浏览器环境,还有一种就是node环境,本文中如无特殊说明,均指浏览器环境。
this的含义
首先,this关键字总是返回一个对象。
其次,this的指向是动态的,即this的指向是可以发生变化的,this对象是在运行时基于函数的执行环境绑定的,即只有在运行的时候才能知道this的值(bind函数除外)。
this的使用场景
this的使用场景主要有以下这五个使用场景。
- 全局对象
- 构造函数
- 对象的方法
- DOM事件
- call/apply/bind
下面,我将详细阐述这五个使用场景。
其中,call/apply/bind单独作为一个单元来讲。
1. 全局对象中的this
在全局环境中使用this,无论是直接运行还是在函数内部运行,它指向的就是顶层对象window。
this === window; // true(function(){console.log(this === window)})(); // truefunction f() {console.log(this === window)}; f(); // true
通过上例,我们可以看到在浏览器上,以上三段代码均返回true。但在node中并不完全一致。
// 以下代码请在node环境中执行console.log(this === global); // false(function(){console.log(this === global)})(); // truefunction f() {console.log(this === global)}; f(); // true
在node环境下,只有在函数中,this 才会指向顶层对象 global。
2. 构造函数中的this
1.构造函数中的 this 指向实例对象。
function Person(name) { this.name = name;}Person.prototype.sayName = function() { return this.name;}var p = new Person('kylin');console.log(p.name); // kylinp.sayName(); // kylin
2.原型继承中的this
var Parent = function() { this.get = function() { return this; }}var Son = function() {}Son.prototype = new Parent();var son = new Son();son.get(); // son{}
这个例子也说明了,this 对象和调用方法的对象有关,即使在继承中也不例外。
3. 对象方法中的this
1.直接使用对象调用对象中的方法,其方法中的 this 指向该对象。
var person = { name: 'kylin', getName: function() { return this.name; }}person.getName(); // kylin
2.需要注意的是,当A对象的方法被赋值给了B对象时,方法中的 this 指向就从A对象变成了B对象。
var personA = { name: 'kylin', getName: function() { return this.name; }}var personB = { name: 'lover'}personB.getName = personA.getName;personB.getName(); // lover
3.如果某个方法位于多层对象的内层,这时 this 也只会指向当前这一层的对象,而不会继承更上面的层的对象。
var outerObj = { a: 'hello', b: { // a: 'world', c: function() { return this.a; } }};outerObj.b.c(); // undefined
如果将注释掉的内容恢复,就会返回 world。
4.如果将对象的方法赋值给一个变量,那么 this 指向会变成 window 对象。
var name = 'the window';var obj = { name: 'kylin', getName: function() { return this.name; }}var f = obj.getName;f(); // the window
5.方法内部定义的函数,一般而言其执行环境具有全局性,即 this 指向顶层对象window。
var name = 'the window';var obj = { name: 'my ojb', getNameFunc: function() { return function() { console.log(this.name); // the window } }};obj.getNameFunc()();var obj2 = { name: 'my ojb', getNameFunc: function() { function f() { console.log(this.name); // the window console.log(this === window); // true } f(); }};obj2.getNameFunc();
实际开发中,我们确实有在方法中定义新的函数的需求,一般而言,我们会使用闭包将 this 传入内部函数。
var name = 'the window';var obj = { name: 'my ojb', getNameFunc: function() { return function f() { console.log(this.name); // the window console.log(this === window); // true } }};obj.getNameFunc()();var obj2 = { name: 'my ojb', getNameFunc: function() { var _this = this; return function f() { console.log(_this.name); // my obj console.log(_this === window); // false } }};obj2.getNameFunc()();
6.比较特殊的,在方法中处理数组
var o = { v: 'hello', p: [ 'a1', 'a2' ], f: function f() { this.p.forEach(function (item) { console.log(this.v + ' ' + item); }); }};o.f();// undefined a1// undefined a2
与上面的示例一样,数组处理方法中的 this 也是指向顶层对象window。
7.对象属性中的this
var obj = { name: 'outer', self: this, getName: function() { console.log(this.name); // outer console.log(this.self === window); // true }, inner: { name: 'inner', self: this, getName: function() { console.log(this.name); // inner console.log(this.self === window); // true }, }}obj.getName();obj.inner.getName();
具体JavaScript为什么这么设计,我也不太明白,有知道的同学麻烦告诉我。
8.函数数组中的this
function f1() {return this};function f2() {return this};var arr = [f1, f2];arr[0](); // arr[]
其实这个并不难理解,arr数组其实就是arr对象,[]运算符可以理解为对象中的 . 运算符,只不过在对象中凡是能用 . 运算符的时候都能用 [] 运算符,但是在某些特殊情况下只能用 [] 运算符。调用可以这样理解
// 仅仅作为辅助理解作用,语法上并不合适arr.0()
很明显,会输出 arr 对象嘛。
9.下面来看几个比较奇怪的例子
var name = 'the window';var obj = { name: 'kylin', getName: function() { console.log(this.name); }};obj.getName(); // kylin(obj.getName)(); // kylin(obj.getName = obj.getName)(); // the window(true && obj.getName)(); // the window(false || obj.getName)(); // the window(1, obj.getName)(); // the window
相信实际开发中不会有人这么写,仅作为开拓视野的部分,不再详细展开。
其基本原理是一致的,最后四个代码片段,第一个小括号最后都会返回一个函数并且在全局作用域下执行。
4. DOM事件中的this
DOM事件处理程序中的 this ,一般都是指向绑定事件的Element节点。
但里面有两个特殊的事件处理程序的 this 对象指向 window 对象。
// HTML级事件处理程序<div id="root" onclick="showMSG()"/>function showMSG() { console.log(this === window); // true}// IE事件处理程序<div id="root"/>var rootEle = document.getElementById('root');rootEle.attachEvent('onclick', function () { console.log(this === window); // true});
有对DOM事件还不太了解的同学可以看我的这篇文章DOM事件;
绑定this
1. function.prototype.call()
1.call 方法接受多个参数,其中第一个参数为要绑定的对象,其他的参数为函数调用需要的参数。
var name = 'the window';var obj = { name: 'kylin',};var f = function() { console.log(this.name);}f(); // the windowf.call(obj); // kylin
2.call 方法中的参数,如果参数为空、null、undefined,则默认传入 window 对象。
var name = 'the window';var obj = { name: 'kylin', getName: function() { console.log(this.name); }};var obj2 = { name: 'obj'};obj.getName.call(obj2); // objobj.getName.call(); // the windowobj.getName.call(null); // the windowobj.getName.call(undefined); // the window
3.如果 call 方法中的参数是原始值,那么将传入其包装类型。
var name = 'the window';var obj = { name: 'kylin', getName: function() { console.log(this); }};var obj2 = { name: 'obj'};obj.getName.call(obj2); // obj{}obj.getName.call(1); // Number{}obj.getName.call('string'); // String{}obj.getName.call(false); // Boolean{}
4.call 方法的一个经典实用场景是调用对象的原生方法。
var str = 'my str';console.log(str.toString()); // my strObject.prototype.toString.call(str); // [object String]
2. function.prototype.apply()
apply方法和call方法类似,唯一的不同是其接受数组作为函数执行时的参数。
var name = 'the window';var obj = { name: 'kylin',};var f = function() { console.log(this.name);}f(); // the windowf.apply(obj); // kylin
3. function.prototype.bind()
1.bind 函数用于将函数体内的 this 绑定到某个对象上,然后返回一个新的函数。
var obj = { count: 0, inc: function() { console.log(++this.count); }};var f1 = obj.inc;f1(); // NaNvar f2 = obj.inc.bind(obj);f2(); // 1
2.bind 函数在绑定 this 的同时,还可以绑定原函数的参数。
var add = function(x, y) { return x * this.m + y * this.n;}var obj = { m: 2, n: 3}var newAdd = add.bind(obj, 5);newAdd(10); // 40
3.如果 bind 函数的第一个参数为null、undefined,则默认绑定顶层对象。
var m = 5, n = 10;var add = function(x, y) { console.log(x * this.m + y * this.n);}var newAdd1 = add.bind();newAdd1(5, 10); // 125var newAdd2 = add.bind(null, 5);newAdd2(10); // 125var newAdd3 = add.bind(undefined, 5);newAdd3(10); // 125
4.请注意,bind函数每次都返回一个新函数。
var obj = {name: 'kylin'};var f = function() {return this}var f1 = f.bind(obj);var f2 = f.bind(obj);f1 === f2; // falsef1() === f2(); // true
5. 箭头函数
一般而言,this 指向和执行时的对象有关,而和定义时的对象无关,但是对于箭头函数而言并不是这样。
var name = 'the window';var obj = { name: 'kylin', getNameFunc: function(){ return () => { return this.name; } }};obj.getNameFunc()(); // kylinvar f = obj.getNameFunc();f(); // kylinvar obj2 = { name: 'kylin', getNameFunc: function(){ return function() { return this.name; } }};obj2.getNameFunc()(); // the windowvar f2 = obj2.getNameFunc();f2(); // the window
致谢
本文主要参考了阮一峰老师的文章this 关键字和《JavaScript高级程序设计》,谨在此向阮一峰老师和JavaScript的作者译者表示感谢。
联系我
如果您有任何疑问或本文侵犯了您的著作权,请联系我。 mail to kylin
- 【javascript】javascript中的this
- JavaScript中的this指针
- javascript 中的"this"
- javascript中的this!
- Javascript中的this讲解
- Javascript中的this关键字
- javascript中的this
- JavaScript中的this关键字
- JavaScript中的this详解
- JavaScript中的this指针
- javascript中的this
- JavaScript 中的this 关键字
- 有关javascript中的this
- javascript中的this
- JavaScript 中的 this
- Javascript中的this
- javascript中的this
- JavaScript中的this用法
- 好困#7
- 浅谈数据库事务
- 【每日算法】归并排序
- 黄金系统
- 剑指Offer面试题39二叉树的深度(以及判断平衡二叉树),面试题40数组中只出现一次的数字
- JavaScript中的this
- springmvc注解RequestBody和ResponseBody
- 丑数问题
- java基础
- 虚函数和纯虚函数的区别
- Python入门过程
- 释放被程序占用的磁盘空间
- 【欧几里算法】寻找两数的最大公约数
- 机房登入系统