0
Posted on
Tuesday, December 01, 2020
by
醉·醉·鱼
and labeled under
javascript
最近在看ES6,看得自己快吐了。我第一次遇到这么恶心的编程语言。真的,it sucks!
一直在改动
最大的改动还是在ES6。感觉上就是吸收了很多编程语言的优势,试图加入很多东西,比如Symbol,生成器,迭代器这些在之前版本里面都没有的功能,以及对之前一些有缺陷方法的替换方法。比如,Array(3)和Array.of(3)。原始的方法里面根据输入的不同,返回的类型还不一样,完全不符合常理啊!所以有了新方法,那实现一种功能,还有好几种方法,还得记住这些方法有哪些缺陷。一个前端工程师至少有3-5年的沉淀,记住这些演变过程。OMG。无论是Ruby还是数据库系统,都没有这么激进的改动,都是符合一些理论基础的,所以对之前的方法基本很少改动,一般都是在底层上面做性能优化。个人觉得,JavaScript在ES6之前就不是一个成熟完备的语言。
疯狂的继承
单构造函数,或者编写一个类,就有N多种写法(详见高程三),每个写法还有各自的缺陷,以至于最后出了一个关键字class来解决分歧。实际上,javascript的继承关系和其他编程语言就不是一类的。这原型继承稍不留神就要出错,比如实例属性写到prototype上去...
全局变量
你定义的变量都是全局变量,所有作用域都可见,都可以修改。变量越多,你都不知道谁改了你的变量。
没有块级作用域
虽然With和Try...Catch有块级作用域,但是在For循环里面却没有,导致内部定义的局部变量在外部可以访问了,这也是为啥let的出现。
+
如果是数字,那就是加法。否则,就是转换成字符串,再拼接起来。Amazing!
var arr = [1, 2, 3] //undefined
var arr2 = [4, 5, 6]; //undefined
arr + arr2 // '1,2,34,5,6'
伪数组
执行typeof,它告诉你,数组是一个对象。
0
Posted on
Tuesday, July 28, 2020
by
醉·醉·鱼
and labeled under
CodeWar
要求
给定字母组合'DBAA’,求在所有组合中的rank。
思路
用递归法。针对第一个字母D,首字母排在D之前的有‘A','A','B'三种可能,在这三种可能下,分别有n!种排列。考虑到去重,则'AA' 和 'AA'是重复的,即有2!种重复的可能。
def listPosition(word)
# 如果word就只有一个字母,就返回1
return 1 if word.size == 1
# 对word按照字母顺序排序
sorted_chars = word.chars.sort
# 计算每个字母的顺序
p word_to_num_by_index = word.chars.map { |e| sorted_chars.index(e) }
# 去重考虑,比如有N个'A',计算所有的排列,即n!,再累乘
p k = sorted_chars.uniq.map { |e| (1..sorted_chars.count(e)).reduce(&:*) }.reduce(&:*)
# 针对第一个字母,先考虑剩下的字母所有的排列,即(n-1)!, 再乘以该字母在序列word_to_num_by_index中的序号
# 假如'DBAC',首字母为'D',在字母序列word_to_num_by_index中排3,则可能出现以'A','B','C'打头的3种情况
# 最后还需要处理k来去重
p counter = (1..(word_to_num_by_index.size-1)).inject(&:*) * word_to_num_by_index[0] / k
counter + listPosition(word[1..-1])
end
p listPosition('DBAA')
# 针对 'DBAA','D'在排序序列中排3,在以'D'打头之前有 3 * (4-1)! / 2 种可能
# 针对 'BAA','B'在排序序列中排2,在以'B'打头之前有 2 * (3-1)! / 2 种可能
# 针对 'AA','A'在排序序列中排0,在以'A'打头之前有 0 * (2-1)! / 2 种可能
# 针对 'A',只有一种可能
0
如果还需要用到实例自己的方法,变量,比如这里的name,那就需要用instance_exec,第一个v其实就是speak传入的参数,进而在传入block的word变量。
还有另外一种方法去扩展实例方法,即extend。像下面这种方法,实际上也会在singleton_class上面创建实例方法。这里需要注意的是,用到了instance_eval,这样的话,最后一段就不需要像其他each方法一样,还要写{|e| puts e.name},自动绑定到每个元素上执行了。
Posted on
Tuesday, July 14, 2020
by
醉·醉·鱼
and labeled under
ruby
最近在刷CodeWar,整理来说,比exercism.io难多了。因为选择的是快速升级,所以没有刷几道题,难度就蹭蹭蹭地往上窜,有时候发现之前一晃而过的地方,啪啪地被打脸,原来真的就是一晃而过。- eval
class A
attr_reader :x
def initialize(x)
@x = x
end
def get_binding
binding
end
end
a = A.new(1)
b = A.new(2)
eval 'p @x', a.get_binding
eval 'p @x', b.get_binding
我们可以用eval str, binding 这种方式,执行一段字符串,同时切换上下文context。我们还可以用instance_eval来实现达到同样的目的。
- instance_eval
class A
attr_reader :x
def initialize(x)
@x = x
end
def get_binding
binding
end
end
a = A.new(1)
b = A.new(2)
a.instance_eval 'p @x'
b.instance_eval 'p @x'
instance_eval 还可以执行代码块。
p a.instance_eval { @x }
p b.instance_eval { @x }
还可以单独给实例创建方法,这个方法不在class上,反而是在singleton_class上。同样的逻辑,我们也可以给class上执行instance_eval,这样创建的就是class method了。
a.instance_eval do
def speak
puts 'ya ya ya!'
end
end
a.speak
b.instance_eval do
def speak
puts 'bia bia bia!'
end
end
b.speak
p a.methods # => [:speak, :x, :get_binding, ...]
p a.class.instance_methods(false) # => [:x, :get_binding]
p a.singleton_class.instance_methods(false) # => [:speak]
- class_eval
相当比较简单,只能够在class上面执行class_eval, 创建出来的实例方法。比如在http://zhongxiao37.blogspot.com/2020/06/yield.html 中,将yield换成class_eval,context就变成了class,而不再是main了。
- instance_exec & class_exec
instance_exec 和 class_exec 相比 _eval,多了可以传入参数的功能。可以参考 https://www.saturnflyer.com/blog/the-difference-between-instanceeval-and-instanceexec
比如下面这个例子,如果不需要考虑引用实例的方法,变量,用yield就行了。
class C
attr_reader :name
def initialize(name)
@name = name
end
def build(m, &block)
self.singleton_class.define_method(m) do |v|
yield v
end
self
end
end
a = C.new('jack').build(:speak) do |word|
"says #{word}"
end
b = C.new('jane').build(:speak) do |word|
"yells #{word}"
end
p a.speak('hello')
p b.speak('bye')
class B
attr_reader :name
def initialize(name)
@name = name
end
def build(m, &block)
self.singleton_class.define_method(m) do |v|
instance_exec v, &block
end
self
end
end
a = B.new('jack').build(:speak) do |word|
"#{name} says #{word}"
end
b = B.new('jane').build(:speak) do |word|
"#{name} yells #{word}"
end
p a.speak('hello')
p b.speak('bye')
- extend
module InstanceEach
def each(&block)
self.size.times { |i| self[i].instance_eval &block }
self
end
end
t = Array.new(@cnt) { A.new('') }.extend(InstanceEach)
t.each { puts name }
0
后来,在尝试打印self的时候,发现block是在顶级作用域main里面执行的。导致的结果就是,第二次会覆盖第一次的方法定义,而且所有地方都有这个方法,无论是类方法,还是实例方法。问题到这里,就是切换context的问题了。用class_eval可以切换context到新建的类执行代码块,进而定义实例方法。
Posted on
Tuesday, June 30, 2020
by
醉·醉·鱼
and labeled under
ruby
前任留下了一个祖传代码,看着挺好的,通过一个build方法,就可以动态创建一个新的类。等到自己去实现第二个类的时候,出了问题。say方法被覆盖了。第一感觉就是,类被重新打开,然后被覆写了。参考 https://stackoverflow.com/questions/19319138/dynamically-create-a-class-inherited-from-activerecord