资讯专栏INFORMATION COLUMN

关于JavaScript中访问不带有this修饰的变量的搜索顺序的理解

jeyhan / 2563人阅读

摘要:这几天因为对于中的作用域链和原型链有点混淆,当访问一个不带有修饰的变量时,我想知道它的搜索顺序,因为作用域链的链结点也是一个变量对象,那么当在这个变量对象中查找变量时会不会沿着它的原型链查找呢这样就有两种可能先查找作用域链前端的变量对象,然

这几天因为对于JavaScript中的作用域链和原型链有点混淆,当访问一个不带有this修饰的变量时,我想知道它的搜索顺序,因为作用域链的链结点也是一个变量对象,那么当在这个变量对象中查找变量时会不会沿着它的原型链查找呢?这样就有两种可能:

先查找作用域链前端的变量对象,然后再查找它的原型,然后再查找作用域链中下一个变量对象,然后再查找它的原型;

一直查找作用域链中的变量对象,直到window对象,再查找它的原型。

然而在使用with语句做实验时,发现了下面的现象,因此本篇文章是我对下面的事实作出的猜测和理解,望指正!

考察下列代码:

Object.prototype.s=10;
(function(){
    var s=25;
    var obj={};
    obj.__proto__={};
    obj.__proto__.__proto__={s:15};
    with(obj){
      console.log(s);//输出15
    }
}());

上述代码中,在Object.prototype中定义了一个属性s=10,在匿名函数中定义一个变量s=25,其中又有一个对象obj,在obj的二级原型链中定义一个属性s=15,然后,使用with将这个对象obj挂在作用域链顶端,输出s,但是它输出了15.
对此我做出的猜测是:在搜查变量中实际上是一个二维的过程而不是一维的,它构造出的二维链是这样子的:

所以上述过程中,先从obj(即作用域链顶端的变量对象开始搜查),因为obj本身没有s,则沿着obj的原型链搜查,在二级原型链中找到了s=15,从而停止搜查,返回s=15的值,故而输出15.

按照这个思路,发现所有对象的原型链都最终指向Obje.prototype,所以为了验证这个猜想,做下述实验,即删除s=15这个语句

Object.prototype.s=10;        //保留Object.prototype中的s
(function(){
    var s=25;
    var obj={};
    obj.__proto__={};
    obj.__proto__.__proto__={};//删除了s:15
    with(obj){
      console.log(s);//输出10
    }
}());

上述代码输出了10,这就是说,沿着第一个作用域链结点的原型链找,最终在Objec.prototype中找到了s,从而停止查找,那么函数中s=25没有遍历到

下面做个实验,证明确实是二维查找。
使用嵌套的with语句,在作用域链顶端挂两个对象,其中第二个对象是一个函数对象,而s正是在Function.prototype中,如果上面的猜想可行,那么应该能正确输出s,而事实上确实如此

Function.prototype.s=5;//给Funct.prototype添加s
var obj={};
var func=function(){};
(function(){
    var s=25;        //s=25  
              with(func){    //嵌套
                  with(obj){
                      console.log(s);    //输出5
                  }
                  
              }
}());

上述输出的正是5,其过程如下所示:

最后要特别说明的是,函数对象本身和函数的上下文不是同一个东西,比如上图中,我并不知道匿名函数上下文的__proto__指向哪里,但是我认为它不会指向Function.prototype,因为如果Function.prototype在匿名函数上下文的继承链中,那么下面代码应该能正常输出:

Function.prototype.s=5;//给Funct.prototype添加s
var obj={};
(function(){ 
    with(obj){
       console.log(s);    //输出????
    }
}());

也就是说,因为obj本身没有s,一直找到Object.prototype中也没有s,转而从作用域链的下一节点也即匿名函数上下文寻找,同时匿名函数中也没有s,如果Function.prototype在匿名函数上下文的继承链中,那么应该能找到s=5,但是很遗憾,上面输出的是
Uncaught ReferenceError: s is not defined
若改成下面这样则能正常输出15,因为s本身就在匿名函数的上下文中

Function.prototype.s=5;//给Funct.prototype添加s
var obj={};
(function(s=15){ //参数
    with(obj){
       console.log(s);    //输出15
    }
}());

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

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

相关文章

  • 第17部分_反射机制

    摘要:如果此对象表示非静态上下文中声明的内部类,则形参类型作为第一个参数包括显示封闭的实例。参数字段名返回此类中指定字段的对象抛出如果找不到带有指定名称的字段。 一、类的加载 1. 概述 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化 2. 加载 就是指将class文件读入内存,并为之创建一个Class对象 任何类被使用时系统都...

    trilever 评论0 收藏0
  • JavaScript正则表达式RegExp

    摘要:的正则表达式体系是参照建立的。字面量形式构造函数形式以上都是创建了一个内容为的正则表达式,其表示对一个手机号码的校验。按照给定的正则表达式进行替换,返回替换后的字符串。 正则表达式,也称规则表达式,经常使用其来完成对字符串的校验和过滤。由于正则表达式的灵活性、逻辑性和功能性都非常强大,而且 可以利用很简单的方式完成对复杂字符串的控制,所以很多程序语言都支持正则表达式。在JavaScri...

    SexySix 评论0 收藏0
  • Java 虚拟机类加载机制

    摘要:验证验证阶段的主要目的是为了确保文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。不同的虚拟机对类验证的实现可能会有所不同,但大致都会完成以下四个阶段的验证文件格式的验证元数据的验证字节码验证和符号引用验证。 原文地址 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,Thisis ...

    Dionysus_go 评论0 收藏0
  • 广州三本找Java实习经历

    摘要:广州三本大三在读,在广州找实习。这篇文章其实主要是记录一下自己的面试经历,希望大家看完之后能有所了解进入中小公司究竟需要什么水平。时间复杂度尽量低一些使用快排的,将给出的随机数做基准值返回的坐标就是了。 前言 只有光头才能变强 这阵子跑去面试Java实习生啦~~~我来简单介绍一下背景吧。 广州三本大三在读,在广州找实习。大学开始接触编程,一个非常平庸的人。 在学习编程时,跟我类似的人应...

    enali 评论0 收藏0
  • Web前端开发规范手册

    摘要:规范目的为提高团队协作效率便于后台人员添加功能及前端后期优化维护输出高质量的文档特制订此文档。 规范目的 为提高团队协作效率, 便于后台人员添加功能及前端后期优化维护, 输出高质量的文档, 特制订此文档。 文件规范 文件命名规则 文件名称统一用小写的英文字母、数字和下划线的组合,其中不得包含汉字、空格和特殊字符;命名原则的指导思想一是使得你自己和工作组的每一个成员能够方便的理解每一个...

    wua_wua2012 评论0 收藏0

发表评论

0条评论

jeyhan

|高级讲师

TA的文章

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