this指向
Posted sherrycat
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了this指向相关的知识,希望对你有一定的参考价值。
在创建执行上下文这个阶段中,最后是确定this指向。
一个非常重要一定要牢记于心的结论:this的指向,是在函数被调用的时候确定的。也就是执行上下文被创建的时候确定的。
同一个函数,调用的方式不同,this的指向也不同:
var a = 10; var obj = a: 20 function fn () console.log(this.a); fn(); // 10 fn.call(obj); // 20
B.apply(A, arguments):即A对象应用B对象的方法。
在函数执行的过程中,this的指向一旦确定,就不可被更改了。
var a = 10; var obj = a: 20 function fn () this = obj; // 这句话试图修改this,运行后会报错 console.log(this.a); fn();
一、全局对象中的this
全局环境中的this,指向它本身。
// 通过this绑定到全局对象 this.a2 = 20; // 通过声明绑定到变量对象,但在全局环境中,变量对象就是它自身 var a1 = 10; // 仅仅只有赋值操作,标识符会隐式绑定到全局对象 a3 = 30; // 输出结果会全部符合预期 console.log(a1); console.log(a2); console.log(a3);
二、函数中的this
三、使用call、apply指定this
call和apply的功能一样,只是参数不同。call是列举出所有参数,而apply是以将参数放入数组,以数组的形式传递。举例:
function fn() console.log(this.a); var obj = a: 20 fn.call(obj);
上面输出为20。可以看到,通过call,将fn内部的this绑定为obj,因此就可以通过this.a访问obj的a属性了。
再看添加参数的例子:
function fn(num1, num2) console.log(this.a + num1 + num2); var obj = a: 20 fn.call(obj, 100, 10); // 130 fn.apply(obj, [20, 10]); // 50
call和apply的第一个参数是this绑定的对象,后面就是传入fn的参数。
call/apply的应用场景
1.将类数组对象转换为数组
function exam(a, b, c, d, e) // 先看看函数的自带属性 arguments 什么是样子的 console.log(arguments); // 使用call/apply将arguments转换为数组, 返回结果为数组,arguments自身不会改变 var arg = [].slice.call(arguments); console.log(arg); exam(2, 8, 9, 10, 3); // result: // ‘0‘: 2, ‘1‘: 8, ‘2‘: 9, ‘3‘: 10, ‘4‘: 3 // [ 2, 8, 9, 10, 3 ] // // 也常常使用该方法将DOM中的nodelist转换为数组 // [].slice.call( document.getElementsByTagName(‘li‘) );
nodelist是DOM操作取出来的集合,而不是数组,不能直接用数组元素的方法来操作nodelist。
2.根据自己的需要灵活修改this指向
3.实现继承
// 定义父级的构造函数 var Person = function(name, age) this.name = name; this.age = age; this.gender = [‘man‘, ‘woman‘]; // 定义子类的构造函数 var Student = function(name, age, high) // use call Person.call(this, name, age); this.high = high; Student.prototype.message = function() console.log(‘name:‘+this.name+‘, age:‘+this.age+‘, high:‘+this.high+‘, gender:‘+this.gender[0]+‘;‘); new Student(‘xiaom‘, 12, ‘150cm‘).message(); // result // ---------- // name:xiaom, age:12, high:150cm, gender:man;
在student的构造函数中,借助call方法,将父级的构造函数执行了一次,相当于将person中的代码在student中复制了一份,其中this的指向为从student中new出来的实例对象。
4.在向其它执行上下文的传递中,确保this的指向不变
举个栗子:
var obj = a: 20, getA: function() setTimeout(function() console.log(this.a) , 1000) obj.getA();
在这段代码中,希望的是this.a输出的是20,也就是说希望this指向obj,但是由于setTimeout中的匿名函数,所以当中的this指向丢失而指向了全局。因此可以将this的指向保存起来:
var obj = a: 20, getA: function() var self = this; setTimeout(function() console.log(self.a) , 1000) obj.getA()
这样的话,在obj.getA()时,self为obj,输出为20。
还可以直接利用ES5中的bind方法:
var obj = a: 20, getA: function() setTimeout(function() console.log(this.a) .bind(this), 1000)
obj.getA()
在obj.getA()时,bind(this)中的this指向obj,可以将匿名函数中的this的指向改为obj。
还可以借助闭包与apply方法,封装一个bind方法(※):
function bind(fn, obj) return function() return fn.apply(obj, arguments); var obj = a: 20, getA: function() setTimeout(bind(function() console.log(this.a) , this), 1000) obj.getA();
借助call方法实现bind(※):
if (!Function.prototype.bind) Function.prototype.bind = function () var self = this, // 保存原函数 context = [].shift.call(arguments), // 保存需要绑定的this上下文 args = [].slice.call(arguments); // 剩余的参数转为数组 return function () // 返回一个新函数 self.apply(context,[].concat.call(args, [].slice.call(arguments)));
四、构造函数与原型方法上的this
结合例子:
function Person(name, age) // 这里的this指向了谁? this.name = name; this.age = age; Person.prototype.getName = function() // 这里的this又指向了谁? return this.name; // 上面的2个this,是同一个吗,他们是否指向了原型对象? var p1 = new Person(‘Nick‘, 20); p1.getName();
总结了一篇关于原型和原型链的文章。这里的this都是指向p1。
必须要搞明白,new的过程中到底发生了什么(※):
(1)创建了一个新的对象
(2)将构造函数的this指向这个新对象
(3)指向构造函数的代码,为这个对象添加属性、方法等
(4)返回新对象
以上是关于this指向的主要内容,如果未能解决你的问题,请参考以下文章