1. this的涵义,this是什么
-
不管是什么场合,this都有一个共同点:它总是返回一个对象;简单说,this就是属性或方法“当前”所在的对象。
- JavaScript 语言之中,一切皆对象,运行环境也是对象,所以函数都是在某个对象之中运行,this就是函数运行时所在的对象(环境)。
2. this的设计目的
- 由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。
3. 使用场合,使用注意事项
- 使用场合
- 全局环境:全局环境使用this,它指的就是顶层对象window。
- 构造函数。
- 对象的方法:JavaScript 引擎内部,obj和obj.foo储存在两个内存地址,称为地址一和地址二。obj.foo()这样调用时,是从地址一调用地址二,因此地址二的运行环境是地址一,this指向obj。但是,如果是直接取出地址二进行调用,这样的话,运行环境就是全局环境,因此this指向全局环境。
- 注意事项
- 避免多层this
var o = { f1: function () { console.log(this); var f2 = function () { console.log(this); }(); } } o.f1() // Object // Window // 实际执行的是下面的代码。 var temp = function () { console.log(this); }; var o = { f1: function () { console.log(this); var f2 = temp(); } } // 严格模式下,如果函数内部的this指向顶层对象,就会报错。 var counter = { count: 0 }; counter.inc = function () { ‘use strict‘; this.count++ }; var f = counter.inc; f() // TypeError: Cannot read property ‘count‘ of undefined
2. 避免数组处理方法中的 this
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 // 上面代码中,foreach方法的回调函数中的this,其实是指向window对象,因此取不到o.v的值。 // 将this当作foreach方法的第二个参数,固定它的运行环境。 var o = { v: ‘hello‘, p: [ ‘a1‘, ‘a2‘ ], f: function f() { this.p.forEach(function (item) { console.log(this.v + ‘ ‘ + item); }, this); } } o.f() // hello a1 // hello a2
3. 避免回调函数中的 this
var o = new Object(); o.f = function () { console.log(this === o); } // jQuery 的写法 $(‘#button‘).on(‘click‘, o.f); // 上面代码中,点击按钮以后,控制台会显示false。原因是此时this不再指向o对象,而是指向按钮的 DOM 对象
4. 绑定this的方法
- Function.prototype.call()
var obj = {}; var f = function () { return this; }; f() === window // true f.call(obj) === obj // true // call方法还可以接受多个参数。 func.call(thisValue, arg1, arg2, ...) //call的第一个参数就是this所要指向的那个对象,后面的参数则是函数调用时所需的参数。
- Function.prototype.apply()
// apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数。 // 1. 找出数组最大元素 var a = [10, 2, 4, 15, 9]; Math.max.apply(null, a) // 15 // 2. 将数组的空元素变为undefined,空元素与undefined的差别在于,数组的forEach方法会跳过空元素,但是不会跳过undefined。 Array.apply(null, [‘a‘, ,‘b‘]) // [ ‘a‘, undefined, ‘b‘ ] // 3. 转换类似数组的对象。 Array.prototype.slice.apply({0: 1, length: 1}) // [1] Array.prototype.slice.apply({0: 1}) // [] Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined] Array.prototype.slice.apply({length: 1}) // [undefined] // 从上面代码可以看到,这个方法起作用的前提是,被处理的对象必须有length属性,以及相对应的数字键。 // 4. 绑定回调函数的对象 var o = new Object(); o.f = function () { console.log(this === o); } var f = function (){ o.f.apply(o); // 或者 o.f.call(o); }; // jQuery 的写法 $(‘#button‘).on(‘click‘, f);
- Function.prototype.bind()
// bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。 var counter = { count: 0, inc: function () { this.count++; } }; var func = counter.inc.bind(counter); func(); counter.count // 1