javascript中this指针探讨

简介:

 javascript是一门类java语言有很多跟java相类似的特点,但也仅是类似而已,真正使用中还是有很大的差别。this指针常常让很多初学者抓狂,本人也曾为此困惑不解,查找过很多资料,今天在这里总结一下,希望能帮助后来者更快驯服这只拦路虎。网上有很多讲解this指针的文章其中不乏精品,以我看来了解this指针关键在于掌握javascript中函数的四种调用模式。那么什么是调用?调用指的是跟在任何产生一个函数值的表达式之后使用"()",obj.f()这种方式成为调用,obj.f这种方式称为访问。

  一、方法调用模式:

  在该调用模式中函数作为一个对象的方法被调用:obj.fun()。当函数以此种形式被调用时this指针绑定到调用该方法的对象上即obj。


var myObj = {
  value: 0,
  increase: function(){
    this.value++;
    console.log(this.value);
  }
};
// this绑定到myObj对象上
myObj.increase(); // 1

myObj2 = {
  value: 10
};
myObj2.increase = myObj.increase;// myObj2与myObj的increase指向同一函数引用地址
// this绑定到myObj2对象上
myObj2.increase(); // 11

所以在将一个html元素的某一事件绑定某一函数时,若函数中使用this指针,则this指针会被绑定到该元素上。


var ele1 = document.getElementById('id');
ele1.addEventListener('click', myObj.increase, false);
// 该绑定相当于
ele1.onclick = myObj.increase;
// 事件触发时即相当于调用click方法
ele1.click(); // 与上文中myObj2.increase一个道理,若ele1中没有value属性则会报错

 二、函数调用模式:

  当函数没有当做方法调用即没有被一个对象通过点语法,这时它被当做一个函数来调用。以此模式调用函数时,this被绑定到全局对象。


var value = -10;
var myObj = {
  value: 0,
  increase: function(){
    this.value++;
    console.log(this.value);
  }
};
// this绑定到myObj对象上
myObj.increase(); // 1

var gInc = myObj.increase;
gInc(); // -9 this绑定到window对象上

所以在方法中使用内部函数时要特别注意,下例中other函数中的this并未绑定到myObj对象上


var value = -10;
var myObj = {
  value: 0,
  increase: function(){
    this.value++;
    console.log(this.value);
    var other = function(){
      this.value++;
      console.log(this.value); 
    };
    other();// -9, 这时other中的this绑定到window对象上
  }
};
// this绑定到myObj对象上
myObj.increase(); // 1

var gInc = myObj.increase;
gInc(); // -8
///////////////
//1
//-9
//-8
//-7

幸运的是我们可以使用以下方式来在other中访问myObj对象:


var myObj = {
  value: 0,
  increase: function(){
    this.value++;
    console.log(this.value);
    var that = this;
    var other = function(){
      that.value++;
      console.log(that.value); 
    };
    other();// -9, 这时other中的this绑定到window对象上
  }
};
// this绑定到myObj对象上
myObj.increase(); // 1
//////////////
//1
//2

  作为浏览器兼容性中很重要的一条:element.attachEvent绑定事件方法,当该事件触发时this指针并未绑定到element对象上,而是绑定到了window对象上,原因在于IE中事件触发时,响应函数是以一个独立函数即函数调用模式来调用的

 

  三、构造器模式调用:

  如果在一个函数前面加上new调用则成为构造器模式调用。使用new运算符,会产生一个连接到该函数prototype的新对象,this指针则被绑定到这个新对象上。


var P = function(n){
  this.name = n;
}
P.prototype.getName = function(){
  console.log(this.name);
}
var p = new P('woodtree'); // 这时P中的this对象呗绑定p指向的对象引用上
p.getName();// woodtree

同时new运算符还会改变函数的返回值。以函数调用模式调用P即P()返回undefined,而通过new运算符则返回一个新对象。new运算符类似于以下Function.prototype.create函数:


var P = function(n){
  this.name = n;
}
P.prototype.getName = function(){
  console.log(this.name);
}
var p = new P('woodtree');
p.getName();

Object.prototype.create = Object.create || function(proto){
  var F = function(){};
  F.prototype = proto;
  return new F();
}

Function.prototype.create = function(){
  var that = object.create(this.prototype);
  var obj = this.apply(that, arguments);

  return obj || that;
}
var p2 = P.create('hello new');
p2.getName(); // hello new

  四、apply、call模式调用:

  javascript中函数对象继承自Object亦可以拥有方法。call跟apply允许我们选择this的绑定对象。这两个方法的区别在于apply第二个参数必须是一个数组或者类数组对象即拥有length属性(arguments、NodeList、HTMLElementCollection等),而call除了第一个参数为要绑定this的对象外,后可跟无数的参数,参数之间用逗号间隔。


var P = function(n){
  this.name = n;
}
P.prototype.getNameAndAge = function(age){
  console.log(this.name + age);
}

P.prototype.getNameAndAge.call({
  name: 'catboat'
}, 99);
P.prototype.getNameAndAge.apply({
  name: 'lanuch'
}, [99]);

通过使用apply与call方法我们可以自行实现ES5中的bind函数


var P = function(n){
  this.name = n;
}
P.prototype.getNameAndAge = function(age, age2){
  console.log(this.name + age + age2);
}

P.prototype.getNameAndAge.call({
  name: 'catboat'
}, 99);
P.prototype.getNameAndAge.apply({
  name: 'lanuch'
}, [99]);

Function.prototype.bindContext = function(that){
  var _method = this,
  slice = Array.prototype.slice,
  args = slice.call(arguments, 1);

  return function(){
    _method.apply(that, Array.prototype.concat.apply(args, arguments));
  }
};

var f1 = P.prototype.getNameAndAge.bindContext({
  name: 'barque'
}, 88);
f1(9);

同样我们也可以解决IE中事件触发时,this指针问题(以下代码来自《Javascript框架设计》):


1 var addEvent = document.addEventListener ? function(el, type, fn, capture){
2   return el.addEventListener(type, fn, capture);
3 } : function(el, type, fn){
4   el.attachEvent('on' + type, fn.bindContext(el, event));
5 }

目录
相关文章
|
3天前
|
存储 编译器 程序员
从C语言到C++④(第二章_类和对象_上篇)->类->封装->this指针(下)
从C语言到C++④(第二章_类和对象_上篇)->类->封装->this指针
4 0
|
3天前
|
存储 编译器 C语言
从C语言到C++④(第二章_类和对象_上篇)->类->封装->this指针(中)
从C语言到C++④(第二章_类和对象_上篇)->类->封装->this指针
5 0
|
3天前
|
Java C语言 C++
从C语言到C++④(第二章_类和对象_上篇)->类->封装->this指针(上)
从C语言到C++④(第二章_类和对象_上篇)->类->封装->this指针
5 0
|
6天前
|
前端开发 JavaScript
JavaScript:this-关键字,2024中级前端开发面试解答
JavaScript:this-关键字,2024中级前端开发面试解答
|
9天前
|
C++ 编译器
|
9天前
|
自然语言处理 JavaScript 前端开发
在JavaScript中,this关键字的行为可能会因函数的调用方式而异
【5月更文挑战第9天】JavaScript中的`this`关键字行为取决于函数调用方式。在非严格模式下,直接调用函数时`this`指全局对象,严格模式下为`undefined`。作为对象方法调用时,`this`指向该对象。用`new`调用构造函数时,`this`指向新实例。通过`call`、`apply`、`bind`可手动设置`this`值。在回调和事件处理中,`this`可能不直观,箭头函数和绑定方法可帮助管理`this`的行为。
17 1
|
9天前
|
JavaScript 前端开发
深入探索JavaScript:如何改变this的指向
深入探索JavaScript:如何改变this的指向
|
9天前
|
存储 编译器 C语言
【C++】类与对象【定义、访问限定符、this指针】
【C++】类与对象【定义、访问限定符、this指针】
6 1
|
9天前
|
JavaScript 前端开发
【专栏】`Function.prototype.apply` 在JavaScript中用于动态设定函数上下文(`this`)和参数列表
【4月更文挑战第29天】`Function.prototype.apply` 在JavaScript中用于动态设定函数上下文(`this`)和参数列表。它接受两个参数:上下文对象和参数数组。理解`apply`有助于深入JS运行机制。文章分三部分探讨其原理:基本概念和用法、工作原理详解、实际应用与注意事项。在应用中要注意性能、参数类型和兼容性问题。`apply`可用于动态改变上下文、传递参数数组,甚至模拟其他语言的调用方式。通过深入理解`apply`,能提升代码质量和效率。
|
9天前
|
JavaScript 前端开发 数据安全/隐私保护