this指向
目录
-
this总是返回一个对象,它就是属性和方法当前所在的对象
-
实质:与内存的数据结构有关,引擎会将函数单独保存到内存中,然后再将内存地址赋值给相应的变量,函数是一个单独的值,它可以在不同的环境(上下文)中执行。this的出现就是为了让它获得当前的环境
01-全局环境—顶层对象window
-
this === window // true function f() { console.log(this === window); } f() // true //只要在全局环境中运行,都是指向window对象
02-构造函数—实例对象
-
var Obj = function (p) { this.p = p } var o = new Obj('hi yucuiwen') console.log(o.p); // hi yucuiwen // 在构造函数中,指向的是当前的实例对象
03-对象的方法—方法运行时所在的对象
-
对象可以看做是存放在地址一,对象的方法可以看作是存放在地址二。从地址一去查询地址二,那么它的运行环境就是地址一,但是如果脱离地址一,直接去访问地址二,那么它的运行环境就会改变,this指向也会改变。
var obj ={ foo: function () { console.log(this); } }; obj.foo() // obj // 情况一 (obj.foo = obj.foo)() // window // 情况二 (false || obj.foo)() // window // 情况三 (1, obj.foo)() // window +++++++++++++++++++++++++++++++++++++++ // 情况一 (obj.foo = function () { console.log(this); })() // 等同于 (function () { console.log(this); })() // 情况二 (false || function () { console.log(this); })() // 情况三 (1, function () { console.log(this); })()
-
如果this所在的方法不在对象的第一层,那么this只会指向当前一层的对象,而不会指向更上面一层的对象
var a = { p: 'Hello', b: { m: function() { console.log(this.p); } } }; a.b.m() // undefined
04-注意
-
避免多层this,借助中间变量 that 固定this指向
var o = { f1:function() { console.log(this); // let that = this //因为这里它相当于在函数内部f1()方法下面又定义的方法 不会指向更上面一层的o,所以是window //解决方法:用that固定 var f2 = function() { console.log(this); //console.log(that) } } } o.f1() //object // window
-
-
避免数组处理方法中的this
var o = { v:'hello', p:[11,2 ], f:function fn() { this.p.forEach(function(item){ console.log(this.v+' '+item); }) } } o.f() // undefined 11 // undefined 2 // 由于数组处理方法中的参数也是函数,所以类似于多层嵌套
-
避免回调函数中的this,因为回调函数中的this往往会改变指向
var o = new Object(); o.f = function () { console.log(this === o); } // jQuery 的写法 $('#button').on('click', o.f); // false
05-call(),apply(),bind() 方法
-
函数/方法 call/apply/bind(对象)
-
call()方法,接收的第一个参数一定是一个对象,如果是null,undefined或者空,那么则默认是window对象;如果是原始值,那么则转为其对应的object实例化对象
-
它的主要作用是改变运行时的object指向
var f = function () {return this;}; console.log(f.call(5)); function add(a,b) { return a+b } console.log(add.call(this,3,4));
-
后面跟着的参数是函数的形参
-
应用之一:调用对象的原生方法(*)
var obj = {}; obj.hasOwnProperty('toString') // false // 覆盖掉继承的 hasOwnProperty 方法 obj.hasOwnProperty = function () { return true; }; obj.hasOwnProperty('toString') // true Object.prototype.hasOwnProperty.call(obj, 'toString') // false
-
apply()方法,主要特点是以数组的形式传递参数
-
应用1:数组取最大值,与数学方法联系起来 将数学上取最大值的方法运用到了数组身上
var a = [12,354,545,45] console.log(Math.max.apply(null,a));
-
应用二:将数组中的空对象设置为undefined,以便于forEach可以遍历的到
console.log(Array.apply(null,['a',,'b']));
-
应用三:将类数组转化为真正的数组,但是类数组必须有length属性,要不然默认length:0
[].slice.apply({0:1,length:1}), // 这种写法 是先new一个实例 然后调用原型对象上的slice方法 // this指向是 创建的实例对象 Array.prototype.slice.apply({0:1}), Array.prototype.slice.apply({0:1,length:2}), Array.prototype.slice.apply({length:1}) // 这些写法 this指向都是 Array.prototype实例对象 // 当然可以改变它们的指向
-
-
-
bind() 方法类似
// 数组方法的实质
06-箭头函数的this指向问题
-
箭头函数中 指向的是定义箭头函数的上下文
-
它并不是没有this指向,只不过它的指向在定义时就已经确认了
window.color = 'red' let o = { color:'blue' } let sayColor = () => {console.log(this.color);} sayColor() //red o.sayColor = sayColor o.sayColor() //red
对于解决异步问题十分有效 var royalName = 'yucuiwen' function King() { this.royalName = 'Henry' setTimeout(() => {console.log(this.royalName)},1000) // setTimeout(function() { // console.log(this.royalName); // },1000) // yucuiwen } function Queen() { this.royalName = 'Elizabeth' setTimeout(() => {console.log(this.royalName)},1000) } new King() //'Henry' new Queen() //'Elizabeth'