最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 【译】为什么 (0, obj.prop)() 不是一个方法调用(js的内置数据结构Reference)

    正文概述 掘金(吃山鬼的神仙)   2021-02-20   658

    文章来源

    Why is (0,obj.prop)() not a method call?

    正文

    这篇博文探讨了references, 一种机制用在ECMAscript语言规范中解释一下两种语法区别

    obj.prop()
    (0, obj,prop)()
    

    方法调用(Method calls) vs 函数调用(Function calls)

    思考下面的对象

    var obj = {
    	getThis: function () {
            "use strict";
            retutn this;
        }    	
    }
    

    如果你执行obj.getThis, 那你得到一个方法调用(Method call), this指向储存方法的对象

    > obj.getThis() === obj;
    true 
    

    如果你把obj.getThis存储在一个变量里面,那么你在执行一个函数调用(Function call)

    > var func = obj.getThis;
    > func()
    undefined // use strict模式下禁止指向全局对象
    

    如果你用逗号的话会有相同的效果,就像这样

    (expr1, expr2) === expr2
    

    就是,如果两个表达式被求值了,那整个表达式执行的结果就是expr2

    如果你运行逗号操作符在执行obj.getThis之前, 你依然是在执行一个函数调用(Function call)

    > (0, obj,getThis)()
    undefined
    

    第一个操作数是什么都没有关系,这里使用0是因为它比较短, 我希望很多JS工程师回去优化并且消除第一个操作符的求值

    当然,只使用括号不会改变任何事情

    > (obj.getThis)() === obj
    true
    

    所以,到底发生了什么? 这个答案在于 references

    References 一种数据结构在ECMAScript规范中

    References 是一种在ECMAScript语言规范中内部使用的数据结构, 一个reference包括3个部分

    • Basic Value(基础值): undefined, a primitive value(原始值,原始类型),a object(一个对象) or a environment record(一个环境记录, 在函数执行的时候会生成词法环境Lexical Environment, 词法环境中有EnvironmentRecords这个字段用来记录环境,数据结构是一个对象) ,undefined表示这个变量还没有被求值, 通过GetBase(V)来访问, 传入一个reference V
    • Referenced name(名称): string或者是一个Symbol, 通过GetReferencedName(V)来访问,传入一个reference V
    • Strict Reference(严格模式的标志): 标识一个Reference是否在严格模式下创建, 通过IsStrictReference(V)来访问

    产生references的一些js表达式示例

    • Prototype reference: 对obj.prop在严格模式下进行求值会产生reference, (obj, 'prop', true)
    • Identifier reference: 对foo在严格模式下进行求值,(env, 'foo', true), env是一个存储了foo函数的环境记录(Environment Record)

    严格模式的标记是必要的,因为某些操作在严格模式下会导致异常,但是在宽松模式(sloppy mode)下是隐性的失败(fail silently), 比如 给一个未初始化的变量赋值,在宽松模式下会创建一个全局变量,在严格模式下会抛错误ReferenceError

    这里是references的其中2个操作

    • GetValue(V) 如果V是一个value,那么返回的结果就是V,如果V是一个reference,那么结果是指向reference的一个value,这种reference转换成reference value的操作叫做dereferenceing(解除引用)
    • PutValue(V, W)把value值W写入reference V
    • GetThisValue(V)只会在V是一个Prototype Reference的时候运行, 对于normal reference, 它返回base value, 对于通过super创建的references, 它返回他们拥有的附加组件(additional component)thisValue(which is needed for super property references)

    References的一些例子

    现在我们准备去理解之前的例子

    下面的表达式产生一个reference

    obj.getThis
    

    如果你函数调用(Function call)这个reference ref那么this会设置为GetThisValue(ref)

    如果你用括号包裹obj.getThis, 什么都不会改变,括号只是在句法上对食物进行分组,不会影响如何求值(它们不是操作符),这就是为什么,下面的表达式依然是一个reference

    (obj.getThis)
    

    如果你把obj.getThis返回的reference赋值给一个变量,那么reference会被dereference

    var func = obj.getThis;
    

    换句话说,保存在func上的是一个function, 而不是一个reference, 在语法标准(Lanaguage spec)中赋值运算符通过GetValue()把references引用转化为值

    逗号运算符同样可以dereferences其操作数(operands), 思考这个表达式

    (0, obj.getThis)
    

    逗号操作符使用GetValues()去取保结果上的每一个操作数都是被解除引用(dereferenced)的如果是一个reference

    References and bind()

    References是临时的这就是为什么你需要使用bind如果你希望在一个回调中返回一个方法(method)

    var log = console.log.bind(console);
    log('hello')
    

    如果你简单的操作

    var log = console.log;
    

    那么receiver(this)会丢失,因为console.log解除引用(dereferenced)在保存为log变量之前

    References 在实际代码中

    Babel使用逗号操作符避免函数调用Function call被转换为方法调用Method call

    思考在ES6模块示例

    import { func } from 'some_module';
    
    func()
    

    Babel解析成es5代码

    'use strict'
    
    var _some_module = require('some_module');
    
    (0, _some_module.func)();
    

    逗号操作符手法在最后一行保证了函数调用function call而不是方法调用method call,this值不会是_some_module

    为什么ECMAScript规范要使用References

    那些实现ECMAScript语言规范的工程师,实际上并不使用reference,这意味这reference是一个设备去帮助他们书写规范,去看看为什么, 考虑它们代表储存的位置,然后考虑下面所有操作储存的位置

    读一个值
    x
    obj.prop
    super.prop
    obj["prop"]
    
    
    运行一个函数或者方法
    
    x()
    obj.prop()
    super.prop()
    obj["prop"]()
    
    赋值
    x = 123
    obj.prop = 123
    super.prop = 123
    obj["prop"] = 123   
    
    复合赋值运算
    
    x += 5
    obj.prop += 5
    super.prop += 5
    obj["prop"] += 5
    
    typeof:
    
    typeof x
    typeof obj.prop
    typeof super.prop
    typeof obj["prop"]    
    delete:
    
    delete x
    delete obj.prop
    delete super.prop
    delete obj["prop"]
    

    因为每个储存位置都有相同的结构表示,一个reference,标准只需要去一个版本在所有的操作中,替代了多个版本(删除变量,删除具有固定健的属性,删除动态计算的属性等)

    思考

    你没有真的看到reference,当你使用js的时候,但是在有些语言中references是一等值,这可以产生有趣的应用,比如可以实现一个为你执行任务的函数。


    起源地下载网 » 【译】为什么 (0, obj.prop)() 不是一个方法调用(js的内置数据结构Reference)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元