开言
这篇文章的内容很简单,一句话就是“涉及this指向谁”!!!
但是涉及JavaScript的普通函数,箭头函数,WIndow,回调,Object等各种知识点
其糅杂在一起,其知识点会很混乱,我们要理性头绪!!
简单来说,普通函数可以看做管理严格的孩子,箭头函数是一个自由自在的孩子
因此,在object中,使用箭头函数很危险,其this指向很随性!!
但在回调函数中,箭头函数可以帮助我们传入当前object的this值!!
而function同时使用bind,也可以达到管理内部的this指针效果!!
这并不是语法缺陷,其可以看到代码编写中有很强大的灵活性!!!
这并不是语法缺陷,其可以看到代码编写中有很强大的灵活性!!!
这并不是语法缺陷,其可以看到代码编写中有很强大的灵活性!!!
函数式编程中,箭头函数非常重要,甚至出现高阶函数,返回一个构建的函数
在上述这些过程中,如果你单纯想用function来实现,你this绑定会非常麻烦!!
目录
一、This指针的错误理解
二、JavaScript脚本语言(动态运行)中This指针的灵活性
三、嵌套对象中this指针
四、在对象定义中警惕在箭头函数中使用this指针,不会链式传导
五、function函数在回调函数中的局限性
六、箭头函数解决参数传递问题
七、常规函数中使用bind来绑定this指针,解决回调函数中的问题
-----
一、This指针的错误理解
我们之前一直不理解this作用域,其核心是一些概念模糊,this关键是看调用方,而不是声明方。
当你看一个存在函数的声明,并不能推断出this的指向,因为JavaScript中存在函数绑定,其可能在不同的对象上调用,导致this的指向不同!!!
这么说,看this的指向,之前我们一直采用静态的眼光看,而我们现在要采用动态的眼光看!!!!
采用 动态的眼光,看调用方!!
采用 动态的眼光,看调用方!!
采用 动态的眼光,看调用方!!
二、JavaScript脚本语言(动态运行)中This指针的灵活性
记住,JavaScript是脚本语言,脚本语言的意义在于“动态运行”,像python一样
而JavaScript的语法比python复杂,同时又兼有c++这种this功能
在c++这种静态语言中,像直接定义一个 this.Attribute,是无法接受的,如下
printFunc = function() { console.log(this.FirstName) }
因为C++其要“先编译,后运行”,在编译中直接报错!!!
而JavaScript是动态语言,其属于“函数声明”,无所谓,先存着;
当在函数调用时,直接动态搜索当前调用方的this对象;
如果没有找到FirstName这个属性,其直接输出undefined值
看下面这个例子,最后Lucy原本的FirstName属性被改为_FirstName,输出Undefined值,并没有报错!!!
let Tom = { FirstName : "Tom", } let Jack = { FirstName: "Jack", } let Lucy = { _FirstName: "Lucy", } printFunc = function() { console.log(this.FirstName) // 动态绑定 this.FirstName } Tom.print = printFunc Tom.print() // Tom Jack.print = printFunc Jack.print() // Jack Lucy.print = printFunc Lucy.print() // undefined
三、嵌套对象中this指针
这里牵扯链式指向,代码如下,可以看到嵌套中输出环境是不同的
function print(){ console.log(this) } Tier = { name: "Tier", Tier1:{ name: "Tier1", print(){ console.log(this.name) } }, print(){ console.log(this.name) } } print() // Window Tier.print() // Tier Tier.Tier1.print() // Tier1z
直接构建出其链式结构,其链式结构如下,其结构和输出很明确
四、在对象定义中警惕在箭头函数中使用this指针,不会链式传导
在对象中使用箭头函数,其this指针,并不会如预期那样,指向调用对象。
在箭头函数中,并不存在“指向外侧”,而是直接指向指向Windows
const myObject = { property1: 'Hello', property2: 'World', regularFunction: function() { console.log(this.property1 + ' ' + this.property2); }, // Object中尽量不要使用箭头函数 arrowFunction: ()=> { console.log(this.property1 + ' ' + this.property2); } }; myObject.regularFunction(); // 输出:Hello World myObject.arrowFunction(); // 输出:undefined undefined
这个要警惕,其箭头函数定义的直接指向全局对象window。
同时,这里不会链式传导,不会链式传导,不会链式传导!!
哪怕内层的Object,当使用箭头函数定义时,其也会指向全局对象
下面是代码结构,当你理解这个,你会真正理解其所处的函数
const globalObject = { myObject : { property1: 'Hello', property2: 'World', regularFunction: function () { console.log(this.property1 + ' ' + this.property2); }, // 箭头函数在内侧定义 Window --> globalObject --> myObject arrowFunction: () => { console.log(this + ' ' + this); } } } globalObject.myObject.regularFunction(); // 输出:Hello World globalObject.myObject.arrowFunction(); // 输出:[Object Window] [Object Window]
五、function函数在回调函数中的局限性
我们之前提到过,在object中警惕使用箭头函数,但是真的一事无成吗箭头函数?
当然不是,在回调函数中,我们可以看看箭头函数的“威力”
现在来,什么是回调函数?相当于我们定义一个函数,交给回调器,其定义方不在我们
这里,存在一个问题,其回调函数原型中,参数已经被定义好了,这是非常关键的
我们如何传递自己的值到回调函数中?
我们如何传递自己的值到回调函数中?
我们如何传递自己的值到回调函数中?
此时就要借助 箭头函数 了!!!!
看下面这个代码,什么问题呢?
var tahoe = { resorts: ["Kirkwood","Squaw","Alpine","Heavenly","Northstar"], print: function(delay=1000) { setTimeout(function() { console.log(this.resorts.join(",")) }, delay) } } tahoe.print() // Uncaught TypeError: Cannot read properties of undefined (reading 'join')
其function中的this,其尝试获取 tahoe对象中的 ["Kirkwood","Squaw","Alpine","Heavenly","Northstar"] 这组数据
这样写很天真,因为JavaScript是动态语言,其回调函数调用这个函数,this指针被setTImeout调用时,this指向Window
自然获取不到这个数据(this并不指向tahoe),其是一个undefined,然后找不到join方法
最后自然抛出一个异常 Uncaught TypeError !!!
---
当然,这里可以使用bind解决,bind返回一个新函数,负责管理函数内部this指针的指向问题,在(七)中会提到的。
六、箭头函数解决参数传递问题
函数如下,内侧函数改用箭头函数,这里注意一下重点。
其箭头函数的作用域不限定,如下函数,其this指针直接是函数定义时的this指针 object tahoe
其箭头函数的作用域不限定,如下函数,其this指针直接是函数定义时的this指针 object tahoe
其箭头函数的作用域不限定,如下函数,其this指针直接是函数定义时的this指针 object tahoe
var tahoe = { resorts: ["Kirkwood","Squaw","Alpine","Heavenly","Northstar"], print: function(delay=1000) { setTimeout( ()=> { console.log(this.resorts.join(",")) }, delay) } } tahoe.print() // Kirkwood,Squaw,Alpine,Heavenly,Northstar
其链子如下,其传入回调函数之后,this值已经确定,不会改变!
其链子如下,其传入回调函数之后,this值已经确定,不会改变!
其链子如下,其传入回调函数之后,this值已经确定,不会改变!
但是下列代码,当使用两个箭头函数,其this指针就无法无天了,声明时就指向Window对象!!
这个前面讲过,这个一点也不难,很好理解。
var tahoe = { resorts: ["Kirkwood","Squaw","Alpine","Heavenly","Northstar"], print: (delay=1000) => { setTimeout( ()=> { console.log(this.resorts.join(",")) }, delay) } } tahoe.print() // Uncaught TypeError: Cannot read properties of undefined (reading 'join')
关于Object的回调函数,记住下面三种情况:
① ()=>{} + ()=>{this} // 回调函数传入时this指向Window
② function(){} + ()=>{this} // 回调函数传入时this指向Window
③ function(){} + function(){this} // this直接指向调用方
七、常规函数中使用bind来绑定this指针,解决回调函数中的问题
function(){ xx }.bind(),其返回一个新函数,这个其实非常关键
我们使用function.bind(this)可以解决回调函数问题
bind()的核心是帮助管理函数内部的this指针!!
bind()的核心是帮助管理函数内部的this指针!!
bind()的核心是帮助管理函数内部的this指针!!
---
如下代码,其对象中的函数可以单独拆分出来,但是此时其this指针会丢失而指向Window
此时,函数最好的方法是调用bind(),把对象重新绑定函数上,此时this就会重新指向person
const person = { name: 'John', greet: function() { console.log(`Hello, my name is ${this.name}`); } }; const greetFunction = person.greet; greetFunction(); // 输出:Hello, my name is undefined const boundGreetFunction = person.greet.bind(person); boundGreetFunction(); // 输出:Hello, my name is Johne
而下面解决我们提到的setTimeout回调函数的困惑,直接function(){xxx}.bind(this),这个this指针,很明显指向Object
此时该函数挂载到回调函数时,不会再改变了,this就指向这个Object
但是如果使用原来的Function,其传入时就是被视作一个单纯的普通函数,因为其是单独定义的!
但是如果使用原来的Function,其传入时就是被视作一个单纯的普通函数,因为其是单独定义的!
但是如果使用原来的Function,其传入时就是被视作一个单纯的普通函数,因为其是单独定义的!
var tahoe = { resorts: ["Kirkwood","Squaw","Alpine","Heavenly","Northstar"], print: function (delay=1000) { setTimeout( function () { console.log(this.resorts.join(",")) }.bind(this), delay) } } tahoe.print() // Kirkwood,Squaw,Alpine,Heavenly,Northstar
标签:function,函数,指向,作用域,Javascript,箭头,print,指针 From: https://www.cnblogs.com/qwe-asd-zxc-nm/p/17640221.html