是函数运行时候,函数内部自动生成的一个对象,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
1.当为函数调用时
function fn() {
console.log(this) // window
}
fn()
从代码中可以看出这个时候 this 指向window, 因为 fn 挂载在 window 下,所以执行fn的是window ,所以this 是window
2.当为对象方法调用时候
当做对象方法调用时候,this 指向这个对象,所以还是有函数执行的时候才能确定this到底指向谁
function fn() {
console.log(this) // obj
}
var obj = {
test: fn
}
obj.test()
我们再来看一个例子
function fn() {
console.log(this) // obj
}
var obj = {
test: fn
}
var fn2 = obj.test
fn2()
fn2 的调用对象是Window ,虽然fn2 的方法是 obj.test, 但是执行者是window
3. 当作为构造函数使用时候
function Fn() {
console.log(this) // a
}
var a = new Fn()
这里可以看做 new 关键字,改变了this的指向, new之后都发生了什么呢,可看做以下三个步骤
- 创建一个空对象,将它的引用赋给this,继承函数的原型。
- 通过this将属性和方法添加至这个对象
- 最后返回this指向的新对象,也就是实例
这里遇到过一个小问题,当作为构造函数的时候加了 return 值
function Fn() {
return
}
// 这个时候 a 是以Fn 为构造函数的对象
//和
function Fn() {
return {}
}
var a = new Fn()
// 这个时候 a 是 空对象
如果返回值是一个引用类型,那么this指向的就是那个返回的对象,如果返回值不是一个引用类型那么this还是指向函数的实例
4. call apply bind调用
我们知道call apply可以改变this指向,来看下call apply bind的实现原理
1.call
我们看个 call 的例子
var count = 1
var obj = {
count: 2}
function addNum(num1, num2) {
return this.count + num1 + num2}
addNum(1,2) // 1 + 1 + 2 = 4
addNum.call(obj, 1,2 ) // 2 + 1 + 2 = 5
我们可以看出来call 改变了 this指向, 将函数看作是传入对象的树形,然后执行这个对象的属性就行了
Function.prototype.myCall = function(context) {
context = context || window
context.fn = this
var args = [...arguments].slice(1)// 取出除了第一个参数的剩余参数
var result = context.fn(...args)
delete context.fn
return result
}
通过myCall 再运行上面的例子
addNum.myCall(obj, 1,2)
2.apply
apply 和 call 方式类似,只是apply 参数是用数组传递的
Function.prototype.myApply = function(context) {
context = context || window
context.fn = this
var result = context.fn(...arguments[1])
delete context.fn
return result
}
3. bind
bind 要比call 和 apply 复杂一些, bind 是返回一个函数,在返回函数调用的时候用apply方法,确定好context 就可以了,bind 还可以支持 new 关键字
Function.prototype.myBind = function(context) {
context = context || window // 传入的 需要绑定的对象
var _this = this // 当前调用myBind的函数实例
var args = [...arguments].slice(1)
return function F() { // 这个时候返回一个函数
if( this.instanceof F) { // 通过new 的方式调用
return new _this(...args, ...arguments)
}
return _this.apply(context, args)
}
}
5. new 的原理及模拟
当new F() 之后会发生这几件事
- 一个对象被创建 并继承 F.prototype
- 继承F的内部属性
- 返回这个创建的对象
下面就来实现一个new ,由于关键字不能覆盖,我们使用函数方式模拟
function F() {
this.name = '123'
}
F.prototype.showName = function() {
console.log(this.name)
}
function myNew() {
// 1.第一步:创建新对象并继承 原型
var obj = new Object()
// 获取到需要继承的函数的原型对象
var F = [].shift.call(arguments)
obj.__proto__ = F.prototype
// 第二步:继承F的内部属性
F.apply(obj, arguments)
// 第三步 返回这个对象
return obj
}
// 运行上面代码返回一个 对象
myNew(F)