1. var a = 20
  2. var obj = {
  3. a: 40,
  4. foo:() => {
  5. console.log(this.a) // 40
  6. function func() {
  7. this.a = 60
  8. console.log(this.a) // var a = 60
  9. }
  10. func.prototype.a = 50
  11. return func
  12. },
  13. foo2() {
  14. console.log(this.a) // 40
  15. function func() {
  16. this.a = 60
  17. console.log(this.a)
  18. }
  19. func.prototype.a = 50
  20. return func
  21. }
  22. }
  23. var bar = obj.foo() // 20 因为 obj.foo return了 func,函数中 this指向 window
  24. bar() // 60
  25. new bar() // 60

this 指向的场景

  1. 作为构造函数被 new 调用;
  2. 作为对象的方法使用;
  3. 作为函数直接调用;
  4. 被 call、apply、bind 调用;
  5. 箭头函数中的 this

this MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this

当一个函数被调用时,会创建一个执行上下文,
包含函数在哪里被调用(调用栈)、函数的调用方式、传入的参数等信息,
this 就是这个记录的一个属性,它会在函数执行的过程中被用到

非严格模式下 this 绑定到全局对象(浏览器下是 winodw,node 环境是 global)
严格模式下 this 绑定到 undefined (因为严格模式不允许 this 指向全局对象)

new

new 调用时, this 绑定的是新创建的构造函数的实例

  1. function Parent() {
  2. console.log(this)
  3. }
  4. var man = new Parent() // 输出: Parent 实例,this 就是 man

new的过程

用 new 调用构造函数时,会依次执行下面的操作:
创建一个新对象;
构造函数的 prototype 被赋值给这个新对象的 proto
将新对象赋给当前的 this;
执行构造函数;
如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象,如果返回的不是对象将被忽略;

this的优先级

new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定
**
new 绑定: 函数是否在 new 中调用?如果是的话 this 绑定的是新创建的对象;
显式绑定: 函数是否是通过 bind、call、apply 调用?如果是的话,this 绑定的是指定的对象;
隐式绑定: 函数是否在某个上下文对象中调用?如果是的话,this 绑定的是那个上下文对象;
如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到全局对象;

箭头函数中的 this

箭头函数没有构造函数 constructor,也不可以使用 new 调用,即不能作为构造函数,否则会报错
箭头函数不创建新的函数作用域直接沿用语句外部的作用域

  1. var a = 'hello'
  2. var obj = {
  3. a: 'world',
  4. foo: () => {
  5. console.log(this.a)
  6. }
  7. }
  8. obj.foo() // "hello"

箭头函数不为 arguments、super、this 或 new.target 定义本地绑定。
箭头函数中对 arguments、super、this 或 new.target 的任何引用都解析为当前所在词法作用域中的绑定
箭头函数所在的函数作用域

事件调用中的 this

上下文中的 this

隐式绑定 this

函数在某个上下文对象中调用,this 绑定的是那个上下文对象
this 指向调用这个方法的对象,
如果嵌套了多个对象,那么指向最后一个调用这个方法的对象

  1. var a = 'hello'
  2. var obj = {
  3. a: 'world',
  4. foo: function() {
  5. console.log(this.a) // this = obj
  6. },
  7. b:{
  8. a:'China',
  9. foo: function() {
  10. console.log(this.a)
  11. }
  12. }
  13. }
  14. obj.foo() // "world"
  15. obj.b.foo() // "China"
  16. // 特殊调用
  17. var bar = obj.b.foo // this = window
  18. bar() // "hello"

bar 方法此时是作为函数独立调用的,所以此时的场景属于默认绑定,而不是隐式绑定
这种情况和把方法作为回调函数的场景类似

如果回调函数不是箭头函数,那么其中的 this 指向的就是全局对象 window

  • 参数传递实际上也是一种隐式的赋值 ```javascript var a = ‘hello’

var obj = { a: ‘world’, foo: function() { console.log(this.a) } }

function func(fn) { fn() }

func(obj.foo)

  1. <a name="zOmmD"></a>
  2. ## call& apply
  3. 1. [Function.prototype.bind() - JavaScript | MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)
  4. 1. [Function.prototype.call() - JavaScript | MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call)
  5. 1. [Function.prototype.apply() - JavaScript | MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)
  6. 显式的修改 this的指向<br />参考 JS的显式类型 & 隐式类型
  7. ```javascript
  8. func.call(thisArg, arg1, arg2, ...) // call 参数是一个,一个的传递
  9. func.apply(thisArg, [arg1, arg2, ...]) // apply 参数是个数组

通过 call、apply、bind 可以显式的修改函数绑定 this,使其成为我们指定的对象。
第一个参数我们可以显式地绑定 this
如果 call、apply、bind 第一个参数传入的是:null 或 undefined,在调用时会被忽略,实际应用的是默认绑定规则

  1. var a = 'hello'
  2. function foo() {
  3. console.log(this.a)
  4. }
  5. foo.call(null) // 输出: "hello" this
  1. function foo(name, price) {
  2. this.name = name
  3. this.price = price
  4. }
  5. function Food(category, name, price) {
  6. foo.call(this, name, price) // call 方式调用修改 this指向
  7. // foo.apply(this, [name, price]) // apply 方式调用
  8. this.category = category
  9. }
  10. new Food('食品', '汉堡', '5块钱')
  11. // {name: "汉堡", price: "5块钱", category: "食品"}

bind

bind 是设置 this 为给定的值,并返回一个新的函数,
且在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项

  1. func.bind(thisArg[, arg1[, arg2[, ...]]])

bind返回一个新的函数

  1. var food = {
  2. name: '汉堡',
  3. price: '5块钱',
  4. getPrice: function(place) {
  5. console.log(place + this.price)
  6. }
  7. }
  8. food.getPrice('KFC') // 浏览器中输出: "KFC 5块钱"
  9. var getPrice = food.getPrice.bind({ name: '鸡腿', price: '7块钱' }, '肯打鸡 ')
  10. getPrice() // 浏览器中输出: "肯打鸡 7块钱"

bind实现原理

es5实现 bind

  1. Function.prototype.bind = function() {
  2. const _this = this;
  3. const rest = Array.prototype.slice.call(arguments);
  4. const context = rest.shift()
  5. return function() {
  6. const args = Array.prototype.slice.call(arguments);
  7. return _this.apply(context, rest.concat(args))
  8. }
  9. }

es6实现bind

  1. Function.prototype.bind = Function.prototype.bind || function(...rest) {
  2. const context = rest.shift()
  3. return (...args) => {
  4. return this.apply(context, [...rest, ...args])
  5. }
  6. }