1. 全局对象中的this
全局环境中的this,指向它本身。浏览器中指向window。
2. 函数中的this
在函数中,this的指向由调用者决定。
// demo02
var a = 20;
function fn() {
function foo() {
console.log(this.a);
}
foo();
}
fn(); // 20
上述代码中,fn在全局中调用,所以fn的this指向全局也就是window,foo在fn中调用,所以foo的this指向fn的this也是全局window。注意!在严格模式下,this是undefined。
再来观察如下代码
// demo03
var a = 20;
var obj = {
a: 10,
c: this.a + 20,
fn: function () {
return this.a;
}
}
console.log(obj.c);
console.log(obj.fn());
首先obj.c中的this,因为对象并不是一个作用域,所以指向全局为20+20。关键是这里的fn是在obj中调用的!所以这里我们引出一个概念:函数的调用方式。
如果调用函数的家伙被某一个对象拥有,那么函数调用的时候,内部的this指向该对象。即上述代码的this指向obj,this.a就是10。
3. 使用call、apply、bind显示指定this
1.call和apply
call和apply除了参数略有不同,其功能完全一样。
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
2. call和apply的使用场景
2.1 将类数组对象转换为数组
function exam(a, b, c, d, e) {
// 先看看函数的自带属性 arguments 什么是样子的
console.log(arguments);
// 使用call/apply将arguments转换为数组, 返回结果为数组,arguments自身不会改变
var arg = [].slice.call(arguments); // 利用array原型上的slice方法。
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') );
2.2 通过构造函数实现继承
function SuperType(){
this.color=["red", "green", "blue"];
}
function SubType(){
// 核心代码,继承自SuperType
SuperType.call(this);
}
var instance1 = new SubType();
instance1.color.push("black");
console.log(instance1.color);
// ["red", "green", "blue", "black"]
var instance2 = new SubType();
console.log(instance2.color);
// ["red", "green", "blue"]
缺点:
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现复用,每个子类都有父类实例函数的副本,影响性能
3. bind
bind和call、apply有些相似,他是把this永久的绑定到了bind的第一个参数上。
var person = {
name: "axuebin",
age: 25
};
function say(){
console.log(this.name+":"+this.age);
}
var f = say.bind(person);
console.log(f());
4. 手写call
5. 手写apply
4. 构造函数与原型方法上的this
在构造函数中我们经常使用this,那么this到底是什么呢?我们先给结论:this被绑定到正在构造的新对象上。
那么在new一个对象时的步骤我们必须要清楚:
- 创建一个新对象。
- 将这个新对象的[[prototype]]指向构造函数的prototype
- 将构造函数的this指向obj
- 给对象赋值(属性、方法)
- 返回this
可见这个this指向创建的新对象person上。
function Person(name){
this.name = name;
this.age = 25;
this.say = function(){
console.log(this.name + ":" + this.age);
}
}
var person = new Person("axuebin");
console.log(person.name); // axuebin
person.say(); // axuebin:25
4.1 手写new
5. 箭头函数
所有的箭头函数都没有自己的this,会捕获其所在上下文的this作为自己的this。
function Person(name){
this.name = name;
// 上下文
this.say = () => {
var name = "xb";
return this.name;
}
// 上下文
}
var person = new Person("lkh");
console.log(person.say()); // lkh
上述代码可以观察到,箭头函数的上下文处对应的this是构造函数Person的this,当new出来person对象时,this指向person,所以箭头函数的this也指向person对象,所以this.name为lkh.
6. 作为一个DOM事件处理函数
this指向触发事件的元素,也就是始事件处理程序所绑定到的DOM节点。
var ele = document.getElementById("id");
ele.addEventListener("click",function(e){
console.log(this);
console.log(this === e.target); // true
})