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

 

你可能感兴趣的:(JavaScript,面试,JavaSript函数调用,this指向)