js前端this指向规则

一言以蔽之:

  • this只和调用方式(调用者)有关
  • this是在运行时被绑定的

直接调用

当函数直接调用时,this指向的是window

js 复制代码
      function foo() {
        console.log(this)
      }

      foo()

打印结果:

object Window

隐式绑定(对象)

当函数是以对象调用时,打印的是调用的对象

js 复制代码
      function foo() {
        console.log(this)
      }

      var obj1 = {
        name: "obj1",
        foo: foo
      }

      obj1.foo()

打印结果:

{

"name": "obj1"

}

显式绑定(call/apply/bind)

分为call/apply和bind

js 复制代码
      function foo(name,age) {
        console.log(this,name,age)
      }

      var obj1 = {
        name: "obj1",
        foo: foo
      }

      foo.call(obj1,'zhangsan',18)
      foo.apply(obj1,['zhangsan',18])

      var bar = foo.bind(obj1,'zhangsan',18)
      bar()

执行结果:

new关键字绑定this

首先要清楚,new调用流程:(通过new关键字创建一个新对象的步骤是什么/构造函数时如何创建新对象的)

  • 创建一个新的对象
  • 空的对象的__proto__属性指向构造函数的Prototype属性(原型链)
  • 执行构造函数,如果构造函数中有this,则将this指向这个对象
  • 返回创建的对象
js 复制代码
      function foo(name) {
        console.log(this) // foo{}
        this.name = name // foo{name:'obj1'}
      }
      var obj1 = new foo('obj1')

优先级

new>显式>隐式

经典面试题分析1

js 复制代码
		// 错误的题目
        function foo(){
            console.log(this)
        }
        var obj1 = {
            name:'obj1',
            foo: foo
        }
        var obj2={
            name:'obj2'
        }
		// 错误原因在这里没有分号
		// 由js的自动分号插入(ASI)导致
		// 参考:https://juejin.cn/post/7325243117861519370
        (obj2.foo = obj1.foo)()

报错:

index.html:21 Uncaught TypeError: Cannot set properties of undefined (setting 'foo')

at index.html:21:19

(anonymous) @ index.html:21

正确的题目

复制代码
        function foo(){
            console.log(this)
        }
        var obj1 = {
            name:'obj1',
            foo: foo
        }
        var obj2={
            name:'obj2'
        }; // 这里有分号

        (obj2.foo = obj1.foo)()

结果:

window

这里的(obj2.foo = obj1.foo)()等价于foo(),显然属于直接调用,打印window

参考:https://juejin.cn/post/7325243117861519370

经典面试题分析2

js 复制代码
        var name = '全局window'
        var person = {
            name: 'person',
            sayName: function(){
                console.log(this.name)
            }
        }
        function sayName(){
            var fun = person.sayName
            fun() // window
            person.sayName();
            (b = person.sayName)()
        }
        sayName()

结果:

这里还有个注意点,当我们不声明name这个变量,window.name这个也是存在的,默认是一个空字符串。

并且,如果你①先运行上面这段代码,②再把var name = '全局window'这句注释,③刷新页面,会发现还是显示全局window而不是空字符串!这里的原理是:

window.name是一个所有浏览器都有的属性,表示浏览器窗口的名称,默认是一个空字符串,所有浏览器都是个空字符串。

window.name有个很有意思的跨页面特性,具体描述为:页面如果设置了window.name,即使进行了页面跳转到了其他页面,这个window.name还是会保留,刷新也是。

可以参考:https://www.zhangxinxu.com/wordpress/2019/09/window-name/

相关推荐
九转成圣几秒前
Java 性能优化实战:如何将海量扁平数据高效转化为类目字典树?
java·开发语言·json
Beginner x_u3 分钟前
链表专题:JS 实现原理与高频算法题总结
javascript·算法·链表
SmartRadio4 分钟前
ESP32-S3 双模式切换实现:兼顾手机_路由器连接与WiFi长距离通信
开发语言·网络·智能手机·esp32·长距离wifi
Front思10 分钟前
前端的.hbs
前端
laowangpython17 分钟前
Rust 入门:GitHub 热门内存安全编程语言
开发语言·其他·rust·github
我叫汪枫21 分钟前
在后台管理系统中,如何递归和选择保留的思路来过滤菜单
开发语言·javascript·node.js·ecmascript
_.Switch23 分钟前
东方财富股票数据JS逆向:secids字段和AES加密实战
开发语言·前端·javascript·网络·爬虫·python·ecmascript
软件技术NINI23 分钟前
webkit简介及工作流程
开发语言·前端·javascript·udp·ecmascript·webkit·yarn
Brendan_00123 分钟前
JavaScript的Stomp.over
开发语言·javascript·ecmascript
普通网友24 分钟前
ES6模块化、Promise、async、await、EventLoop、API接口案例_export function 与 await
前端·ecmascript·es6