var a = 20
var obj = {
a: 40,
foo:() => {
console.log(this.a) // 40
function func() {
this.a = 60
console.log(this.a) // var a = 60
}
func.prototype.a = 50
return func
},
foo2() {
console.log(this.a) // 40
function func() {
this.a = 60
console.log(this.a)
}
func.prototype.a = 50
return func
}
}
var bar = obj.foo() // 20 因为 obj.foo return了 func,函数中 this指向 window
bar() // 60
new bar() // 60
this 指向的场景
- 作为构造函数被 new 调用;
- 作为对象的方法使用;
- 作为函数直接调用;
- 被 call、apply、bind 调用;
- 箭头函数中的 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 绑定的是新创建的构造函数的实例
function Parent() {
console.log(this)
}
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 调用,即不能作为构造函数,否则会报错
箭头函数不创建新的函数作用域直接沿用语句外部的作用域
var a = 'hello'
var obj = {
a: 'world',
foo: () => {
console.log(this.a)
}
}
obj.foo() // "hello"
箭头函数不为 arguments、super、this 或 new.target 定义本地绑定。
箭头函数中对 arguments、super、this 或 new.target 的任何引用都解析为当前所在词法作用域中的绑定。
箭头函数所在的函数作用域
事件调用中的 this
上下文中的 this
隐式绑定 this
函数在某个上下文对象中调用,this 绑定的是那个上下文对象
this 指向调用这个方法的对象,
如果嵌套了多个对象,那么指向最后一个调用这个方法的对象
var a = 'hello'
var obj = {
a: 'world',
foo: function() {
console.log(this.a) // this = obj
},
b:{
a:'China',
foo: function() {
console.log(this.a)
}
}
}
obj.foo() // "world"
obj.b.foo() // "China"
// 特殊调用
var bar = obj.b.foo // this = window
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)
<a name="zOmmD"></a>
## call& apply
1. [Function.prototype.bind() - JavaScript | MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)
1. [Function.prototype.call() - JavaScript | MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call)
1. [Function.prototype.apply() - JavaScript | MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)
显式的修改 this的指向<br />参考 JS的显式类型 & 隐式类型
```javascript
func.call(thisArg, arg1, arg2, ...) // call 参数是一个,一个的传递
func.apply(thisArg, [arg1, arg2, ...]) // apply 参数是个数组
通过 call、apply、bind 可以显式的修改函数绑定 this,使其成为我们指定的对象。
第一个参数我们可以显式地绑定 this
如果 call、apply、bind 第一个参数传入的是:null 或 undefined,在调用时会被忽略,实际应用的是默认绑定规则
var a = 'hello'
function foo() {
console.log(this.a)
}
foo.call(null) // 输出: "hello" this
function foo(name, price) {
this.name = name
this.price = price
}
function Food(category, name, price) {
foo.call(this, name, price) // call 方式调用修改 this指向
// foo.apply(this, [name, price]) // apply 方式调用
this.category = category
}
new Food('食品', '汉堡', '5块钱')
// {name: "汉堡", price: "5块钱", category: "食品"}
bind
bind 是设置 this 为给定的值,并返回一个新的函数,
且在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项
func.bind(thisArg[, arg1[, arg2[, ...]]])
bind返回一个新的函数
var food = {
name: '汉堡',
price: '5块钱',
getPrice: function(place) {
console.log(place + this.price)
}
}
food.getPrice('KFC') // 浏览器中输出: "KFC 5块钱"
var getPrice = food.getPrice.bind({ name: '鸡腿', price: '7块钱' }, '肯打鸡 ')
getPrice() // 浏览器中输出: "肯打鸡 7块钱"
bind实现原理
es5实现 bind
Function.prototype.bind = function() {
const _this = this;
const rest = Array.prototype.slice.call(arguments);
const context = rest.shift()
return function() {
const args = Array.prototype.slice.call(arguments);
return _this.apply(context, rest.concat(args))
}
}
es6实现bind
Function.prototype.bind = Function.prototype.bind || function(...rest) {
const context = rest.shift()
return (...args) => {
return this.apply(context, [...rest, ...args])
}
}