V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
cc7756789
V2EX  ›  JavaScript

js 定义属性奇怪的问题。

  •  
  •   cc7756789 · 2016-03-20 14:48:32 +08:00 · 2898 次点击
    这是一个创建于 3172 天前的主题,其中的信息可能已经有所发展或是发生改变。
    function Keygrip(keys) {
      if (arguments.length > 1) {
        console.warn('as of v2, keygrip() only accepts a single argument.')
        console.warn('set keygrip().hash= instead.')
        console.warn('keygrip() also now only supports buffers.')
      }
    
      if (!Array.isArray(keys) || !keys.length) throw new Error("Keys must be provided.")
      if (!(this instanceof Keygrip)) return new Keygrip(keys)
    
      this.keys = keys
    }
    
    
     Keygrip.prototype = {
      _hash: 'sha256',
    }
    
    
    Object.defineProperties(Keygrip.prototype, {
      // modified Keygrip.prototype.constructor's enumerable = false
      constructor: {
        value: Keygrip,
        writable: true,
        configurable: true
      },
      
      hash: {
        get: () => {
          console.log(this);  // {} 空对象
          return this._hash;  // undefined
        },
        set: (val) => {
          if (!util.supportedHash(val)) throw new Error('unsupported hash algorithm: ' + val);
          this._hash = val;   
        }
      },
     
    });
    
    >>> const KeyGrip = require('keygrip');
    >>> var s = KeyGrip(['fuck off my house', 'I never want to see you again']);
    >>> console.log(s.hash)
    {}
    undefined
    

    这是keygrip模块,我看到它原本的 constructor 只是定义了 value ,是可枚举的。手贱 fork 后修改了下,发现 get 和 set 中的 this 都是指向了一个空对象{},所以这样写的话,无论获取还是设置,都没有成功,想不明白到底是为什么。

    第 1 条附言  ·  2016-03-20 16:08:08 +08:00
    关于这个问题,随便找个教程看箭头函数对作用域的改变吧,是我在玩箭头函数之前没有去看教程 http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001438565969057627e5435793645b7acaee3b6869d1374000
    9 条回复    2016-04-07 14:33:23 +08:00
    ETiV
        1
    ETiV  
       2016-03-20 14:52:49 +08:00 via iPhone
    我擦,吓到宝宝了,居然有代码加色
    ggiiss
        2
    ggiiss  
       2016-03-20 15:31:01 +08:00
    目测是 箭头函数的坑,
    解决方法是:不用箭头函数
    cc7756789
        3
    cc7756789  
    OP
       2016-03-20 15:36:57 +08:00
    @ggiiss 我去我一着急,就一路用箭头装逼下去,现在一换过来,果然,这个坑搞得我测试了很长时间,一路以为是作用域的问题
    ggiiss
        4
    ggiiss  
       2016-03-20 15:42:21 +08:00
    @cc7756789 es6 增加了 let, => 特性后我发现之前的作用域, this 指向 问题又复杂了,泪。
    Wenwei
        5
    Wenwei  
       2016-03-20 17:51:32 +08:00
    你这箭头函数用错了。

    ```javascript
    hash: {
    get() {
    console.log(this); // {} 空对象
    return this._hash; // undefined
    },
    set(val) {
    if (!util.supportedHash(val)) throw new Error('unsupported hash algorithm: ' + val);
    this._hash = val;
    }
    },
    ```
    haozhang
        6
    haozhang  
       2016-03-20 19:18:09 +08:00
    arrow function 的 this 是来自外部域的,你调用 xxx.hash = yyy 的时候,是调用了 set 函数,但是 set 箭头函数中的 this 并不指向 xxx ,而是指向 xxx.hash = yyy 这个语句所在域的 this 。我估计这个域是个最外层域,所以 this 就变成了 undefined , get 同理。这是我的推断不知道对不对。
    cc7756789
        7
    cc7756789  
    OP
       2016-03-21 08:14:09 +08:00
    @haozhang 是的,我用 arraw 的时候没有去看 es6 ,以为和普通的匿名函数是一样的,后来才知道 es6 的 arraw 的作用域只会是调用方法的对象,而没有运行时这个坑,之所以只在 arraw 规则这样实现,我认为是为了做到向后兼容吧,普通的函数 this 运行时依旧不改变。
    morethansean
        8
    morethansean  
       2016-03-21 09:13:13 +08:00
    @cc7756789 “之所以……” function 里的 this 本来就是语言的特性之一,谈不上什么向后兼容。
    acthtml
        9
    acthtml  
       2016-04-07 14:33:23 +08:00
    keygrip 这个模块看不懂有什么用,

    只是做一个 hash 加密的话,为何参数要设置成数组,直接指定一个字符串作为秘钥不就行了。

    不明白。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3596 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 11:10 · PVG 19:10 · LAX 03:10 · JFK 06:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.