一、this
1、什么是this
JS中的this表示了一个对象的引用,那么这个对象到底指向了谁呢?首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
2、详细了解this
例1:
function a(){
var name = "liang";
console.log(this.name); //undefined
console.log(this); //window
}
a();
这里为什么this打印出来是window呢?其实函数a在执行的时候是全局作用域的window调用的,等于是window.a(),遵循“this的最终指向的是那个调用它的对象”这个规则,可以看下面代码:
function a(){
var name = "liang";
console.log(this.name); //undefined
console.log(this);  //window
}
window.a()
例2:
var obj = {
name:"liang",
sayName:function(){
console.log(this.name) //liang
}
}
obj.sayName()
上述代码就很明显的展示了“this的最终指向的是那个调用它的对象”这个规则,这里的sayName这个函数是对象obj调用他的,那么函数内部的this自然指向的是obj这个对象,obj对象中有name属性,打印的就是name属性的值
把上面的代码再改一下,
var obj = {
name:"liang",
sayName:function(){
console.log(this.name) //liang
}
}
window.obj.sayName()
结果还是一样,这里的this为什么不是指向window,因为sayName方法最终还是由obj这个对象调用的,只是obj对象是挂载在window下的一个属性,但并不是window调用了sayName方法
同样的,下面的代码依然证明了“this的最终指向的是那个调用它的对象”这个规则:
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
var o = {
a:10,
b:{
// a:12,
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
上述两段代码中,最终调用fn函数的都只是b这个对象,所以this都指向的是b,第一段代码中b对象有a属性,因此打印的是b中的a属性值。而第二段代码中将b对象中的a注释掉了,那么this指向的b对象中找不到a属性了,自然打印的是undefined
例3:
看这段代码
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
这里为什么this指向的是window呢?其实,var j = o.b.fn这一步操作是将fn这个函数赋值给了j,而j是挂载在window下的变量,那么j变量保存的函数执行的时候this指向的就是window
例4:
function Fn(){
this.user = "liang";
}
var a = new Fn();
console.log(a.user); //liang
这里对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向,将这个this指向对象a,我们这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象a中会有user,因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份
当this遇到return时:
function Fn()
{
this.user = 'liang';
return {};
}
var a = new Fn();
console.log(a.user); //undefined
function Fn()
{
this.user = 'liang';
return function(){};
}
var a = new Fn();
console.log(a.user); //undefined
function Fn()
{
this.user = 'liang';
return 1;
}
var a = new Fn();
console.log(a.user); //liang
function Fn()
{
this.user = 'liang';
return undefined;
}
var a = new Fn();
console.log(a.user); //liang
function Fn()
{
this.user = 'liang';
return null;
}
var a = new Fn();
console.log(a.user); //liang
经上述几个return,总结得出:如果返回值是一个除null以外的对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例
二、call/apply/bind的理解
1.这三个东西是干什么用的,为什么要使用他们?
碰到以下案例:
var a = {
user:"liang",
fn:function(){
console.log(this.user);
}
}
var b = a.fn;
b(); //undefined
我想要的效果是b执行后打印出user,却得到结果是undefined,原因是为什么上面已经解释过了,那么如何能达到我要的效果呢? 这时候就需要用到call/apply/bind来改变this的指向了
2、call
var a = {
user:"liang",
fn:function(){
console.log(this.user); //liang
}
}
var b = a.fn;
b.call(a);
通过call方法,给第一个参数添加要把b添加到哪个环境中,简单来说,this就会指向那个对象
call方法除了第一个参数以外还可以添加多个参数,如下:
var a = {
user:"liang",
fn:function(num1,num2){
console.log(this.user); //liang
console.log(num1 + num2); //3
}
}
var b = a.fn;
b.call(a,1,2);
3.apply
var a = {
user:"liang",
fn:function(){
console.log(this.user); //liang
}
}
var b = a.fn;
b.apply(a);
apply方法和call方法有些相似,它也可以改变this的指向,同样apply也可以有多个参数,但是不同的是,第二个参数必须是一个数组或者类数组,如下:
var a = {
user:"liang",
fn:function(num1,num2){
console.log(this.user); //liang
console.log(num1 + num2); //11
}
}
var b = a.fn;
b.apply(a,[10,1]);
4.bind
bind方法和call、apply方法有些不同,但是它们都可以用来改变this的指向,bind改变完this指向之后是不会立马执行的
var a = {
user:"liang",
fn:function(){
console.log(this.user);
}
}
var b = a.fn;
b.bind(a);
上述代码最终并没有打印出liang,因为b改变完this指向之后并未执行
var a = {
user:"liang",
fn:function(){
console.log(this.user); //liang
}
}
var b = a.fn;
var c = b.bind(a);
console.log(c); //function() { [native code] }
c()
实际上bind方法返回的是一个修改过后的函数,我们手动执行之后就会成功打印出liang
var a = {
user:"liang",
fn:function(e,d,f){
console.log(this.user); //liang
console.log(e,d,f); //10 1 2
}
}
var b = a.fn;
var c = b.bind(a,10);
c(1,2);
同样bind也可以有多个参数,并且参数可以执行的时候再次添加,但是要注意的是,参数是按照形参的顺序进行的
以上就是对call/apply/bind作用和使用的理解