Home  >  Q&A  >  body text

javascript - 理解js中的this,如果有错误欢迎纠正

有这么一段代码;

var x = 10;

//创建一个对象
var obj = {
    x: 20,
    f: function () {
        console.log(this.x);
        var that = this;
        var foo = function(){
            console.log(that.x);
        }
        foo();
    }
};
obj.f();

首先要讲清楚两个基本概念.
1.在js中一切都是对象,函数也是对象,既然是对象那就有方法。对于函数对象来说,有一个call()的方法,可以吧
2.js中变量的值,变量的值有基本类型值和引用类型值。基本类型值,像数据字符串之类的都是基本类型值。上面说过了既然在js中一切都是对象,变量也是对象,所以也有属性和方法。比如这样 var name="huangweidong";这个时候如果给它一个属性再给个值,name.age="shamate"。纵然不会出错,但是这句会被浏览器pass掉。由于js不能访问并对内存直接操作,而是通过引用。我是这么理解引用的,引用就是js和内存之间的桥梁(欢迎大神纠正错误)。变量其实就是一个有标识符或者id身份的字符串,当我们创建了一个新对象实例时(这时这个对象就会出现并保存在内存堆中)并把它保存在变量中时,变量中保存是什么不是对象的原型(保存在内存中的对象),保存的是引用也就是指针,这个指针指向内存中对象原型。所以当我们把对象复制到其他变量中时,复制的是引用也就是指针,而内存中的对象不被复制。但是基本类型值就不同了,是可以被复制的。

this不就是指向对象嘛,它的值也是一个指针,当把this复制给that时,复制的是引用也就是指针。

console.log(this.x) 要找到x就要从方法所处的对象的上下文去找,这儿我有个问题,当把对象objx属性删了之后,为什么控制台显示的是undefined,不应该是继续往上找吗。*

高洛峰高洛峰2768 days ago675

reply all(8)I'll reply

  • 迷茫

    迷茫2017-04-10 16:13:37

    var x=10;
    
    //创建一个对象
    var obj={
        var x=20,
        f:function (){
            console.log(this.x);
            var that=this;
            var foo=function(){
            console.log(that.x);}
            foo ();
        }
    };
    obj.f();

    1)上述代码在语法是有错误的,应该为

    var x=10;
    //创建一个对象
    var obj={
        x:20,
        f:function (){
            console.log(this.x);
            var that=this;
            var foo=function(){
                console.log(that.x);
            }
            foo ();
        }
    };
    obj.f();

    2)当obj.f()语句执行时,this为obj这个对象,这个对象上有属性x,故其console.log(this.x)输出为20,
    内部的foo函数执行时,因为之前that已经通过that=this赋值语句指向了obj对象,因为闭包的关系,foo函数依旧能够访问到that变量,所以console.log(that.x)
    也是20
    3)在闭包环境下,this及arguments是不会到所处函数的外层函数寻找的
    4)当obj的x属性被删除,也就是通过delete obj.x语句删除后再执行obj.f(),此时this还是obj,其上的x属性已经不存在了,所以其输出为undefined

    reply
    0
  • 天蓬老师

    天蓬老师2017-04-10 16:13:37

    题主的理解大概是最危险的那种(对了表面的80%,错了核心的20%)

    1.在js中一切都是对象,函数也是对象,既然是对象那就有方法。对于函数对象来说,有一个call()的方法

    js中并非一切都是是对象, 原始值就是原始值,不是对象(只不过装箱机制让它看上去有点像对象)

    js其实没有方法的概念,尤其是理解核心体系的时候,千万不要用方法这个概念来套JS。方法是基于类OO语言的概念(类-接口-方法),这些概念在JS里都没有,都只能模拟。
    平常说JS方法,大概是指“某个对象的某个类型是函数的属性”

    js中变量的值,变量的值有基本类型值和引用类型值。基本类型值,像数据字符串之类的都是基本类型值。上面说过了既然在js中一切都是对象,变量也是对象,所以也有属性和方法。比如这样 var name="huangweidong";这个时候如果给它一个属性再给个值,name.age="shamate"。纵然不会出错,但是这句会被浏览器pass掉

    也是对一半错一半,JS值区分原始值(说基本值也对,基本类型值也能理解)和引用值(对象),但原始值从来不是对象。 当原始值被点运算求属性值的时候,会触发自动装箱机制,被自动包装成对应的对象。name.age等价于(new String(name)).age,给它赋值不是不出错,而是就能正常运行完,但运行完以后那个自动装箱出来的String对象就被释放掉了

    console.log(this.x) 要找到x就要从方法所处的对象的上下文去找,这儿我有个问题,当把对象obj的x属性删了之后,为什么控制台显示的是undefined,不应该是继续往上找吗

    题主可能是把“原型链”和“闭包”搞混了,它们确实都“向上找”,但是完全不同的两个机制。原型链影响点运算(查找对象的属性),沿对象的原型链(__proto__)往上找。闭包影响查找不在当前闭包中声明的变量,沿lexical scope查找,也就是按照代码文面的包含关系往上找

    //嗯,想起来scope好像就是作用域,那lexical scope应该就是“词法作用域”

    reply
    0
  • 天蓬老师

    天蓬老师2017-04-10 16:13:37

    因为var x;声明的是全局对象的一个属性,全局对象不在原型链的查找范围内。

    reply
    0
  • 巴扎黑

    巴扎黑2017-04-10 16:13:37

    此时,this指的就是obj对象(已经确定了,就不会变心了),找属性肯定也是在obj上找其对应的x属性啊。x不存在,所以undefined咯。

    reply
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-10 16:13:37

    因为,你的调用方式是obj.f();,导致只会在obj的这个上下文中找

    reply
    0
  • 大家讲道理

    大家讲道理2017-04-10 16:13:37

    你这样写不报错吗?

    var obj = {
        var x = 20,
        f: function() {
            ... 
        }
    }

    在上下文往外层作用域查找的是变量,这个东西叫做冒泡机制。而不是this的指向.

    reply
    0
  • 黄舟

    黄舟2017-04-10 16:13:37

    1. {a:1,b:function(){},c:"字符串"} 对象里面都应该是这种关键字,冒号,值的形式。不应该出现赋值语句。所以那个语法错误了。值可以是数字、字符串、函数等等。

    2. this指代调用这个函数的对象。也就是obj。如果obj.func(),在func这一层有this,this就是指func。如果再有一层函数,叫func2,this就指代调用func2的对象了。用that是为了在func2里还能调用func1的值。比如:

    var obj={
        x:13;
        func:function(){
            var that=this;
            alert(that.x);//13
            alert(this.x);//13(此时this和that都代指obj)
            $.post(
                'url',
                {name:123},
                function(r){
                    alert(that.x);//that一定是obj,所以就相当于取到了obj.x,所以值是13
                    alert(this.x);//这里this代指的不管是谁,肯定不是obj了,所以取不到obj.x,值不是13。
                }
            );
        }
    }
    obj.func();
    

    reply
    0
  • PHP中文网

    PHP中文网2017-04-10 16:13:37

    猜想,题主的疑惑在这里吧:

    var x = 10;//定义全局作用域内是x
    function foo() {
        var x = 20;//定义函数foo作用域内的x
        function f() {
            console.log(x);
        }
        return f();
    }
    foo();//20    

    当你把var x = 20;删除,输出结果就变成了10。
    console.log(x)首先会在f函数内寻找x的值,如果没有找到就在foo函数内找,还没找到,就到全局作用域内找。当我们谈到执行上下文的时候一般是在讲作用域的问题,作用域分为全局作用域和函数作用域,寻找某一个变量时,在函数作用域内没找到,就会沿着作用域链到全局作用域内找。
    我想正是这一块的知识点导致了题主在obj对象内写出了var x = 20;的错误语句。

    obj.f()讲的是函数调用的问题,牵扯到this的指向,console.log(this.x)中的this指向obj,此语句表示输出对象obj的x值,obj有x则输出具体值,没有就undefined了。

    所以,我感觉题主可能是在学习这两个知识点的时候把它俩弄混了一点点……其他知识点像函数调用方式、this指向等感觉题主掌握的应该不错了,我就不在这多废话了。

    reply
    0
  • Cancelreply