函数调用模式的区别-this

2017-09-11  本文已影响20人  YM雨蒙

前言

学习js也快有一段时间了,一直不怎么想碰this,也碰到别人写的一些关于this,一直懒得看,但是最近在学习DOM事件,写代码中经常看见this,有时候理解的不太透彻,所以决定把它研究一下,当然了,现在写的this也只是我现在的水平和参考一下大神的文章,自己结合起来,写给自己的

正文:

引自 MDN this


什么是this?

this是在执行上下文创建时确定的一个在执行过程中不可更改的变量。


正文说:严格模式与飞非严格模式会有区别,我们来看一下:

看一下严格模式下

var a = 1;
function fun() {
   'use strict';
    var a = 2;
    return this.a;
}
fun();  //报错: Cannot read property 'a' of undefined

非严格模式下:

var a = 1;
function fun() {
    var a = 2;
    return this.a;
}
fun();  // 输出 1

总结: 当函数独立调用的时候,在严格模式下它的this指向undefined,在非严格模式下,当this指向undefined的时候,自动指向全局对象(浏览器中就是window)


正文说:绝大多数情况下,函数的调用方式决定了this的值

我们来看看函数有几种调用方式

函数调用模式

//例子:
function add(i,j){
  console.log(this);  //Window
  // console.log(arguments);
  var sum = i+j;
  console.log(sum);
  (function(){
    console.log(this);  //Window
  })()
  return sum;
}
add(1,2);

从上面的例子我们看到this两次返回的都是window全局对象,匿名函数也会产生本地作用域,打印也是window按理说第一次打印应该是undefined,但是浏览器里有一条规则:

如果你传的 context 就 null 或者 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)

总结:函数调用模式this指向window的全局对象

方法调用模式

//例子:
var myNumber = {
  value: 1,
  add: function(i){
    console.log(this);  //Object{value: 1, add: ƒ}
    this.value += i;
  }
}
myNumber.add(1);

函数实现改变value的值加1,add被调用时,this的指向是Object对象

总结:方法调用模式this指向调用者

构造函数调用模式

//例子:
function Car(type,color){
  this.type = type;
  this.color = color;
  this.status = "stop";
  this.light = "off";
  console.log(this);  //打印结果是我们创建的对象
}
Car.prototype.start = function(){
  this.status = "driving";
  this.light = "on";
  console.log(this.type + " is " + this.status);
}
Car.prototype.stop = function(){
  this.status = "stop";
  this.light = "off";
  console.log(this.type + " is " + this.status);
}
var benz = new Car("benz", "black");  //Car {type: "benz", color: "black", status: "stop", light: "off"}

如果函数作为构造函数用,那么其中的this就代表它即将new出来的对象。为啥呢?new做了啥呢?new做了下面这些事:

也就是说new其实就是个语法糖,this之所以指向临时对象还是没逃脱上面说的几种情况。
总结:构造函数调用模式this指向被构造的对象

apply(call)调用模式

对于这一个,由于自己还没学到,先借鉴MDN上的,后面自己再总结一下

如果要想把this的值从一个context传到另一个,就要用call,或者apply
方法。

// 一个对象可以作为call和apply的第一个参数,并且this会被绑定到这个对象。
var obj = {a: 'Custom'};

// 这个属性是在global对象定义的。
var a = 'Global';

function whatsThis(arg) {
  return this.a;  // this的值取决于函数的调用方式
}

whatsThis();          // 直接调用,      返回'Global'
whatsThis.call(obj);  // 通过call调用,  返回'Custom'
whatsThis.apply(obj); // 通过apply调用 ,返回'Custom'

当一个函数的函数体中使用了this关键字时,通过call()方法和apply()方法调用,this的值可以绑定到一个指定的对象上。call()和apply()的所有函数都继承自Function.prototype 。

function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// 第一个参数是作为‘this’使用的对象
// 后续参数作为参数传递给函数调用
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

// 第一个参数也是作为‘this’使用的对象
// 第二个参数是一个数组,数组里的元素用作函数调用中的参数
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

使用 call 和 apply 函数的时候要注意,如果传递的 this 值不是一个对象,JavaScript 将会尝试使用内部 ToObject 操作将其转换为对象。因此,如果传递的值是一个原始值比如 7 或 'foo' ,那么就会使用相关构造函数将它转换为对象,所以原始值 7 通过new Number(7)被转换为对象,而字符串'foo'使用 new String('foo') 转化为对象,例如:

function bar() {
  console.log(Object.prototype.toString.call(this));
}

//原始值 7 被隐式转换为对象
bar.call(7); // [object Number]

参考资料

上一篇下一篇

猜你喜欢

热点阅读