本文已参与「新人创作礼」活动,一起开启掘金创作之路
javascript this详解
什么是this
在javascript中,this表示对象的引用,this指向的对象并不是固定的,会根据调用的上下文(即执行时的环境)的改变而改变
this指向哪里
- 全局调用时this指向window
- 谁调用指向谁,即指向当前调用的对象
- 独立函数调用时,指向window
- 构造函数的this指向
- 箭头函数的this指向
- prototype中的this指向
1、全局调用函数时,this指向window
function point(){
console.log(this)
}
point(). // window
2、当函数属于某对象时
var obj = {
count : 0
func: function() {
console.log(this.count)
}
}
// 调用
obj.func() // 0
var fun = obj.func()
fun() // undefined
obj.func() 调用时func内部的this指向obj对象
3、fun调用时是独立于obj对象之外的,是独立函数调用,this指向window
4、构造函数中的this指向
构造函数和普通函数区别不大,主要在于调用方式,当使用new关键字调用构造函数时,往往会返回一个对象,而this就会指向这个对象,如果不返回对象,则指向构造函数
var name = 'frank';
// 当构造函数没有返回值时
let myClass = function() {
this.name = 'lily';
this.sayName = function() {
console.log('class内部的this',this.name)
}
}
// 调用实例的方法,this指向构造函数
let myObj = new myClass()
myObj.sayName() // lily
// 把实例中的function作为独立函数调用,独立函数中的this指向window
let outSay = myObj.sayName
outSay()
console.log('外部的this',myObj.name) // lily
// 当构造函数有返回值时
var name = "waite";
let myClass = function() {
this.name = "lucy",
this.sayHellow = function() {
console.log('hellow',this.name)
}
return {
name: 'sucy'
}
}
let myObj = new myClass()
// 调用实例的方法
myObj.sayHellow() // 报错,因为myObj时myClass的返回值,{name: 'sucy'},没有sayHellow方法
// 把实例方法作为独立函数调用
let func = myObj.sayHellow;
func() // 报错,同上
// 直接访问实例的this
console.log("直接访问实例的this",myObj.name) // sucy
5.箭头函数中的this指向 箭头函数不会创建自己的上下文,而是将this指向外部函数已经创建好的上下文
v
var fun = () => {
console.log(this)
}
fun() // window
let obj = {
name: "object",
print:() => {
console.log(this)
},
log: function() {
setTimeout(() => {
console.log(this)
},500)
}
}
// 当使用箭头函数作为对象的方法时,this指向window
obj.print() // window
obj.log() // obj本身
6.prototype中的this 在对象的原型上定义方法时的this和在对象中定义的方法差不多,主要看调用形式
var name = "window"
var myClass = function() {
this.name = 'prototype',
this.insetFun = function() {
console.log('inset',this.name)
}
}
myClass.prototype.protoFun = function() {
console.log('proto',this.name)
}
var myObj = new myClass()
// 实例调用
myObj.insetFun() // prototype
myObj.protoFun() // prototype
// 独立函数调用
var fun1 = myObj.insetFun;
var fun2 = myObj.protoFun;
fun1() // window
fun2() // window
this的绑定方式
1、隐式绑定 2、显式绑定 3、new绑定
1、隐式绑定
this的隐式绑定是指谁调用就指向谁,自动搜寻上下文 最外层的this指向window对象 孤立函数中的this指向的是window
2、显式绑定
显式绑定的优先级大于隐式绑定,常用来强行改变this指向 常用的显示绑定方法有bind,call,apply
call,apply,bind在使用上的区别
var year = '2022';
function getDate(month, day) {
console.log(this.year +'-' + month + "-" + day)
}
var obj = {
year: "2021",
}
getDate.call(null, 3, 8) // 2022-3-8
getDate.call(obj, 3, 8) // 2021-3-8
getDate.apply(obj,[6, 8]) // 2021-6-8
getDate.bind(obj)(9, 8) // 2021-6-8
1、bind
bind使用时返回一个新的函数,bind的参数是this将要指向的对象,调用bind返回的函数时传递原函数的参数
bind传参问题
let newThis = {
name: "newThis",
}
function sayHellow (greet1, greet2){
console.log(this.name + "," + greet1 +"、" + greet2)
}
let greet = sayHellow.bind(newThis, "morning",'afternoon')
greet("evening") // 输出 newThis,morning,afternoon
调用bind时传入的参数会拼接在bind返回函数的参数之前一起传给返回函数,多余的参数不起作用
那么怎么手写实现一个bind呢
Function.prototype.mtbind = function (context = window) {
let fn = this //this指代调用bind的函数
// 保存参数,调用bind时返回的参数
let args = arguments.slice(1)
let bind = function (){
// bind的返回函数
// 存储调用返回函数时的参数
let bindargs = [...arguments]
return fn.apply(context,[...args,...bindargs])
}
return bind
}
2、call
call使用时是参数形式是第一个参数是this将要指向的对象,之后函数参数逐个添加
怎么实现一个call呢
Function.prototype.mycall = function (context = window) {
context.fn = this. // this指代当前调用mycall的函数
let args = [...arguments].slice(1). // 取出第一个参数之后的所有参数
let res = context.fn(...args) / 调用函数并传递参数得到执行结果
delete context.fn // 删除context上的fn函数
return res // 返回执行结果
}
3、apply
apply函数只有两个参数,第一个参数是this将要指向的对象,第二个参数是数组,原函数的所有参数添加到该数组中
Function.prototype.myapply = function (context = window) {
context.fn = this
// 此处需要判断是否有第二参数
let res
if(arguments.length > 1){
let args = arguments[1]
res = context.fn(...args)
}else {
res = context.fn()
}
delete context.fn
return res
}
3、new
首先我们明确一点,使用new操作符时发生了什么
存在以下两种情况 当构造函数没有明确返回对象时,进行以下几步 1)、创建一个新的对象 2)、把构造函数的作用域赋给当前对象(this即指向当前对象) 3)、执行构造函数中的代码,把构造函数的属性赋给当前对象 4)、返回当前对象
当构造函数有return 一个对象时,发生以下几步
1)、把构造函数的this指向返回值Object 2)、返回该Object
// 当构造函数没有返回值时
let myClass = function(name,age,family){
this.name = name;
this.age = age;
this.family = family;
}
let pasonA = new myClass("axion",18,"上海")
console.log(pasonA)
// 输出 {
"name": "axion",
"age": 18,
"family": "上海"
}
// 当构造函数有返回值时
this.name = name;
this.age = age;
this.family = family;
return {
color: "yellow"
}
}
let pasonA = new myClass("axion",18,"上海")
console.log(pasonA)
// 输出 { color: "yellow"}