问题来源

在 js 中,有一个疑惑的点 this, 它的指向问题,存在各种各样的,来看一下,它是如何绑定指向的吧

  • 函数在调用时,JavaScript 会默认给 this 绑定一个值
  • this 的绑定和定义的位置(编写的位置)没有关系
  • this 的绑定和调用方式以及调用的位置有关系
  • this 是在运行时,动态绑定的

this 绑定规则

1.默认绑定

注意: 严格模式下默认 this 为 undefined ,非严格模式下才是 window

作为独立函数调用时,采用的默认绑定规则:

function foo() {
  console.log(this) // window
}

function test1() {
  console.log(this) // window
  test2()
}
function test2() {
  console.log(this) // window
  test3()
}
function test3() {
  console.log(this) // window
}

test1()

function fn(fnc) {
  fnc()
}

var obj = {
  bar: function () {
    console.log(this)
  }
}

fn(obj.bar) // window 因为`obj.bar`取出的是函数,函数再被独立执行的

2.隐式绑定

作为对象方法调用时,采用隐式绑定规则

function foo() {
  console.log(this)
}

var obj = {
  bar: foo
}
obj.bar() // obj

var obj1 = {
  bar: foo
}
var obj2 = {
  obj1: obj1
}
obj2.obj1.bar() // obj1

var obj3 = {
  foo: foo
}
var bar = obj1.foo
// 取出函数,独立调用了
bar() // window

3.显示绑定

使用 call、apply、bind 进行绑定

function foo() {
  console.log(this)
}

// bind
var obj = {
  name: 'jpliu'
}
var bar = foo.bind(obj)
bar() // obj

// call/apply
foo.call(window) // window
foo.call({ name: 'jpliu' }) // {name: 'jpliu'}
foo.call(123) // Number对象的123     Number {123}
foo.apply('123') // String 对象的'123'  String {'123'}

4.new 绑定

通过 new 关键字实例化对象的时候,绑定为实例化的对象

function Person(name) {
  console.log(this) // Person {}
  this.name = name // Person { name: 'jpliu' }
}
var p = new Person('jpliu')
console.log(p)

5.内置方法

// 其实算是隐式绑定,因为这些方法都是 `window`的
window.setTimeout(function () {
  // 这里或许没这么简单,这个是回调函数,与隐式绑定,没啥关系,这里是浏览器实现的黑盒
  // 在 v8 中,有一个测试用例,模拟,是采用 call 绑定的,this是指向的 window
  // 所以这个看具体如何实现
  console.log(this) // window
}, 2000)

// 2.监听点击
const boxDiv = document.querySelector('.box')
// 隐式绑定 `boxDiv` 的`onclick` 方法触发
boxDiv.onclick = function () {
  console.log(this)
}
// `addEventListener`的`this`是隐式绑定
// 当`callback`的`this`没有显示绑定时
// 使用`bind`显示绑定`addEventListener`的`this`
boxDiv.addEventListener('click', function () {
  console.log(this)
})
boxDiv.addEventListener('click', function () {
  console.log(this)
})
boxDiv.addEventListener('click', function () {
  console.log(this)
})

// 3.数组.forEach/map/filter/find
// 可以通过第二个参数绑定回调函数的`this`
var names = ['abc', 'cba', 'nba']
names.forEach(function (item) {
  console.log(item, this)
}, 'abc')
names.map(function (item) {
  console.log(item, this)
}, 'cba')

6.规则优先级

1.默认规则的优先级最低

2.显示绑定优先级高于隐式绑定

function foo() {
  console.log(this)
}

var obj = {
  name: 'obj',
  foo: foo.bind('aaa')
}

// [String: 'aaa']
obj.foo()

3.new 绑定优先级高于隐式绑定

var obj = {
  name: 'obj',
  foo: function () {
    console.log(this)
  }
}

// new的优先级高于隐式绑定
// foo {}
var f = new obj.foo()

4.new 绑定优先级高于 bind

  • new 绑定和 call、apply 是不允许同时使用的,所以不存在谁的优先级更高
  • new 绑定可以和 bind 一起使用,new 绑定优先级更高
function foo() {
  console.log(this)
}
var bar = foo.bind('aaa')
// foo {} 不是 [String: 'aaa']
var obj = new bar()

7.规则之外

1.null 或者 undefined

// 非严格模式下
// apply/call/bind: 当传入null/undefined时, 自动将this绑定成全局对象
foo.apply(null)
foo.apply(undefined)

var bar = foo.bind(null)
bar()

// 严格模式下,就是 `null/undefined`

2.间接函数引用

var obj1 = {
  name: 'obj1',
  foo: function () {
    console.log(this)
  }
}

var obj2 = {
  name: 'obj2'
}

// 这里是取出了obj1.foo函数,赋值给了obj2.bar
// = 运算法的返回值,就是右侧的值, ob1.foo 的函数定义
// 相当于取出函数,然后独立调用, 所以指向 window
;(obj2.bar = obj1.foo)()

3.箭头函数,箭头函数是无法使用 bind/call/apply 绑定 this 的,箭头函数的 this 是定义的时候所处的上下文环境,无法变更,属于静态 this, 而不是动态绑定的

8.实践

var name = 'window'

var person = {
  name: 'person',
  sayName: function () {
    console.log(this.name)
  }
}

function sayName() {
  var sss = person.sayName
  sss() // window: 独立函数调用
  person.sayName() // person: 隐式调用
  person.sayName() // person: 隐式调用
  ;(b = person.sayName)() // window: 赋值表达式(独立函数调用), 使用 = 号运算符之后,返回了 person.sayName 这个函数方法,后续调用,跟 person 无关
}
sayName()
var name = 'window'

var person1 = {
  name: 'person1',
  foo1: function () {
    console.log(this.name)
  },
  foo2: () => console.log(this.name),
  foo3: function () {
    return function () {
      console.log(this.name)
    }
  },
  foo4: function () {
    return () => {
      console.log(this.name)
    }
  }
}
var person2 = { name: 'person2' }

// person1.foo1(); // person1(隐式绑定)
// person1.foo1.call(person2); // person2(显示绑定优先级大于隐式绑定)

// person1.foo2(); // window(不绑定作用域,上层作用域是全局)
// person1.foo2.call(person2); // window

// person1.foo3()(); // window(独立函数调用)
// person1.foo3.call(person2)(); // window(独立函数调用)
// person1.foo3().call(person2); // person2(最终调用返回函数式, 使用的是显示绑定)

// person1.foo4()(); // person1(箭头函数不绑定this, 上层作用域this是person1)
// person1.foo4.call(person2)(); // person2(上层作用域被显示的绑定了一个person2)
// person1.foo4().call(person2); // person1(上层找到person1)
var name = 'window'

function Person(name) {
  this.name = name
  ;(this.foo1 = function () {
    console.log(this.name)
  }),
    (this.foo2 = () => console.log(this.name)),
    (this.foo3 = function () {
      return function () {
        console.log(this.name)
      }
    }),
    (this.foo4 = function () {
      return () => {
        console.log(this.name)
      }
    })
}

var person1 = new Person('person1')
var person2 = new Person('person2')

person1.foo1() // person1
person1.foo1.call(person2) // person2(显示高于隐式绑定)

person1.foo2() // person1 (上层作用域中的this是person1)
person1.foo2.call(person2) // person1 (上层作用域中的this是person1)

person1.foo3()() // window(独立函数调用)
person1.foo3.call(person2)() // window
person1.foo3().call(person2) // person2

person1.foo4()() // person1
person1.foo4.call(person2)() // person2
person1.foo4().call(person2) // person1
var name = 'window'
function Person(name) {
  this.name = name
  this.obj = {
    name: 'obj',
    foo1: function () {
      return function () {
        console.log(this.name)
      }
    },
    foo2: function () {
      return () => {
        console.log(this.name)
      }
    }
  }
}

var person1 = new Person('person1')
var person2 = new Person('person2')

person1.obj.foo1()() // window
person1.obj.foo1.call(person2)() // window
person1.obj.foo1().call(person2) // person2

person1.obj.foo2()() // obj
person1.obj.foo2.call(person2)() // person2
person1.obj.foo2().call(person2) // obj

到此这篇关于JavaScript中 this 的绑定规则的文章就介绍到这了,更多相关JS this 绑定规则内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

JavaScript中 this 的绑定指向规则的更多相关文章

  1. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  2. HTML5数字输入仅接受整数的实现代码

    这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. html5简介_动力节点Java学院整理

    这篇文章主要介绍了html5简介,用于指定构建网页的元素,这些元素中的大多数都用于描述网页内容,有兴趣的可以了解一下

  5. ios 8 Homescreen webapp,关闭和打开iPad停止javascript

    我有一个适用于iPad的全屏HTML5网络应用程序,并且刚刚安装了IOS8来试用它,它一切正常,直到你关闭并重新启动iPad.一旦web应用程序重新启动javascript就会停止并加载新页面不会重新启动它.在iPad上的Safari中打开同一页面时,关闭和打开iPad会继续按预期工作.其他人注意到了这个或想出了一个解决方案吗?解决方法这似乎是我在iOS8.1.1更新中解决的.

  6. iOS 6 javascript与object.defineProperty的间歇性问题

    当访问使用较新的Object.defineProperty语法定义属性的对象的属性时,有没有其他人注意到新iOS6javascript引擎中的间歇性错误/问题?https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty我正在看到javascript失败的情况,说

  7. ios – 如何使用JSExport导出内部类的方法

    解决方法似乎没有办法将内部类函数导出到javascript.我将内部类移出并创建了独立的类,它起作用了.

  8. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

  9. ios – 内存泄漏与UIWebView和Javascript

    清楚地包含一个Javascript文件到我的HTML是使UIWebView泄漏内存.当我重复使用相同的UIWebView对象时,或者每当我有内容实例化一个新的漏洞时,会出现泄漏的事实,导致我认为必须有一些JavaScript文件被loadHTMLString处理,导致泄漏.有人知道如何解决这个问题吗?

  10. iOS应用程序的UI自动化测试如何与乐器和Javascript

    从WWDC2010视频会议中了解iOS应用程序的自动化UI测试,但没有实践.从代码项目project,我们可以有一个例子.这个问题在这里听到有涉及这个的人.任何限制?解决方法我建议从AlexWollmer开始使用thisblogpost.他创建了一个非常有用的JavaScript库:tuneup_jswithtest()函数,它允许测试分离和有用的帮助者以及为自动化仪器编写测试的断言.

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部