Skip to content
LYF edited this page Jun 3, 2020 · 15 revisions

第一个例子

  var property = "window property";
  function test(){
    this.property = "test object property";
  }
  test.property = "test function property";
  var fn = test.fn = test.property.fn = function(){
      alert(this.property);
  }
  fn(); // window property
  test.fn(); // test function property
  var t = new test();
  alert(t.property); // test object property

第二个例子

 var property = "window property";

 var obj = {
   property:"obj property",
   sayProperty:function(){
     alert(this.property);
   }
 }

 obj.sayProperty(); // obj property

 var fn = obj.sayProperty;

 fn();  // window property

 (obj.sayProperty)(); // obj property

第三个例子

// 如果不适用严格模式,那么两个函数内部的this都是指向window的
"use strict";

(function(){
    console.log("IIFE inner",this); // undefined
    function test(){ 
        console.log("this inner",this) // undefined
    }
    test();
})()

第四个例子(箭头函数的绑定)

箭头函数没有自己的this绑定,绑定的是父函数内的this,也就是说,只有父函数的this改变,箭头函数的this才改变,我们无法直接改变箭头函数的this指向

例如

var name = 'window'

var obj = {
  name: 'obj'
}


function parentFunction () {
  return () => console.log(this.name)
}

parentFunction()() // window

var innerFunction1 = parentFunction()

innerFunction1() // window

// 无法改变this指向
parentFunction().call(obj) // window

// 无法改变this指向
var innerFunction2 = parentFunction().bind(obj)

innerFunction2() // window

// 我们来试试改变外部函数的this指向
var innerFunction3 = parentFunction.call(obj)

// 改变了外部函数this指向,箭头函数的this也跟着变了
innerFunction3() // obj

// 再试试bind,发现也是同上
var innerFunction4 = parentFunction.bind(obj)()

innerFunction4() // obj

结论

  1. 普通函数调用,this为全局对象或是undefined
  2. 作为对象的方法,this为那个对象
  3. new 表达式,this为以该函数为原型的新创建的对象
  4. 使用 apply/call指定 this
  5. 用bind绑定固定的this
  6. 事件处理函数中的this是当前的触发事件的DOM元素(event.currentTarget)
  7. this跟代码中的位置没关系,是在执行的时候赋值的
  8. this是不会沿着变量作用域、原型链或闭包结构向上查找
  9. this只存在于函数调用期间,在变量作用域中不存在跟第7条是一个意思,这里列出来,是为了在不同的语境下理解

几个面试题

var length = 10;
    function fn(){
        alert(this.length);
    }
    var obj = {
        length:5,
        method:function( fn /* , a */ ){
            fn(); // 10
            arguments[0](); //1
            // this.method.arguments[0]();
            // console.dir(arguments);
            // console.dir(this.method.length);
            // console.dir(arguments.length);
        }
    }
    obj.method(fn);

第一个弹出10应该好理解,第二个弹出1 arguments并不是一个数组 arguments[0]这个0就相当于arguments的一个属性,跟obj[attrName]是一样的 arguments0就跟调用obj[attrName]一样,这时候fn里面的this就指向arguments了 这样就能理解后一个为什么是1了

https://segmentfault.com/q/1010000004867221?_ea=712571

function Foo() {
    getName = function () { alert (1); };
    return this;
}
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
var getName = function () { alert (4);};
function getName() { alert (5);}

//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

一道常被人轻视的前端JS面试题

运算符优先级

从这两套题,重新认识JS的this、作用域、闭包、对象

var name = 'window'

var person1 = {
  name: 'person1',
  show1: function () {
    console.log(this.name)
  },
  show2: () => console.log(this.name),
  show3: function () {
    return function () {
      console.log(this.name)
    }
  },
  show4: function () {
    return () => console.log(this.name)
  }
}
var person2 = { name: 'person2' }

person1.show1()
person1.show1.call(person2)

person1.show2()
person1.show2.call(person2)

person1.show3()()
person1.show3().call(person2)
person1.show3.call(person2)()

person1.show4()()
person1.show4().call(person2)
person1.show4.call(person2)()
var name = 'window'

function Person (name) {
  this.name = name;
  this.show1 = function () {
    console.log(this.name)
  }
  this.show2 = () => console.log(this.name)
  this.show3 = function () {
    return function () {
      console.log(this.name)
    }
  }
  this.show4 = function () {
    return () => console.log(this.name)
  }
}

var personA = new Person('personA')
var personB = new Person('personB')

personA.show1()
personA.show1.call(personB)

personA.show2()
personA.show2.call(personB)

personA.show3()()
personA.show3().call(personB)
personA.show3.call(personB)()

personA.show4()()
personA.show4().call(personB)
personA.show4.call(personB)()

this绑定的几种类型

默认绑定(非严格模式情况下,this 指向 window, 严格模式下,this指向 undefined。) 隐式绑定(如果函数调用时,前面存在调用它的对象,那么this就会隐式绑定到这个对象上) 显式绑定(函数通过 call()、apply()、bind()调用,this 指向被绑定的对象。) new 绑定(函数被 new 调用,this 指向由 new 新构造出来的这个对象。)

绑定优先级:

new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定

function globalFunction() {
  this.a = 'globalFunction';
}

let obj = {
  name: 'obj'
};
// 1、bind
const Bar = globalFunction.bind(obj);
// 2、new
const bar = new Bar();
console.log(obj.a, '--', bar.a) // obj -- globalFunction

https://juejin.im/post/5e88b054f265da47c35d7418

箭头函数无法作为构造器使用

构造函数内的this指向,是指向new操作符产生的对象的,由于箭头函数没有自己的this绑定,所以无法使用当成构造器使用它,会报TypeError

var Person = () => { this.name = name; }
var p = new Person()
VM386:1 Uncaught TypeError: Person is not a constructor
    at <anonymous>:1:9
Clone this wiki locally