面向对象之---this的用法

在绝大多数情况下,函数的调用方式决定了this的值

全局环境

无论是否在严格模式下,在全局执行环境中,this都指向全局对象·

在全局作用域中调用一个函数时,this总是指向Global对象(在浏览器中指向window)

函数(运行内)环境

在函数内部,this的值取决于函数被调用的方式

1.简单调用

非严格模式
function f1() {
  console.log(this);
}
// 在浏览器环境
f1();//window

// 在Node环境
f1();//global

严格模式

在严格模式下,如果this没有被执行环境(execution context)或者称为上下文,this会保持它进入执行环境时的值,所以下面this会被默认为undefined

function f2() {
  'use strict';
  console.log(this);
}
f2(); //undefined

使用call()或者apply()方法,改变this的指向

// 如果想把this的值从一个环境传到另一个,就可以调用call()或者apply()方法
var o = {
  a: 'Customs'
};
var o1 = {
  a: 'Customs1'
};
var o2 = {
  a: 'Customs2'
};
var a = 'Global';
function whatThis(arg) {
  console.log(this.a);
}

whatThis(); //Global
whatThis.call(o); //Customs
whatThis.apply(o); //Customs
whatThis.call(o1); //Customs1
whatThis.apply(o1); //Customs1
whatThis.call(o2); //Customs2
whatThis.apply(o2); //Customs2
强制指向,即改变函数的调用对象
两者有何异同?
apply(thisObj,[argsArray])
call(thisObj,arg1,arg2,arg3)
call()与apply()方法类似,区别就是接受的参数形式不一样
apply()接受的是数组;call()接受的是以逗号分隔的参数
 
使用 call 和 apply 函数的时候要注意,如果传递给 this 的值不是一个对象,JavaScript 会尝试使用内部 ToObject 操作将其转换为对象。
因此,如果传递的值是一个原始值比如 7 或 'foo',那么就会使用相关构造函数将它转换为对象,所以原始值 7 会被转换为对象,像 new Number(7) 这样,而字符串 'foo' 转化成 new String('foo') 这样,
function bar() {
  console.log(Object.prototype.toString.call(this));
}

//原始值 7 被隐式转换为对象
bar.call(7); // [object Number]

2.作为对象的方法调用

当函数作为对象的方法调用,他们的this是调用该函数的对象

var x4 = 44;
function f4() {
  console.log(this.x4); //{x:55,say:f4} this指向o4
}
var o4 = {};
o4.x4 = 55;
o4.say = f4;
o4.say(); // 55
var x5 = 56;
var o5 = {
  x5: 66,
  f5: function() {
console.log(this)
// {x5:66,f5:f} this指向o5

// console.log(this.x5);//66
    return this.x5;
  }
};

console.log(o5.f5()); //66
原型链中的this

对于原型链上某处定义的方法,同样也适用, 如果该方法存在于对象的原型链上,那么this的指向的是调用该方法的对象

var oo = {
  f: function() {
    return this.a + this.b;
  }
};

var p = Object.create(oo);
p.a = 1;
p.b = 2;
console.log(p.f()); // 3
// 解析:对象p没有自己的f属性,该属性继承自原型,
// 对于f的查找过程中,最终在对象oo中找到f属性,查找的过程是p.f的引用开始的,所以this指向p
// 也就是说,因为f是作为p的方法调用的,所以this指向p
getter和setter中的this
当一个函数在一个setter或者getter中被调用
用作getter或者setter的函数都会把this绑定到设置或者获取属性的对象
function sum() {
  console.log(this); //{a: 1,average: 2,b: 2, c: 3,sum: 6}
  return this.a + this.b + this.c;
}
var oo1 = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    console.log(this);//{a: 1,average: 2,b: 2, c: 3,sum: 6}
    return (this.a + this.b + this.c) / 3;
  }
};

Object.defineProperty(oo1, 'sum', {
  get: sum,
  enumerable: true,
  configurable: true
});

console.log(oo1.average, oo1.sum); // 2,6

 

3.作为构造函数

当一个函数作为构造函数时(使用new关键字),他的this指向用构造函数创建的对象

function Test() {
  this.x = 3;
}
var obj1 = new Test();
console.log(obj1.x); // 3
// 解析:this指向Test的实例,即obj1
obj1.x = 5;
console.log(obj1.x); // 5

4.bind()方法

ES5引入Function.prototype.bind()

调用 f.bind()方法会创建一个与 f具有相同的函数体和作用域的函数

但是在这个函数中,this将永久性的被绑定到了bind的第一个参数,无论函数是怎么样调用的

var a3 = 'Global';
function f3() {
  console.log(this.a3); //zhangsan
  return this.a3;
}

var g = f3.bind({ a3: 'zhangsan' });
console.log(g()); // zhangsan

var h = g.bind({ a3: 'haha' }); // bind只生效一次,再次修改也不会生效
console.log(h()); // zhangsan

var o3 = {
  a3: 37,
  f3: f3,
  g: g,
  h: h
};
console.log(o3.f3(), o3.g(), o3.h()); // 37,"zhangsan","zhangsan"

5.作为一个DOM时间处理函数

当函数被用作事件处理函数时,它的this指向触发事件的元素

6.作为一个内联事件处理函数

当代码被内联on-event 处理函数调用时,它的this指向监听器所在的DOM元素

 
 
参考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this
http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html
 
posted @ 2019-02-20 15:39  shengnan_2017  阅读(738)  评论(0编辑  收藏  举报