javascript的this原理

栏目: JavaScript · 发布时间: 5年前

内容简介:不知道看了多少篇关于this的文章,很难理解,每次看到的文基本都是说明了主要么,也是我没有真正深入的去了解在《高程3》中的p182的第9行写到:

不知道看了多少篇关于this的文章,很难理解,每次看到的文基本都是说明了 this 的几个不同环境的指向。然后像记住历史一样,记在了脑子里,但这种记忆随着时间的变化会越来越分辨不清。

主要么,也是我没有真正深入的去了解 this 。真的去深入了,才发现 this 涉及的内容真的好多。

this 原理

在《高程3》中的p182的第9行写到: 在全局函数中, this 等于 window ;当函数作为某个对象的方法调用时, this 等于那个对象;匿名函数的执行环境具有全局性,所以 this 等于 window

这个概念,应该是一个前端必备的知识点吧?那么问题来了,为什么会有这样一个判定呢?

先了解一个概念:

执行上下文:也叫一个执行环境,有 全局执行环境函数执行环境 eval

每个执行环境中包含这三部分: 变量对象/活动对象,作用域链, this 的值

下面这段代码大家肯定都不陌生

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

var say = obj.say;
obj.say();  //行1 a
say();  //行2 undefined
复制代码

以上那几行代码,其实包含了两个我曾经一度没有深入理解的内容:

  1. this 是在函数运行时基于的函数的执行上下文绑定的。这个时候需要了解一下执行上下文的创建过程
  1. 对象的值都是存入内存的,而 this 跟内存里面的数据结构有关系,了解一下阮大大的 javascript 的 this 原理

对象的内存结构

我这里直接进入对象中的函数的声明与调用,以上文中的 obj 为例。

在创建执行上下文中,变量的声明的步骤依次为: 创建、初始化、赋值 。对象是一种特殊的变量,所以它也存在这3个步骤。

在初始化之后赋值之前, obj 的值为 undefined ,在赋值操作时, javascript 引擎会在内存里创建一个下面的对象,然后将这个对象的内存地址赋值给 obj 这个变量。

{
    name: 'a',
    say: function(){
        console.log(this.name)
    }
}
复制代码

若要读取 obj.name ,引擎会先拿到 obj 的内存地址,然后到这个内存地址中找到 name 这个属性的 value 属性。

当给对象赋值的是一个函数时,如上面的 obj.say 的地址,引擎会把函数单独保存在内存中,然后再将函数的地址赋值给 say 属性的 value 属性。

{
  name: {
    [[value]]: 'a'
    [[writable]]: true
    [[enumerable]]: true
    [[configurable]]: true
  },
  say: {
    [[value]]: 函数的地址
    [[writable]]: true
    [[enumerable]]: true
    [[configurable]]: true
  }
}
复制代码

大概的内存结构是这样的

javascript的this原理

这张图就可以很清晰的看出来了,因为函数是一个独立的地址,那么执行 var say = obj.say; 时,其实是把函数的地址赋值给了 say ,那么 say 就可以独立运行了,当执行 say 时,引擎可以直接拿到函数的地址而不再通过 obj 的内存了。

大概的结构是这样的

javascript的this原理

环境变量

js允许在函数体内部,引用当前环境的其他变量。

比如下面的代码,x代表着当前环境的变量。

var f = function(){
    console.log(x);
}
复制代码

那么问题来了,函数可以在不同的环境里运行,那么怎么获取到它的当前运行环境呢?所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。

var x = 'a';

var f = function(){
    console.log(this.x);
}

var obj = {
    f:f,
    x: 'b'
}

f();  //a 在全局环境下单独运行,this指代全局环境,全局的x为a
obj.f(); //b  在obj中运行,this指代obj环境,obj的x 为b

复制代码

this的绑定

常见的有两种,一种是直接在全局运行,函数内部的this直接绑定到全局,一个是通过对象调用,函数内部的this绑定到调用他的对象上。

除了常见的两种,还有两种:

1.是从一个环境传到另一个环境中,需要使用 callapply ,俗称改变this的指向。

2.不绑定。箭头函数独有,此时的this继承于作用域链的上一层,这里不免要聊一下作用域链上的this了。

call and apply

还是用上面的粒子

var x = 'a';

var f = function(){
    console.log(this.x);
}

var obj = {
    f:f,
    x: 'b'
}

f();  //a 在全局环境下单独运行,this指代全局环境,全局的x为a
f.call(obj, x); //b  
f.apply(obj, [x]); //b
复制代码

callapply 都是将this绑定到它第一个参数上。若其第一个参数不是对象,则会使用js的类型强制将第一个参数转为对象。

bind

bindcallapply 不一样的是,它会生成一个新的函数,且这个新生成的函数的 this 将永久地被绑定到了 bind 的第一个参数。具体原因还不清楚,若有知悉的望告知。

继续上面的那个粒子

var g = f.bind(obj);
var obj2 = {
    x: 'c'
}
var h = g.bind(obj2);
g(); //b
h(); //b g的this指向不会被bind改变
复制代码

箭头函数不绑定this

箭头函数不绑定this,此时的this继承于作用域链的上一层

var x = 1;
function a(){  //函数作用域上没有x,向上找,最后找到window
    setTimeout(() => {
        console.log(this.x);
    })
}
function c(){  //函数作用域上没有x,向上找,最后找到window
    setTimeout(() => {
        console.log(this.x);
    })
}
var obj = {
    x: 2, //对象的原型链上有x
    c: c
}
var obj1 = {//对象的原型链上没有x
    c: c
}
a(); //1 执行环境是全局
obj.c(); //2 执行环境是对象
obj1.c(); //undefined 执行环境是对象
复制代码

箭头函数上的call和apply,bind

由于箭头函数没有自己的this指针,通过 call() 或 apply(),bind()方法调用一个函数时,只能传递参数,不能绑定this,他们的第一个参数会被忽略。

var x = 1;
var a = (b) =>{  //函数作用域上没有x,向上找,最后找到window
    console.log(this.x + b);
}
var obj = {
    b: 2,
    x: 3
}
a.call(obj, obj.b); //3
复制代码

文末

因为写到这道题,发现自己并不清楚为什么结果是window,然后翻了下this的原理,算是做一份总结吧。 回顾一下上面的内容,因为js引擎在生成对象的内存时,obj这个变量还未被赋值,所以它的值为undefined,在es5中以明确,当bind第一个参数为undefined时,在浏览器上将执行window。

var obj = {
        say: function () {
          function _say() {
            console.log(this)
          }
          return _say.bind(obj)
        }()
      }
 obj.say() //window
复制代码

若有理解不合理的地方,还望指正。


以上所述就是小编给大家介绍的《javascript的this原理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Purely Functional Data Structures

Purely Functional Data Structures

Chris Okasaki / Cambridge University Press / 1999-6-13 / USD 49.99

Most books on data structures assume an imperative language such as C or C++. However, data structures for these languages do not always translate well to functional languages such as Standard ML, Ha......一起来看看 《Purely Functional Data Structures》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具