this的几种用法
关于this
this是什么?
理论上this是执行上下文的一个属性,this的值在进入到执行上下文的时候就已经确定了,且不会再改变。这一点很重要。
this的作用?
this 的机制提供了一个优雅的方式,隐式地传递一个对象,这可以让函数设计的更加简洁,并且复用性更好。
总览
new绑定,this指向由new创建的对象
显示绑定,this指向apply或者call函数的第一个参数
隐式绑定,this指向函数的调用者。
默认绑定,严格模式下指向undefinded,非严格模式this指向全局对象。
箭头函数绑定,this指向箭头函数外边包裹的普通函数
new绑定
当用new创建一个新的对象的时候,this指向了由new关键字声明创建的对象。
class Person(name){
constructor(name){
this.name = name;
}
showThis(){
return this;
}
}
var p1 = new Person('zhang');
var p2 = new Person('zhao');
console.log(p1.showThis() === p1); //true
console.log(p2.showThis() === p2); //true
console.log(p1.showThis() === Persion) //false
可以看到,这种情况下this的值指向了由new创建的对象的引用。this会被绑定到这个对象上去。
显式绑定
所谓的显式绑定,指的是通过apply或者call方法的第一个参数。
call和apply的不同,两个方法的第一个参数都是this赋给的对象。不同在于,之后的参数被当作call方法的形参依次传进去,而apply则是接受一个数组。
看代码:
function foo(){
console.log(this === obj); //true
console.log(this.a === 2); //true
}
var obj = {
a:2
}
foo.call(obj);
隐式绑定
隐式绑定用的次数比较多。一个最重要的特点就是,this的指定顺序和在哪里定义没有关系,而是取决于调用者。
严格意义来说,this是上下文里的一个属性(存放各种变量的变量对象同样也是上下文里的属性),this的值总是指向当前上下文的父级上下文,其实也就是当前上下文的调用者。
看代码:
//第一个简单的例子
var obj = {
a : 1,
foo : function(){
console.log(this === obj); //trun
console.log(this.a === 1); //true
},
bar : bar
}
//假如把一个属性定义在对象外边
function bar(){
console.log(this === obj); //true
}
obj.foo();
obj.bar(); //都是true
再来一个例子
function bar(){
console.log(this === obj1);
console.log(this === obj2);
}
function foo(){
console.log(this === obj1);
console.log(this === obj2);
}
var obj1 = {
bar: bar,
foo: foo
}
var obj2 = {
bar: obj1.bar,
foo: obj1.foo,
}
obj1.foo(); //true false
obj2.foo(); //false true
obj1.bar(); //true false
obj2.foo(); //false true
很简单,foo和bar两个方法分别由obj1和obj2调用,哪怕obj2中的foo和bar是obj1的也没关系,与在哪里定义没有关系,纯粹看是看谁调用的,obj2.foo()就是obj2调用的foo方法,所以,这个时候this指向obj2。
多说一句,如果既有显示绑定又有隐式绑定,当然是以显示绑定为准。
默认绑定
这种情况下,this不属于任何一个函数方法内,即在全局作用域下,这种情况下称为默认绑定。
非严格模式下,这个时候this值为window全局对象。
function foo(){
console.log(this === window);
}
foo();
严格模式下,this的值是undefined
"use strict";
function foo() {
console.log( this === undefined );
}
foo(); // true
foo.call(undefined); // true
foo.call(null); // false
箭头函数
箭头函数其实是一个语法躺,箭头函数的里的this指向包裹箭头函数的那个函数的this值。很好理解。
// ES6
function foo() {
setTimeout(() => {
console.log(this === obj); // true
}, 100);
}
const obj = {
a : 1
}
foo.call(obj);
// ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log(_this === obj); // true
}, 100);
}
var obj = {
a : 1
}
foo.call(obj);
最后的总结
用伪代码的形式来表示
if (`newObj = new Object()`) {
this = newObj
} else if (`bind/call/apply(thisArgument,...)`) {
if (`use strict`) {
this = thisArgument
} else {
if (thisArgument == null || thisArgument == undefined) {
this = window || global
} else {
this = ToObject(thisArgument)
}
}
} else if (`Function Call`) {
if (`obj.foo()`) {
// base value . Reference = base value + reference name + strict reference
// 例外: super.render(obj). this = childObj ?
this = obj
} else if (`foo()`) {
// 例外: with statement. this = with object
this = `use strict` ? undefined : window || global
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。