this指向和call、apply、bind
this指向:
在浏览器里,在全局范围内this指向window对象;
在普通函数中,this永远指向最后调用他的那个对象;
在构造函数中,this指向new出来的那个新的对象;
在call、apply、bind中的this被强绑定在指定的那个对象上;
箭头函数中this比较特殊,箭头函数this是父作用域的this,不是调用时的this。
要知道前四种方式,都是调用时确定,也就是动态的,而箭头函数的this指向是静态的,声明的时候就确定了下来;
apply、call、bind都是js给函数内置的一些API,调用他们可以为函数指定this的执行,同时也可以传参。
一、全局中的this: ①在浏览器里,在全局范围内:
this等价于window对象,用var声明一个变量和给this或者window添加属性是等价的;
如果你在声明一个变量的时候没有使用var或者let、const(es6),你就是在给全局的this添加或者改变属性值:
// 1
console.log(this === window); //true
//2
var name = "Jake";
console.log(this.name ); // "Jake"
console.log(window.name ); // "Jake"
//3
age = 23;
function testThis() {
age = 18;
}
console.log(this.age ); // 23
testThis();
console.log(this.age ); // 18
在全局范围内this是最大的,它等价于window对象(即指向window),如果你声明一些全局变量(不管在任何地方),这些变量都会作为this的属性。
二、函数中的this:对于函数中的this指向问题,运行时this永远指向最后调用它的那个对象:
var name = "windowsName";
function sayName() {
var name = "Jake";
console.log(this.name); // windowsName
console.log(this); // Window
}
sayName();
console.log(this) // Window
我们看最后调用 sayName的地方 sayName();前面没有调用的对象那么就是全局对象 window,这就相当于是 window.sayName()。
对于严格模式来说,默认绑定全局对象是不合法的,this被置为undefined。会报错:
function foo() {
console.log( this.age );
}
var obj1 = {
age : 23,
foo: foo
};
var obj2 = {
age : 18,
obj1: obj1
};
obj2.obj1.foo(); // 23
还是开头的那句话,最后调用foo()的是obj1,所以this指向obj1,输出是23。
三、构造函数中的this:构造函数就是通过这个函数生成一个新对象(object)。当一个函数作为构造器使用时(通过 new 关键字), 它的 this 值绑定到新创建的那个对象。如果没使用 new 关键字, 那么他就只是一个普通的函数, this 将指向 window 对象。举例new的过程:
var a = new Foo("zhang","jake");
new Foo{
var obj = {};
obj.__proto__ = Foo.prototype;
var result = Foo.call(obj,"zhang","jake");
return typeof result === 'obj'? result : obj;
}
如果执行 new Foo(),过程是:
首先创建一个新的对象 obj;然后给这个新对象的内部属性赋值,构造原型链就是将新对象的隐式原型指向其构造函数的显示原型;
之后执行函数 Foo,执行过程中内部 this 指向新创建的对象 obj(这里使用了call改变this指向);
最后如果 Foo 内部显式返回对象类型数据,就返回该数据,执行结束;否则返回新创建的对象 obj。
var name = "Jake";jiuzhixiang
function testThis(){
this.name = 'jakezhang';
this.sayName = function () {
return this.name;
}
}
console.log(this.name ); // Jake
new testThis();
console.log(this.name ); // Jake
var result = new testThis();
console.log(result.name ); // jakezhang
console.log(result.sayName()); // jakezhang
testThis();
console.log(this.name ); // jakezhang
那个被new了 this就指向那个
四、call、apply、bind中的this:call、apply、bind 被称为 this 的强绑定,用来改变函数执行时的this指向,目前所有关于它们的运用,都是基于这一点来进行的。
var name = 'zjk';
function fun() {
console.log (this.name);
}
var obj= {
name: 'jake'
};
fun(); // zjk
fun.call(obj); //Jake
上面的fun.ccall(obj)
等价于fun.capply(obj)
和fun.cbind(obj)()
五、箭头函数中的this:箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this:
let name = "zjk";
let o = {
name : "Jake",
sayName: function () {
console.log(this.name)
},
func: function () {
setTimeout( () => {
this.sayName()
},100);
}
};
o.func() // Jake
使用 call 、 apply、 bind等方法给 this传值,箭头函数会忽略。箭头函数引用的是箭头函数在创建时设置的 this值:
let obj = {
name: "Jake",
func: (a,b) => {
console.log(this.name,a,b);
}
};
func.call(obj,1,2);// 1 2
func.apply(obj,[1,2]);// 1 2
call、apply、bind三者的区别:
①call和apply都可以改变this指向,可以让函数立刻执行;区别是传参的时候 call传的是字符串,apply传的是数组;
②bind 可以改变this指向,但是不会让函数立刻执行;
function add (a, b) {
return a + b;
}
function sub (a, b) {
return a - b;
}
add.bind(sub, 5, 3); // 这时,并不会返回 8
add.bind(sub, 5, 3)(); // 调用后,返回 8