第一组:刘聪 JavaScript:(a==1 && a==2 && a==3)能输出true么?(转载)
JavaScript:(a==1 && a==2 && a==3)能输出true么?
有人会说,这个问题好奇葩,放在别的语言里,这要是能输出true,估计是见鬼了,但是你别说,放在js中好真有可能。最近在一个人的推特上提了一个问题:
• 问题:Can (a==1 && a==2 && a==3) ever evaluate to true?
• 答案:yes
在这篇文章中,我将解释这段代码的原理:
const a = {
num: 0,
valueOf: function() {
return this.num += 1
}
};
const equality = (a==1 && a==2 && a==3);
console.log(equality); // true
你可以打开chorme浏览器,然后打开开发者模式,在console中输入这段代码,你就可以看到输出结果([windows]: Ctrl + Shift + J [mac]: Cmd + Opt + J))(????)
有什么窍门呢?
其实也没有,能有的就是js中的两个概念:
• 隐式转换
• object的valueOf函数
隐式转换
注意:这题里面我们用的是==而不是===,在js中==代表的是等于而不是全等,那么就存在变量的隐式转化问题。这就意味着结果会比我们所期望的更多的可能性。
valueOf
JavaScript提供了一种将对象转化为原始值的方法:Object.prototype.valueOf(),默认情况下,返回正在被调用的对象。
我们举个例子:
const a = {
num: 0
}
我们可以对上述对象使用valueOf方法,他会返回一个对象。
a.valueOf();
// {num: 0}
是不是很酷,我们可以用typeOf来检测一下这个输出结果的类型:
typeof a.valueOf();
// "object"
为了让valueOf可以更方便将一个对象转化成原始值,我们可以重写他,换种说法就是我们可以通过valueOf来返回一个字符串、数字、布尔值等来代替一个对象,我们可以看以下代码:
a.valueOf = function() {
return this.num;
}
我们已经重写了原生的valueOf()方法,当我们调用valueOf的时候,他会返回a.num。那我们现在运行以下:
a.valueOf();
// 0
我们得到0了,这很合理,因为0就是赋给a.num的值。那我们可以来做几个测试:
typeof a.valueOf();
// "number"
a.num == a.valueOf()
// true
很好,但为什么这个很重要呢?
这很重要,因为当你两种不同类型的遇到相等操作符的时候,js会对其进行类型转化——它企图将操作数的类型转化为类似的。
在我们的问题中:(a==1 && a==2 && a==3)JavaScript会企图将对象转化成数字的类型,进行比较。当要转化的是一个Object的时候,JavaScript会调用valueOf()方法。
自从我们改变了valueOf()方法之后,我们能不能做到以下几点呢:
a == 0
// true
我们做到了,异常轻松。
现在我们需要做的的一点是:当我们每次去调用a的值的时候,能改变它。
幸运的是,在JavaScript中有+=符号。
+=这个运算符可以轻松的去改变一个的值,我们可以举个简单的例子:
let b = 1
console.log(b+=1); // 2
console.log(b+=1); // 3
console.log(b+=1); // 4
正如你所见的,我们每次使用加法赋值运算符,可以让我们的变量增加。
所以我们可以将这个观念用到valueOf()中。
a.valueOf = function() {
return this.num += 1;
}
当我们每次调用valueOf的时候,他会将变量增加1返回给我们。
随着这个改变,我们来运行下面的代码:
const equality = (a==1 && a==2 && a==3);
console.log(equality); // true
这就是它的工作原理。
记住下面两点:
• 使用相等操作符,js会做强制类型转化
• 我们的对象每次调用valueOf()它的值会增加1
所以比较的时候我们每次都能得到true。
• 补充第二点的运算过程
a == 1 ->
a.valueOf() == 1 ->
a.num += 1 == 1 ->
0 += 1 == 1 ->
1 == 1 -> true
a == 2 ->
a.valueOf() == 2 ->
a.num += 1 == 2 ->
1 += 1 == 2 ->
2 == 2 -> true
a == 3 ->
a.valueOf() == 3 ->
a.num += 1 == 3 ->
2 += 1 == 3 ->
3 == 3 -> true
转载自:https://juejin.im/post/5a63f9a451882573473ddba4。
第二组:徐晋 Vue.js计算属性computed与$watch
在模板中绑定表达式是非常便利的,但是它们实际上只用于简单的操作。模板是为了描述视图的结构。在模板中放入太多的逻辑会让模板过重且难以维护。这就是为什么 Vue.js 将绑定表达式限制为一个表达式。如果需要多于一个表达式的逻辑,应当使用计算属性。
基础例子
<div id="example">
a={{ a }}, b={{ b }}
</div>
var vm = new Vue({
el: '#example',
data: {
a: 1
},
computed: {
// 一个计算属性的 getter
b: function() {
// `this` 指向 vm 实例
return this.a + 1
}
}
})
这里我们声明了一个计算属性 b。我们提供的函数将用作属性 vm.b的 getter。
console.log(vm.b) // -> 2
vm.a = 2
console.log(vm.b) // -> 3
你可以打开浏览器的控制台,修改 vm。vm.b 的值始终取决于 vm.a 的值。
你可以像绑定普通属性一样在模板中绑定计算属性。Vue 知道 vm.b 依赖于 vm.a,因此当 vm.a 发生改变时,依赖于 vm.b 的绑定也会更新。而且最妙的是我们是声明式地创建这种依赖关系:计算属性的 getter 是干净无副作用的,因此也是易于测试和理解的。
计算属性 vs. $watch
Vue.js 提供了一个方法 $watch,它用于观察 Vue 实例上的数据变动。当一些数据需要根据其它数据变化时, $watch 很诱人 —— 特别是如果你来自 AngularJS。不过,通常更好的办法是使用计算属性而不是一个命令式的 $watch 回调。考虑下面例子:
<div id="demo">
{{fullName}}
</div>
var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar',
fullName: 'Foo Bar' } }) vm.$watch('firstName', function (val) { this.fullName
= val + ' ' + this.lastName }) vm.$watch('lastName', function (val) { this.fullName
= this.firstName + ' ' + val })
上面代码是命令式的重复的。跟计算属性对比效果更好:
var vm = new Vue({
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName
}
}
})
计算 setter
计算属性默认只是 getter,不过在需要时你也可以提供一个 setter:
// ...
computed: {
fullName: {
// getter
get: function() {
return this.firstName + ' ' + this.lastName
},
// setter
set: function(newValue) {
var names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1]
}
}
}
// ...
现在在调用 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstName 和 vm.lastName 也会有相应更新。
第三组:黄华英 Vue 组件之间的通信
一、非父子组件之间通信
vue中的slot分发内容
当我们在使用vue组件的时候,我们常常要像如下代码一样组合它们:
<app>
<app-header></app-header>
<app-footer></app-footer>
</app>
为了让组件可以组合,我们需要一种方式来来混合父组件的内容和子组件的模板,这个过程被叫做内容分发,我们通过<slot>元素作为原始内容的插槽的方式来实现。注意:父组件模板的内容应该就要在父组件 作用域内编译,子组件模板的内容应该在子组件作用域内编译。
<!-- 无效,应为someChildProperty是子组件的属性 -->
<child-component v-show="someChildProperty"></child-component>
Vue.component('child-component', {
// 有效,因为是在正确的作用域内
template: '<div v-show="someChildProperty">Child</div>',
data: function () {
return {
someChildProperty: true
}
}
})
在进行内容分发的时候子组件至少要有一个slot插槽,否则父组件中的内容将被丢弃。当子组件只有一个slot插槽的时候父组件的所有内容片断都将要插入子组件的slot插槽s所在DOM位子上,并替换掉slot插槽标签本身。
假设子组件模板my-component如下:
<div>
<h2>我是子组件的标题</h2>
<slot>
只有在父组件没有要分发的内容时才会显示。
</slot>
</div>
父组件模板如下:
<div>
<h1>我是父组件的标题</h1>
<my-component>
<!-- 以下内容会进行分发到子组件模板上,如果子组件的模板没有slot插槽,那么内容会被抛弃,如果有一个slot插槽那么以下内容会替换掉slot插槽所在的DOM位子 -->
<p>这是一些初始内容</p>
<p>这是更多的初始内容</p>
</my-component>
</div>
最终渲染的结果为:
<div>
<h1>我是父组件的标题</h1>
<div>
<h2>我是子组件的标题</h2>
<p>这是一些初始内容</p>
<p>这是更多的初始内容</p>
</div>
</div>
如果子组件有多个slot插槽的情况下我们可以通过具名slot将父组件的内容分别分发到子组件的对应名称的slot插槽上面。
子组件:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
父组件:
<app-layout>
<h1 slot="header">这里可能是一个页面标题</h1>
<p>主要内容的一个段落。</p>
<p>另一个主要段落。</p>
<p slot="footer">这里有一些联系信息</p>
</app-layout>
最终渲染的结果:
<div class="container">
<header>
<h1>这里可能是一个页面标题</h1>
</header>
<main>
<p>主要内容的一个段落。</p>
<p>另一个主要段落。</p>
</main>
<footer>
<p>这里有一些联系信息</p>
</footer>
</div>
第四组:王芳 互换城市
过年在携程买票的时候,偶然间发现点击城市中间的图标可以将出发城市和到达城市互换,于是我去官网找了一下实现代码,具体如下:
-
效果:点击图标互换城市
-
HTML结构:给img设置一个ID,href="javascript:;"可以阻止a标签的默认行为
-
JavaScript:
源代码:
$("#citySwap").on("click", function () {
var temp = $("#startCity").val();
$("#startCity").val($("#endCity").val());
$("#endCity").val(temp);
var tempsegnum = $("#startCity").attr("segnum");
$("#startCity").attr("segnum", $("#endCity").attr("segnum"));
$("#endCity").attr("segnum", tempsegnum);
})
第五组:王颢 XtraTreeList控件的使用中几个问题
1.repositoryItemComboBox
下拉表不能显示
通过repositoryItemComboBox的click事件,向其动态add下拉列表中的items后,点击 repositoryItemComboBox
的下拉按钮,下拉列表闪一下就消失了(不是在click事件中添加items的情况,不会出现此问题)。解 决方案,在repositoryItemComboBox
的ButtonClick
事件中,将事件源sender
转换为ComboBoxEdit
,再利用 add函数添加item,最后手动显示下拉列表,代码如下:
ComboBoxEdit combo = sender as ComboBoxEdit; combo.Properties.Items.Add(…);
combo.ShowPopup();
2.DevExpress.XtraTreeList
设置焦点函数setFocusedNode()
无效
当使用TreeListNode addedNode = treeList1.AppendNode(参数略)
,向tree中添加一个节点后,一 般想立刻使这个新添加的节点获得焦点,但此时如果直接使用treeList1.SetFocusedNode(addedNode)
则无效,可能是因为 addedNode
中不包含tree
为其分配的nodeID(猜测),解决方案是 treeList1.SetFocusedNode(treeList1.FindNodeByKeyID(stateID))
;即利用findnode
之类的函数去查询tree,找到新添加的结点,在将该节点作为SetFocusedNode
的参数,则可以完成焦点的设置。
-
DevExpress.XtraTreeList
查找结点函数FindNodeByKeyID()
无效
tree
的find
这类函数,在进行查找时,需要注意参数的类型,例如,这个函数FindNodeByKeyID()
是根据数据源里的主键进行结点查 找,即你需要给定tree对应数据源中的记录的key,如果数据源中的key是整型,而我们利用一个字符串类型作为参数的 话, FindNodeByKeyID(”100”)
将不能找到节点,正确的写法应该是FindNodeByKeyID(100)
。
WinForm设置控件焦点
winform窗口打开后文本框的默认焦点设置,进入窗口后默认聚焦到某个文本框,两种方法:
①设置tabindex
把该文本框属性里的tabIndex设为0,焦点就默认在这个文本框里了。
②Winform的Activated事件
在Form的Activated事件中添加textBox1.Focus(), 即可获得焦点。
private void Form1_Activated(object sender, EventArgs e)
{
textBox1.Focus();
}
TextBox是可以获得焦点的. 有几个前提:
- TextBox所属的窗体(Form)在可操作(Active)状态. 即用户选中了Form.
- TextBox的Enable属性,Visiable属性为True.
刚开始时原以为在Form的Load事件中添加textBox1.Focus(),测试失败
private void Form1_Load(object sender, EventArgs e)
{
textBox1.Focus();
}
因为在窗体加载时调用Focus()函数时, TextBox还未能成功的被显示到界面上。所以导致了失败。