资讯专栏INFORMATION COLUMN

this 初探

weij / 460人阅读

摘要:经济基础决定上层建筑。以下暂不考虑严格模式。在全局执行下,无论是否在严格模式下,指向全局对象。在其他函数内部的箭头函数,这些箭头函数的保留。当一个用于在的事件监听中,指向这个元素。

经济基础决定上层建筑。

我来了

学习,记录,备忘。

感谢参考过的所有资料的作者。

嗯,能看源码的就不要看文档,能看英文文档的就不要看中文文档,能自己上手验证的就不要仅仅参考。请保持质疑。深有所感。

this 定义
A function"s this keyword behaves a little differently in JavaScript compared to other languages. It also has some differences between strict mode and non-strict mode.
In most cases, the value of this is determined by how a function is called. It can"t be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function"s this regardless of how it"s called, and ES2015 introduced arrow functions which don"t provide their own this binding (it retains the this value of the enclosing lexical context).

js 的严格模式和非严格模式有所不同。至于有什么不同,可能写个 demo 比听别人解释更直接。

大多数情况,this 的值取决于 function 是怎么被调用的。在执行期间,是不能通过赋值来设置 this 的值的,并且每次 function 的调用,this 的值也是可能不同的。

可能较为难理解的就是 this 所对应的 context 了。
以下暂不考虑严格模式。

Global Context

在全局执行 context 下,无论是否在严格模式下,this 指向全局对象。

// 浏览器中,全局对象指 window
console.log(this === window) // true
  
// 全局调用 alert
// 相当于:window.alert(this)
alert(this) // [Object Window]
Function Context
Inside a function, the value of this depends on how the function is called.

在函数内,this 取决于这个函数是如何被调用的。取决于调用这个函数的对象。

Simple call

function sayName() {
  console.log(this.name)
}

var name = "~ window ~"

var apple = {
  name: "apple"
}

var banana = {
  name: "banana"
}

// 全局调用,相当于:window.getThis(),this 指向 window
sayName() // ~ window ~

// call 改变 this 指向,this 指向 apple
sayName.call(apple) // apple

// apply 改变 this 指向,this 指向 banana
sayName.apply(banana) // banana

// 注意:
// 在使用 call/apply 来改变 this 的指向的时候,
// 如果第一个参数数据类型不是 object 时,如:7 或者 "test",内部会尝试将该值用其相关的构造函数转为对象,
// 即:7 => new Number(7), "test" => new String("test")

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

var str_1 = "test"
getThis.apply(str_1) // 原谅愚笨,这个结果不知如何描述,可测。

The bind method

ECMAScript 5 introduced Function.prototype.bind. Calling f.bind(someObject) creates a new function with the same body and scope as f, but where this occurs in the original function, in the new function it is permanently bound to the first argument of bind, regardless of how the function is being used.

调用 f.bind(someObject) 会创建一个新 function ,这个新 function 拥有函数 f 相同的主体和作用域。但是 this 的存在只出现在原始函数(f)中,在新 function 中 ,this 就被永久的绑定在 bind 的第一个参数(someObject)上,无论这个新 function 是怎么被调用。

function sayName() {
  console.log(this.name);
}
  
var apple = {
  name: "apple"
}

var banana = {
  name: "banana"
}

// bind 返回一个新函数,且新函数 this 已经绑定 apple
var appleName = sayName.bind(apple)
appleName() // apple

// 由于 appleName 已经永久绑定 apple,即使再次绑定 banana,this 依然指向 apple
var bananaName_1 = appleName.bind(banana)
bananaName_1() // apple

// 但是重新对原始函数进行 bind 绑定,会再次返回一个新函数,新函数 this 永久绑定 banana
var bananaName_2 = sayName.bind(banana)
bananaName_2() // banana
// interesting...

Arrow functions

In arrow functions, this retains the value of the enclosing lexical context"s this. In global code, it will be set to the global object.
In arrow functions, this is set to what it was when it was created (in the following example, the global object). The same applies to arrow functions created inside other functions: their this remains that of the enclosing lexical context.

箭头函数中的 this 保留 the enclosing lexical context 中 this 的值。全局环境中箭头函数 this 指向全局变量。
箭头函数中的 this 指向定义这个箭头函数时所在对象(下面的例子中,this 指向全局对象)。在其他函数内部的箭头函数,这些箭头函数的 this 保留 the enclosing lexical context 。

var getThis = (() => this)
console.log(getThis() === window)
// Create obj with a method bar that returns a function that
// returns its this. The returned function is created as 
// an arrow function, so its this is permanently bound to the
// this of its enclosing function. The value of bar can be set
// in the call, which in turn sets the value of the 
// returned function.
var obj = {bar: function() {
  var x = (() => this);
  return x;
}
};

// Call bar as a method of obj, setting its this to obj
// Assign a reference to the returned function to fn
var fn = obj.bar();

// Call fn without setting this, would normally default
// to the global object or undefined in strict mode
console.log(fn() === obj); // true

// But caution if you reference the method of obj without calling it
var fn2 = obj.bar;
// Then calling the arrow function this is equals to window because it follows the this from bar.
console.log(fn2()() == window); // true
// 此例子觉得 MDN 上讲解的很到位了
Note: if this arg is passed to call, bind, or apply on invocation of an arrow function it will be ignored. You can still prepend arguments to the call, but the first argument (thisArg) should be set to null.

注意:箭头函数的 call/apply/bind 的第一个绑定参数会被忽略。依然可以用这些方法传递后面的参数,但是第一个参数应设置为 null 。

var sayName = (() => this.name)

var apple = {
  name: "apple"
} 

var banana = {
  name: "banana"
}

// this 依然指向全局对象 window
console.log(sayName.call(apple))  // ""
console.log(sayName.bind(banana)()) // ""

As an object method

When a function is called as a method of an object, its this is set to the object the method is called on.

当一个函数作为一个对象的方法被调用时,这个函数的 this 指向调用该方法的对象。

var apple = {
  name: "apple",
  category: "fruit",
  sayName: function (){
      console.log(this.name)
  }
}

function getCategory() {
  console.log(this.category) 
}

apple.getCategory = getCategory

apple.getCategory() // fruit
apple.sayName() // apple
Similarly, the this binding is only affected by the most immediate member reference.

this 的指向只与最直接调用函数的对象有关.

var apple = {
  name: "apple",
  category: "fruit",
  sayName: function (){
      console.log(this.name)
  }
}

function madeIn() {
  console.log(this.name)
}

apple.produce = {
   name: "China",
   madeIn: madeIn
}

// this 指向最直接调用自己的对象 apple.produce
apple.produce.madeIn()
The same notion holds true for methods defined somewhere on the object"s prototype chain. If the method is on an object"s prototype chain, this refers to the object the method was called on, as if the method were on the object.

对象原型链上的方法也是如此(即: this 指向调用该方法的对象)。如果这个方法在对象的原型链上,当这个对象调用方法时,this 指向这个对象。正如对象的方法一样。

var base_methods = {
  sayName: function() {
    console.log(this.name)
  },
  getCategory: function() {
    console.log(this.category)
  }
}

var apple = Object.create(base_methods)
apple.name = "apple"
apple.category = "fruit"

apple.sayName() // apple
apple.getCategory() // fruit
// interesting...
Again, the same notion holds true when a function is invoked from a getter or a setter. A function used as getter or setter has its this bound to the object from which the property is being set or gotten.

getter/setter 中的函数调用也是如此(即: this 指向调用该方法的对象)。用作 getter/setter 的函数,this 指向用这个函数定义 get/set 属性的那个对象 。

var apple = {
  name: "apple"
}

function sayName() {
  console.log(this.name)
}

Object.defineProperty(apple, "sayName", {
  get: sayName, enumerable: true, configurable: true
})

apple.sayName // apple
// 目前对 getter/setter 的执行暂未深入了解

As a constructor

When a function is used as a constructor (with the new keyword), its this is bound to the new object being constructed.
While the default for a constructor is to return the object referenced by this, it can instead return some other object (if the return value isn"t an object, then the this object is returned).

当一个 function 作为一个 constructor 的时候,在用 new 关键字实例化一个新对象之后,funtion 的 this 指向这个新对象。
需要额外注意的是,constructor 在没有 return 的时候,默认返回一个 this 引用的对象,也可以指定 return 一个其他对象(如果 return 的不是一个对象,那么返回的是 this 引用的对象)
constructor 如何执行不做赘述。

function Person() {
  this.nature = "Person"
}

function Teacher() {
  this.nature = "Teacher"
  return {
    name: "Jane"
  }
}

function Student() {
  this.nature = "Student"
  return "Summer"
}

var a = new Person()
console.log(a.nature) // Person

var b = new Teacher()
console.log(b.nature) // undefined
console.log(b.name) // Jane

var c = new Student()
console.log(c.nature) // Student

As a DOM event handler
当一个 function 用于在 DOM 的事件监听中, this 指向这个 DOM 元素。

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

var demo = document.getElementById("demo") // html 需要自己写

demo.addEventListener("click", getThis, false) // this 指向 id="demo" 的 DOM 元素
demo.addEventListener("mouseover", function() {
  console.log(this) // this 指向 id="demo" 的 DOM 元素
}, false)

In an inline event handler

// 在 HTML 的 DOM 的内联中监听事件
// 以下的 this 指向正在监听的 DOM 本身,即:这个 button 元素


// 然而下面的写法,在内联事件内部函数体中的 this 指全局对象 window

参考

MDN

Javascript 的 this 用法

彻底理解js中this的指向,不必硬背。

你不懂JS:this与对象原型 第二章:this豁然开朗!

好记性不如烂笔头。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96319.html

相关文章

  • javscript中this初探

    摘要:是什么是一个特别的关键字,是自动定义在所有函数和全局的作用域中。是在运行时绑定的,而不是声明时绑定的。小结的指向取决于函数执行时的块级上下文 This This是什么:this是一个特别的关键字,是自动定义在所有函数和全局的作用域中。this是在运行时绑定的,而不是声明时绑定的。 为什么要有this假设不存在this关键字,那么对于一个函数根据不同上下文背景下的复用就用传入参数 ...

    Xufc 评论0 收藏0
  • Promise初探

    摘要:可以根据省份城市和区对组件设置默认值。获取省份获取城市获取区出现层嵌套的回调,这就是传说中的恶魔金字塔。相比回调嵌套,层次更分明,可读性强。基本原理学习无论是在异步操作的执行之前或执行之后,用对象的方法注册回调,回调都能一致执行。 遭遇恶魔金字塔 项目需要,封装了一个省市区的地址选择器组件。 可以根据省份id、城市id和区id对组件设置默认值。逻辑是这样的: 获取省份列表,选中默认省...

    mj 评论0 收藏0
  • Vue初探-日期选择器

    摘要:之前用用面向对象的方法实现过日期选择器,最近在练习,现在用实现一遍。需求设定实现一个日期选择器,默认显示,高亮显示。能够点击上一月下一月进行日期跳转。实现日期选择有两个比较关键的方法获取当月天数,以便循环遍历多少天。 之前用jquery用面向对象的方法实现过日期选择器,最近在练习vue,现在用vue实现一遍。发现vue用数据驱动的方式来实现,感觉还不错。 需求设定 1.实现一个日期选择...

    MAX_zuo 评论0 收藏0
  • Babylon-AST初探-代码更新&删除(Update & Remove)

    摘要:操作通常配合来完成。因为是个数组,因此,我们可以直接使用数组操作自我毁灭方法极为简单,找到要删除的,执行就结束了。如上述代码,我们要删除属性,代码如下到目前为止,的我们都介绍完了,下面一篇文章以转小程序为例,我们来实战一波。   通过前两篇文章的介绍,大家已经了解了Create和Retrieve,我们接着介绍Update和 Remove操作。Update操作通常配合Create来完成。...

    levius 评论0 收藏0
  • 初探Vector

    摘要:现在用的比较少了只作为了解一类的声明主要看的是实现了接口二构造方法构造一个空,初始大小为,其标准容量增量为零。构造一个具有指定初始容量的空,其容量增量为零。 ps:现在Vector用的比较少了,只作为了解 一、类的声明 主要看的是实现了List接口 public class Vector extends AbstractList implements List, Ran...

    suemi 评论0 收藏0
  • Javascript 元编程初探 [1]

    摘要:在这里讲到的很多也许只和程序对于工作机制的操作有关,但是作为初探也许也就足够了。一般情况下还有空字符串都会被判断成。面向特征编程面向特征编程的全称是。 引子 元编程会有如下的定义: 一种计算机程序的编写方式,它可以将其它程序(或者其本身)作为数据进行编写和操作,或者在编译时做一部分工作,在运行的时候做另外一部分工作。 在这里讲到的很多也许只和程序对于工作机制的操作有关,但是作为初...

    mcterry 评论0 收藏0

发表评论

0条评论

weij

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<