有如下一小段代码,能否发现这里有什么问题?
const math = { sin(val){ return Math.sin(val); }, cos(val){ return Math.cos(val); }, tan(val){ const sin = this.sin ; const cos = this.cos ; return sin(val)/cos(val); }, };
一个粗心的程序员可能会这么续写
const { sin , cos , tan } = math ; console.log( tan(.5) );
这里就会报错了,因为 tan 方法内部需要的 this 对象在解构赋值的时候丢失了。要想正确使用,必须把代码写成这样的丑陋形式
let { sin , cos , tan } = math ; [ sin , cos , tan ] = [ sin , cos , tan ].map( e => e.bind(math) ); console.log( tan(.5) );
不过,其实只要在开始的时候,把这两行
const sin = this.sin ; const cos = this.cos ;
写成
const sin = math.sin ; const cos = math.cos ;
这样,就消除了隐患。显然,对于 tan 方法,动态绑定 this 对象是没有意义的,因为这个值既不会也不允许改变
总结一下就是,this 是针对动态绑定需求设计的,如果没有这个需求,就不要强行使用,哪怕表面上看上去很优雅
看到好几个同学说字面量定义本身就是种反模式,并用闭包演示如何解决持有变量
可是,闭包无法实现字面量写法提供的自注册效果,像这样
const math = { ... , cot(val){ // <-- 自注册 const tan = math.tan ; return 1/tan(val); }, }; const math = ( () => { ... ; const cot = val => 1/tan(val); return { ... , tan , cot }; // <-- 手动注册 } )();
![]() | 1 yaozeyuan93 2018-12-03 02:32:49 +08:00 ![]() 如果一定依赖 this 的话, 为什么不在初始化时直接使用呢 ```Javascript const math = { sin(val){ return Math.sin(val); }, cos(val){ return Math.cos(val); }, tan(val){ const sin = math.sin ; const cos = math.cos ; return sin(val)/cos(val); }, }; ``` |
2 sker101 2018-12-03 04:53:50 +08:00 个人认为在非对象里面用 this 没啥意义, 纯粹自找 bug 真要那么用可以 ``` const math = { sin(val){ return Math.sin(val); }, cos(val){ return Math.cos(val); }, tan(val){ const sin = this.sin ; const cos = this.cos ; return sin(val)/cos(val); }, }; const { sin, cos, tan } = math; console.log(tan.call(math, 1)); ``` |
3 zn 2018-12-03 07:50:40 +08:00 via iPhone |
4 0xff0x77 2018-12-03 08:00:19 +08:00 个人觉得 js 少了很多东西,OO 很不成熟,所以我看到的大部分 js 库都是函数编程的。 |
5 wangxiaoaer 2018-12-03 08:08:54 +08:00 const { sin , cos , tan } = math ; 说实在的,非常恶心这种写法,可能是因为 java 写多了吧。 因为这样子在阅读代码的时候根本就不知道 sin cos tan 是本文件定义的还是引入的,甚至是哪个库、哪个包都不清楚,需要去 import 里面看。 而 math.sin math.cos 就明显多了。 |
![]() | 6 Jex 2018-12-03 08:22:36 +08:00 ![]() @wangxiaoaer Java 里面 import static 可是后来才加的特性,ES 也照抄了。真的,对 JS 程序员来讲多学一点 Java 是有好处的,然后记得换一个支持 Go to definition 的 IDE。 |
![]() | 7 ChefIsAwesome 2018-12-03 08:53:48 +08:00 ![]() 生搬硬套,半桶水,以为写了个对象就叫面向对象了。 |
8 azh7138m 2018-12-03 09:14:52 +08:00 via Android @wangxiaoaer 就一个解构,C++都有的写法,为啥会恶心。 解构出来的场景大部分是个局部变量,方便优化。 |
9 zhyl 2018-12-03 09:20:23 +08:00 via Android ![]() 既然要持有相关量,为何不用闭包? |
![]() | 10 shintendo 2018-12-03 09:26:57 +08:00 我选择 const math = (function() { const sin = funtion(val) { return Math.sin(val) } cosst cos = function(val) { return Math.cos(val) } const tan = function(val) { return sin(val) / cos(val) } return {sin, cos, tan} })() |
![]() | 11 petelin 2018-12-03 09:28:54 +08:00 via iPhone 其实我根本不知道搞这些东西在干什么,尤其是写了 Go 之后。 |
![]() | 12 1010543618 2018-12-03 09:36:50 +08:00 |
![]() | 13 Jex 2018-12-03 09:41:27 +08:00 ![]() @wangxiaoaer 差点忘了黑一次 NPM,看看 lodash-modularized,就 NPM 这种风气,import module; module.method 这种写法?不存在的! https://www.npmjs.com/search?q=keywords:lodash-modularized |
![]() | 14 wly19960911 2018-12-03 09:47:54 +08:00 楼主的代码就有问题了,没有哪个语言直接定义对象来定义 this 的关系。这根本不是面向对象好不好 js 就因为对象定义就直接用对象? 你这个写法完全不符合闭包的策略 / |
![]() | 15 FakeLeung 2018-12-03 09:54:53 +08:00 用 class 来写就好懂很多。 |
16 wangxiaoaer 2018-12-03 10:13:59 +08:00 @Jex #6 static 特性用的不多,而且跟 node 这种类似,不直观,基本不用。 |
17 wangxiaoaer 2018-12-03 10:15:45 +08:00 @azh7138m #8 局部变量我是认可的,比如在一个局部函数里面,但是现在看看 npm 上的库,多少事直接在库文件根结构直接就用这中写法,美其名曰只引入需要的库,减少依赖,也是醉了。 |
18 Justin13 2018-12-03 10:50:45 +08:00 via Android 非对象,非 new 的用例为啥要用 this? 知道有坑就绕,而不是学如何从坑里爬出来。 |
![]() | 19 AV1 2018-12-03 11:16:18 +08:00 via Android 非 OO 开发时,JS 的 this 毫无使用的必要。 |
![]() | 20 wxsm 2018-12-03 11:53:57 +08:00 这就是所谓的引战帖吧。明明是 LZ 自己写的一坨翔,本来是静态方法的东西偏要加 this,还说自己写的“看上去很优雅”,啧啧。 |
![]() | 21 tommyZZM 2018-12-03 12:09:13 +08:00 正确的做法是这样。 ``` function sin(val) { return Math.sin(val); } function cos(val) { return Math.cos(val); } function tan(val) { return sin(val)/cos(val); }, const math = { sin, cos, tan }; ``` 什么`this`啊, `Function.prototype.bind`啊其实都是糟粕,能不用就不用 |
![]() | 22 tommyZZM 2018-12-03 12:14:15 +08:00 有一个很核心的思路是,尽可能降低函数对外部环境的隐式依赖,同时函数执行时不应该隐式地影响外部环境。 函数之间的关联应该是通过参数的传入联系起来的。 使用了 this 实际上就依赖了调用环境上下文,是一种不好的做法。 |
![]() | 23 no1xsyzy 2018-12-03 13:31:17 +08:00 @ChefIsAwesome 对啊,这个明显是函数式写法啊,为什么要加 this |
![]() | 24 no1xsyzy 2018-12-03 13:34:45 +08:00 “论如何同时激怒两拨人” 写一个函数式的代码,并且用上 this 并开始谈论对象。 ---- const sin = this.sin ; const cos = this.cos ; 这两行直接删去即可。 |
![]() | 25 66beta 2018-12-03 13:52:21 +08:00 via Android js 严格来讲没有“对象” class 也只是模拟,将来指不定就成了糟粕 |
![]() | 27 autoxbc OP @no1xsyzy #24 删去能运行刚好是碰运气,后面写成 const { tan } = math 不引入 sin cos 就无效了 |
29 mskf 2018-12-03 19:40:38 +08:00 你是说静态方法只能在静态方法中被引用吗 |
![]() | 30 rabbbit 2018-12-03 20:17:35 +08:00 |
31 royzxq 2018-12-03 23:08:35 +08:00 意义不明。 |
32 zealot0630 2018-12-04 06:06:21 +08:00 楼主对 OO 的理解有严重问题,OO 设计中,成员函数是放在 prototype 或 meta 里面,而不是对象里面。 |
33 cyssxt 2018-12-04 08:16:59 +08:00 via iPhone math 本来就封装好的 为什么再来一次 |
![]() | 34 nullcc 2018-12-04 08:43:42 +08:00 ![]() 说 JS this 恶心的应该是那些完全不理解 JS 对象模型的人 |
35 zealot0630 2018-12-04 19:04:44 +08:00 |