javaScript面向对象编程之this关键字

javaScript面向对象编程之this关键字

1. 含义

简而言之,this就是属性或方法“当前”所在的对象。

比如:

var person = {
	name: "jidi",
	print: function(){
		return "name:"+this.name;
	}
}
person.print(); // "name:jidi"

在上面这个例子中,this.name中的this表示name属性所在的对象。因为this.nameprint()方法中调用,而priint()方法所在当前对象为person。所以this指向person对象,this.name即为person.name

对象的属性赋值给另一个对象后,属性所在当前对象跟着改变,this的指向也会改变。

var person = {
	name: "jidi",
	print: function(){
		return "name:"+this.name;
	}
}

// 创建一个新对象
var lady = {
	name: 'lady'
};

// 将person.print属性赋值给lady
lady.print = person.print;

person.print(); // "name:jidi"
lady.print(); // "name:lady"

以一种更清晰的方式展示this的指向变化。

// 定义一个全局函数print
function printName(){
	return "name:"+this.name;
}

// 分别创建两个对象
var o1 = {
	name: "Object1",
	print: printName
};
var o2 = {
	name: "Object2",
	print: printName
};

o1.print(); // "name:Object1"
o2.print(); // "name:Object2"

上面例子中,printName()函数内部使用了this,随着printName()函数所在的对象不同,this的指向也不同。

只要函数被赋值给另一个变量,this的指向就会改变。

var p = {
	name: "p",
	print: function(){
		return this.name;
	}
};

var name = "我是全局变量";
// 将p.print赋值给q
var q = p.print;

p.print(); // “p”
q(); // "我是全局变量"

this其实很常见,比如说:

<!--HTML表单片段-->
年龄:<input type="text" name = "age" placeholder="请输入你的年龄!" onChange="varifyAge(this)"></input>
<!--javaScript代码片段--->
function onChange(object){
	if(object.value > 120 || object.value < 0 ){
		console.error("你输入的年龄不合法!");
	}
} 

上面这个例子,this指向的是<input>这个文本框。

在JavaScript 中,一切皆对象,运行环境也是对象。函数都是在某个对象之中运行,this就是函数运行时所在的对象(环境)。

2. 实质

javaScript中之所以有this关键字,跟内存里面的数据结构有很大关系。

var example = {color: "red"};

在上述代码中,将一个对象赋值给变量example,javaScript引擎会先在内存里生成一个对象{color: "red"},然后把这个对象的内存地址赋值给变量example。即变量example是一个对象的内存地址 。当读取example.color时,先从example拿到对象内存地址,然后再从内存地址提取出来原始的对象。

原始的对象以字典结构保存,每一个属性名都对应一个属性描述对象。以上面的例子为例,实际上是以下面的形式保存的。

{
	color:{ // 属性描述对象
		value: "red",
		writable: true,
		enumerable: true,
		configurable: true		
	}
}

如果对象的属性是一个函数,会将函数单独保存,把函数的内存地址赋值给属性名对应的属性描述对象的value

var example = {
	print: function(){
		console.log("我是一个函数");
	}
}

// 内存中的保存形式
{
	print: { // 属性描述对象
		value: 函数内存地址,
		......
	}
}

由于函数是在内存中单独存储的,所以可以在不同的上下文环境中执行。

function printName(){
	console.log(this.name);
}
 var person = {
 	name: "person对象里的name",
	printName: printName
}

var name = "全局环境中的name"

// 单独执行
printName(); // "全局环境中的name"
//person环境中执行
person.printName(); // "person对象里的name",

JavaScript 允许在函数体内部,引用当前环境的其他变量。由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。

3. 使用场合

this主要在以下场景使用。

  1. 构造函数
    构造函数中的this指的实例。
  2. 全局环境
    全局环境中使用,指的是顶层对象window
  3. 对象的方法
    如果对象的方法里面包含thisthis的指向就是方法运行时所在的对象。该方法赋值给另一个对象,就会改变this的指向。
var example ={
  f: function () {
    console.log(this);
  }
};

// 情况一
example.f() // obj
// 情况二
(example.f = example.f)() // window
// 情况三
(false || example.f)() // window
// 情况四
(1, example.f)() // window

之所以出现上述情况,是因为example是个对象,它的属性f其实是一个内存地址,指向属性f对应的属性描述对象,但是属性f对应的描述对象的value其实是函数的内存地址。即exampleexample.f存储在两个内存地址中。example.f()是从地址一调用地址二,所以地址二的运行环境是地址一,this指向exampleexample.f是直接调用地址二,此时运行环境就是全局环境,因此this指向全局环境。

4. 绑定this的方法

this的动态切换,为 JavaScript 创造了巨大的灵活性,但有时,需要把this固定下来,JavaScript 提供了callapplybind这三个方法,来切换/固定this的指向。

4.1 Function.prototype.call()

函数实例的call方法,可以指定函数内部this的指向,然后在所指定的作用域中,调用该函数。

var obj = {};
var f = function () {
  return this;
};

f() === window // true
// 调用call方法,改变this指向
f.call(obj) === obj // true

在上面的例子中,全局环境中运行函数f()this指向全局环境;使用call()方法,将this的指向改变为obj对象,然后在obj对象的作用域中运行函数f()

call方法的参数,是一个对象。如果参数为空、nullundefined,则默认传入全局对象。

var number = 123;
var obj = { number: 456 };

function a() {
  console.log(this.number);
}

// 参数为空,null,undefined默认传入全局对象
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123

// 改变this的指向
a.call(obj) // 456

call方法还可以接受多个参数。call的第一个参数就是this所要指向的那个对象,后面的参数则是函数调用时所需的参数。

function add(a, b) {
  return a + b;
}

// 多个参数,第一个为this指向的对象,后面的参数是函数调用时需要的参数
add.call(this, 1, 2) // 3

4.2 Function.prototype.apply()

apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数。

apply常用来转换类似数组的对象。

Array.prototype.slice.apply({0: 1, length: 1}) // [1]

4.3 Function.prototype.bind()

bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。

var counter = {
  count: 0,
  add: function () {
    this.count++;
  }
};

// 不绑定
var func = counter.add;
func(); 
counter.count; // 0

// 绑定 
var func = counter.add.bind(counter);
func();
counter.count // 1

上面例子中,如果不绑定,将counter.add赋值给func,此时this指向全局环境。

注意:bind方法每运行一次,就会返回一个新函数。

5. 参考链接

本篇博文是我自己学习笔记,原文请参考javaScript教程

发布了5 篇原创文章 · 获赞 1 · 访问量 108

猜你喜欢

转载自blog.csdn.net/qq_41863849/article/details/103948776