this

this 取什么值是在函数执行的时候确认的,不是在函数定义的时候确认的

this 的不同应用场景,this 的指向

函数在调用时,js 会默认给 this 绑定一个值,this 的值与绑定方式、调用方式和调用位置有关,this 是在运行时被绑定的。下面有几种 this 的应用场景:

  • 当作普通函数被调用
  • 作为对象的方法被调用
  • 使用 call、apply、bind
  • 监听 DOM 事件所执行的函数
  • 在 class 的方法中调用
  • 箭头函数

1.0 当作普通函数被调用

普通函数的独立调用可以称为默认绑定,指向 window

function fn() {
console.log(this);
}
fn() // window
// 定时器内部是用 apply 把 this 绑定在 window 上
// 所以定时器指向的也是 window
setTimeout(function() {
console.log(this) // window
},0)

2.0 作为对象的方法被调用

函数是通过某个对象进行调用可以称为隐式绑定,指向拥有该方法的对象

  • 如果有多个对象进行嵌套,this 指向的是调用位置,也就是第一个对象
  • 如果你把对象里的函数赋值给新的变量来调用,那么 this 指向的是新的变量
function fn() {
console.log(this);
}
var obj1 = {
name: "obj1",
fn: fn
}
obj1.fn() // obj1对象
// 如果有多个对象进行嵌套,this 指向的是调用位置,也就是第一个对象
var obj2 = {
name: "obj2",
obj1: obj1
}
obj2.obj1.fn() // obj1对象
// 如果你把对象里的函数赋值给新的变量来调用,那么 this 指向的是新的变量
var newFn = obj.fn
newFn() // window

3.0 使用 call、apply、bind

使用这种方法是对象内部不想放入该函数,然后通过绑定的方式进行调用,这种绑定可以称为显式绑定,指向方法所绑定的对象

function fn() {
console.log(this);
}
var obj = {
name: "fan",
}
fn.call(obj) // {name: "fan"}
fn.apply(obj.name) // String {"fan"}
// bind() 返回的是一个函数
var foo = fn.bind(obj)
foo() // {name: "fan"}

4.0 监听 DOM 事件所执行的函数

给 dom 添加点击事件,当用户点击后,绑定的函数被调用时,会执行回调,把函数绑定到 box 元素节点,指向的是所绑定的元素节点

var div = document.createElement('div')
div.setAttribute('id','box')
div.style.width = "100px"
div.style.height = "100px"
div.style.background = "#ccc"
document.body.appendChild(div)
var box = document.querySelector('#box')
box.onclick = function() {
console.log(this) // box节点
}

5.0 在 class 的方法中调用

class 和构造函数是一个意思,都是通过 new 关键字来实例化,实例化会创建一个全新的对象,这个对象的的原型对象会等于类的原型 fan.__proto__ === Student.prototype ,方法调用的时候,指向的是实例化出来的新对象

class Student {
constructor(name) {
this.name = name
}
sayHi() {
console.log(this);
}
}
var fan = new Student("fan")
console.log(fan) // fan 对象
fan.sayHi() // fan 对象

6.0 箭头函数

箭头函数是没有 this 的,它的 this 是通过外层作用域来决定的

var obj = {
fn: () => {
console.log(this)
}
}
obj.fn() // window

this 的规则优先级

new绑定 > 显式绑定(bind)> 隐式绑定 > 默认绑定

手写 bind 函数

// 实现 bind 函数
Function.prototype.bind1 = function(...args) {
// 获取传入的值
// const arr = Array.prototype.slice.call(arguments)
const arr = [...args]; // 获取 this (数组第一项)
const t = arr.shift() // fn1.bind(...) 中的 fn1
const self = this; // return 一个函数
return function() {
return self.apply(t, arr)
}
} function fn(a, b) {
console.log('this', this);
console.log(a, b);
return 'this is fn'
} const fn2 = fn.bind1({x: 100}, 100, 200)
const res = fn2()
console.log(res);

this 面试题

面试题一

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
}
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
person1.foo4.call(person2)(); // person2
person1.foo4().call(person2); // person1

易错解析:(箭头函数只看上层作用域)

person1.foo2.call(person2) // foo2() 是箭头函数,不适用于显示绑定的规则
person1.foo3()() // 相当于在全局调用 foo3() 返回的函数
person1.foo3.call(person2)() // 显式绑定到 person2 中调用该函数,还是返回一个函数在全局调用
person1.foo3().call(person2) // 拿到返回值再进行显式绑定,绑定的就是没有返回值的函数,相当于调用 person2 中的方法
person1.foo4.call(person2)() // 显式绑定之后调用,返回的是箭头函数,箭头函数向上层作用域找,找到的是 显式绑定的 person2
person1.foo4().call(person2) // 显式绑定之前调用,返回的箭头函数向上层作用域找,找到的是 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
person1.foo2.call(person2) // 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

解析:

person1.obj.foo1()() // obj.foo1()返回的是一个函数,这个函数会在全局执行
person1.obj.foo1.call(person2)() // 最后拿到的还是返回的函数,会在全局执行
person1.obj.foo2()() // 返回一个箭头函数,只要记住是箭头函数就往上层作用域找

最新文章

  1. 【转】推荐10款最热门jQuery UI框架
  2. iOS开发--JS调用原生OC篇
  3. ldap + kerberos 整合
  4. arcgis操作笔记-根据属性提取某区域要素
  5. Android多线程
  6. ABAP Performance Examples
  7. java.sql.SQLException: 对只转发结果集的无效操作: last
  8. hdu3072 强连通+最小树形图
  9. bug_ _java.lang.IllegalArgumentException: View not attached to window manager
  10. Custom Date tag
  11. 实现GetHashCode时要遵循的规则
  12. Integer跟int的区别(备份回忆)
  13. HTML及CSS常用颜色英文词汇
  14. 按ctrl + c 播放下一曲音乐
  15. 对java面向对象的初识
  16. Python基础——1基础
  17. 广州商学院16级软工一班&二班-第二次作业成绩
  18. 简单贪心) Repair the Wall hdu2124
  19. centos7 svn服务器的搭建
  20. 数据库链接 mybatis spring data jpa 两种方式

热门文章

  1. 路由器逆向分析------sasquatch和squashfs-tools工具的安装和使用
  2. Windows API初练手 -- 疯狂写文件代码
  3. cmake VTK visual studio 2010
  4. Ravindrababu Ravula老师的数据结构与算法
  5. 【maven】Failed to execute goal org.apache.maven.plugins:maven-site-plugin:3.3:site (default-site)
  6. android之布局优化
  7. Git 系列教程(5)- 记录每次更新到仓库
  8. Pytorch_Part4_损失函数
  9. 3D深色金属哥特3D项目工具小图标icon高清设计素材
  10. [DB] Kafka