我理解的this
- this的设计跟JS的内存结构有关,对象的属性可以是函数,而函数也是对象,是单独存储的,所以函数的运行环境是可变的,没有办法在定义的时候知道谁会调用它,便设计了this来代替那个未来调用这个函数的对象。
- 不管什么场合使用this,this一定指代某个对象或运行环境
- this的指向不清楚,跟函数的调用方式有直接的关系,函数调用默认使用隐式传递this,大部分时候可以这样传递,但是不便于理解this,建议用call的方式去显示的绑定this。
var A = { name: '张三', describe: function () { return '姓名:'+ this.name; } }; 显示传递this A.describe.call(A) 隐式传递this A.describe()
绑定this
- function.call(this,arg1,arg2,..)
call后面括号的第一个参数是什么,this就是什么,不传或者传入undefined、null,则默认为全局对象。
看一些例子var n = 123; var obj = { n: 456 }; function a() { console.log(this.n); } a.call() // 123 a.call(null) // 123 a.call(undefined) // 123 a.call(window) // 123 a.call(obj) // 456
- function.apply(this,[arg1,arg2,...])
apply的第一个参数是绑定的this对象,第二个参数是一个数组,对数组进行操作时用apply很方便。 - bind
bind方法和上面两个不同,它将this绑定到一个对象上以后不会执行该函数而是返回一个新的函数几个要注意的地方
- bind()函数每次执行一次就会返回一个函数
- 在map,forEach等有回调函数的方法里使用时使用bind绑定this
示例:var obj = { name: '张三', times: [1, 2, 3], print1: function () { this.times.forEach(function (n) { console.log(this.name); }.bind(this)); }, print2: function () { this.times.forEach(function (n) { console.log(this.name); }); } }; obj.print2() //没有任何输出 obj.print1() //'张三'*3
- 结合call使用
var slice = Function.prototype.call.bind(Array.prototype.slice); slice([1, 2, 3], 0, 1) // [1] 相当于Array.prototype.slice.call([1, 2, 3], 0, 1) 更骚的写法 function f() { console.log(this.v); } var o = { v: 123 }; var bind = Function.prototype.call.bind(Function.prototype.bind); bind(f, o)() // 123
使用this要避免的一些情况
- 多层this
var o = { f1: function () { console.log(this); var f2 = function () { console.log(this); }(); //使用call绑定 var f3 = function () { console.log(this); }.call(this); //使用bind绑定 var f4 = function () { console.log(this); }.bind(this)(); } } o.f1() // {f1: ƒ} // Window // {f1: ƒ} // {f1: ƒ}
- 数组方法中的this
var o = { v: 'hello', p: [ 'a1', 'a2' ], f1: function f() { var that = this; this.p.forEach(function (item) { console.log(that.v+' '+item); }); }, //在回调函数中传入第二参数绑定this f2: function f() { this.p.forEach(function (item) { console.log(that.v+' '+item); },this); } } o.f1() // hello a1 // hello a2 o.f2() // hello a1 // hello a2