JavaScript函数调用及函数上下文(this)

JavaScript中函数调用有如下4种方式:

1.作为一个函数直接被调用, func()。

   此时,在非严格模式中函数上下文this指向全局window;在严格模式中指向undefined

2.作为一个对象的方法调用,obj.func()。

  此时,上下文this指向这个调用它的对象obj

3.作为构造函数调用new Func(),实例化一个新的对象。

  此时,构造函数内部的this指向其实例化的对象。

function Func(name) {    this.name = name } let obj1 = new Func('zhangshan'); let obj2 = new Func('lisi');  obj1.name  // => 'zhangshan' obj2.name  // => 'lisi'

  当通过new关键字调用构造函数时会做如下操作:

      1).创建一个新的空对象。

      2).该对象作为this参数传递给构造函数,从而成为构造函数的函数上下文(构造函数的作用域赋给新对象,因此构造函数中              的 this指向了这个新对象)。

      3).以创建的对象为上下文执行构造函数中的代码(为新对象添加属性)

      4).新构造的对象作为new运算符的返回值
       注:
        a:如果构造函数返回一个对象,则该对象将作为整个表达式的值返回, 而传入构造函数的this将被丢弃。
        b.如果构造函数返回的是非对象类型,则忽略返回值,返回新创建的对象。
        c.每个函数都有一个原型对象(可以通过函数的prototype属性访问),该原型对象将被自动设置为通过该函数创建对象的原型。函数的原型可以被任意替换,已经构建的实例引用旧的原型,重新定义函数原型对已经构建的实例没有影响。

//new 操作过程可以用如下代码来表示  let obj = new Object(); Constructor = [].shift.call(arguments); obj.__proto__ = Constructor.prototype; let ret = Contructor.apply(obj, arguments); return typeof ret === 'object' ? ret : obj
function Func(name) {    this.name = name    return 1 }  let obj = new Func('zhangshan'); obj  // => 忽略构造函数中返回值1 还是返回对象 { name: 'zhangshan'};  function Func(name) {    this.name = name    return {      name: 'wang2'    } }  let obj2 = new Func('lisi); obj2 // => { name: 'wang2'} 

4.通过函数的apply或者call方法——func.apply(obj)或者func.call(obj)。

let obj1 = {   name: 'zhangshan' } let obj2 = {   name: 'lisi' }  function func(age) {   console.log(`${this.name} age ${age}`) }  func.call(obj1, 22) // => zhangshan age 22 func.call(obj2, 26) // => lisi age 26  //call, apply第一个参数是函数的上下文this //如果第一个参数是null,在非严格模式下this指向window, 严格模式下指向null //apply和call的用法是一样的除了call传递的参数必须一个一个列出来,apply是以数组形式传递参数 

在JavaScript中this的值会根据函数的调用方式不同而不同,有时候会使程序中this出现与预期不一致的情况。
决解方式有两种:使用es6的箭头函数 和 通过bind绑定上下文

function Ninja(){   this.whoAmI = () => this; } var ninja1 = new Ninja(); var ninja2 = {   whoAmI: ninja1.whoAmI };  ninja1.whoAmI() === ninja1 //true ninja2.whoAmI() === ninja2 //false   //在箭头函数中this等于函数定义时的上下文 //在这个例子中this是指向ninja1 //所以ninja2.whoAmI() 还是指向ninja1  function Ninja(){   this.whoAmI = function(){     return this;   }.bind(this); } var ninja1 = new Ninja(); var ninja2 = {   whoAmI: ninja1.whoAmI };  ninja1.whoAmI() === ninja1  // true ninja2.whoAmI() === ninja2  //false  //在实例化ninja1的时候, ninja1.whoAmI中的this被绑定为ninja1 //所以不管怎样的方式调用ninja1.whoAmI都是指向 ninja1  //注:此例摘录自 《JavaSript忍者秘籍第2版》
    const obj = {       func1() {         return this === obj       },       func2: () => this === window     }     console.log(obj.func1()) //true     console.log(obj.func2()) //true