- Published on
Some tips in Jan,2018
- Authors

- Name
- Simmzl
TODO
Object.defineproperty()margin垂直重叠字的基线深拷贝与浅拷贝未声明的变量会自动升级为全局变量的原因HTTPS与HTTP> ~ +使用rem设置元素宽高在chrome中的问题IOT 中pull-right/经纬度/地区输入小题
var obj1 = {
age: 20,
getAge: function() { return this.age; }
}
var obj2 = { age: 30 }
var getAge = obj1.getAge;
obj2.getAge = getAge;
console.log(obj1.getAge());
console.log(obj2.getAge());
Object.defineProperty()
Object.defineProperty(obj, prop, descriptor)
该方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。与常见的直接使用.和[]不同,它能通过descriptor参数定义属性的更多设定。
obj
要在其上定义属性的对象。
prop
字符串,要定义或修改的属性的名称。
descriptor/属性描述符
对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可能是可写的,也可能不是可写的。访问器描述符是由getter-setter函数对描述的属性。描述符必须是这两种形式之一;不能同时是两者。
| / | configurable | enumerable | value | writable | get | set | | ------------- | -------------| | 数据描述符 | yes | y | y | y | no | n | | 存取描述符 | y | y | n | n | y | y |
configurable
设置属性描述符descriptor是否能被修改,默认为flase;如果尝试去更改configurable:false的属性描述符内的属性则会报错:
var a = {
age: 1
};
Object.defineProperty(a, 'name' , {
configurable: false,
enumerable: false,
value: 'obj'
});
Object.defineProperty(a, 'name' , {
configurable: false,
enumerable: false,
value: 'name'
});
// "error"
// "TypeError: Cannot redefine property: name
enumerable
设置属性是否能被枚举,默认为flase,不能被枚举;
var a = {
age: 1
};
Object.defineProperty(a, 'name' , {
value: 'obj'
});
for(var key in a){
console.log(key + ': ' + a[key]);
}
// "age: 1"
console.log(Object.keys(a));
// ["age"]
// 默认情况下'name'无法被枚举出来
var a = {
age: 1
};
Object.defineProperty(a, 'name' , {
enumerable: true,
value: 'obj'
});
console.log(Object.keys(a));
// ["age", "name"]
value
默认为undefined
writable
仅当该属性的writable为true时,value才能被赋值运算符改变。默认为 false。
这样一道题:
/**
Question : please create a tool to generate Sequence
Expected to be used like:
var sequence1 = new Sequence();
sequence1.next() --> return 1;
sequence1.next() --> return 2;
in another module:
var sequence2 = new Sequence();
sequence2.next() --> 3;
sequence2.next() --> 4;
**/
实例化构造函数时,新的实例都会刷新变量,因此使用通常的方法无法实现效果。
使用Object.defineProperty,并设置writable: true的解决方法:
function Sequence() {
this.next = function() {
Sequence.number++;
console.log(Sequence.number);
return Sequence.number;
}
}
Object.defineProperty(Sequence, "number", {
value: 0,
writable: true,
enumerable: false,
configurable: false,
});
get
给属性提供 getter 的方法
set
给属性提供 setter的方法,该方法将接受唯一参数,并将该参数的新值分配给该属性。
数据描述符
var obj = {};
Object.defineProperty(obj, "demo", {
configurable: true,
enumerable: true,
writable: true,
value: 666 //数据描述符
});
存取描述符
var temp;
var obj = {};
Object.defineProperty(obj, 'demo', {
configurable: true,
enumerable: true,
get: function(){
return temp;
},
set: function(new){
temp = new;
}
});
参考:MDN web docs
margin的垂直重叠
两个或多个相邻的普通流中的块元素垂直方向上的 margin 会折叠
两个或多个
需要两个或两个以上的元素参与的行为,且折叠是相互行为,不存在 A 和 B 折叠,B 没有和 A 折叠的现象。
相邻
兄弟同级相邻
两个元素时兄弟,且二者之间没有其他元素:
<div>
<div style={{ marginBottom: "20px" }}>兄</div>
<div style={{ marginTop: "10px" }}>弟</div>
</div>
此时二者的间距为20px,产生重叠;
若兄弟间有其他元素,则不会产生重叠,二者间距30px;
<div>
<div style={{ marginBottom: "20px" }}>兄</div>
<span>第三者</span>
<div style={{ marginTop: "10px" }}>弟</div>
</div>
父子相邻
父子之间的margin-top相邻或margin-bottom相邻;
<div style={{ marginBottom: "20px" }}>
<div>111</div>
<div style={{ marginBottom: "10px" }}>子</div>
</div>
<div>NEXT</div>
此时父级的margin-bottom与子级的margin-bottom相邻,产生重叠,对于父级外界而言,只取margin-bottom最大值,即20px;
其他相邻
其实只要满足上下相邻,中间没有其他元素皆可。
普通流
相邻的浮动、inline-block、absolute定位的元素垂直方向的margin不会发生重叠;
块元素
内联元素不可设置宽高和margin。
垂直方向
只有在垂直方向才会发生重叠,水平方向不会。
margin重叠有什么意义
看起来有点奇怪的规则,其实有其现实意义。比如在我们使用p元素排版段落时,p元素默认外边距是16px,上下两个p元素不会产生中间间隔32px的现象;
<p>1111</p>
<p>2222</p>
如何使margin垂直方向不重叠
- 使用padding代替;
- 设置父级元素overflow: hidden/auto;
- 设置二者之一的元素
display: inline-block; - 设置元素浮动或者绝对定位;
注:并不是所有的BFC都可以使margin垂直方向不重叠,设置overflow、display、浮动和绝对定位只是BFC的子集;
字的基线与vertical-align
字的基线

vertical-align
默认基线对齐baseline
<div>
<span>aghGi</span>
<img class="img-sm" src="https://simmzl.cn/v2.0/img/icon.png" width=100px;>
<img src="https://simmzl.cn/v2.0/img/icon.png" width=200px;>
</div>
div {
margin: 20px;
background: #ffd800;
width: 600px;
height: 100px;
display: inline-block;
font-size: 0;
}
span {
background: rgba(0, 0, 0, 0.1);
color: #fff;
font-size: 36px;
}
默认基线对齐:

Top
把元素的顶端与其他行中最高元素的顶端对齐
.img-sm {
vertical-align: top;
}
效果:

Bottom
把元素的顶端与其他行中最低的元素的顶端对齐
span {
vertical-align: bottom;
}
效果:

Middle
把元素的中部和父元素字体的中线对齐
<div>
Father-gjly
<span>aghGi</span>
<img class="img-sm" src="https://simmzl.cn/v2.0/img/icon.png" width=100px;>
<img src="https://simmzl.cn/v2.0/img/icon.png" width=200px;>
</div>
div {
margin: 20px;
background: #ffd800;
width: 600px;
height: 200px;
display: inline-block;
font-size: 16px;;
}
span {
background: rgba(0, 0, 0, 0.1);
color: #fff;
font-size: 36px;
}
.img-sm {
vertical-align: middle;
}
效果:

text-top & text-bottom
把元素的顶端与父元素字体的顶端对齐 & 把元素的底端与父元素字体的底端对齐
text-top:

text-bottom:

百分比或者长度
- %: 使用 "line-height" 属性的百分比值来排列此元素。允许使用负值,需要设置line-height;
- 长度:正负px;
以上两种只会让元素在父元素内上下移动,向上最多到父元素顶部,向下则可以出父元素
/* 基于默认基线处上移33px和img-sm居中对齐(不精确) */
span {
vertical-align: 33px;
}

深拷贝与浅拷贝
讲的很好: 深拷贝与浅拷贝的区别,实现深拷贝的几种方法
总结一下:
基本数据类型:number,string,boolean,null,undefined五类,无需深拷贝,直接存在栈内; 引用数据类型:(Object类),有常规名值对的无序对象{a:1},数组[1,2,3],以及函数等。存储在栈中的是堆中的地址,浅拷贝只拷贝栈中地址,故需要深拷贝。
实现深拷贝:
- 递归赋值所有层级属性
- 使用
JSON.stringify()和JSON.prase()
像使用slice() / concat() / Object.assign()等只能深拷贝一层,不是真正的深拷贝。
未声明的变量会自动升级为全局变量的原因
拓展: 10分钟理解JS引擎的执行机制
~ > +
<body>
<div>
<h1>1</h1>
<p>pppppp</p>
<h1>2</h1>
<h1>3</h1>
</div>
<h1>4</h1>
</body>
p~h1 {
color: yellow;
}
p~h1选择和p元素父级相同,在p元素之后的元素,所以color为yellow的是 2 3;
<div class="foo">
<h1>1</h1>
<h1>1</h1>
<h1>1</h1>
<h1>1</h1>
<div>
<h1>2</h1>
</div>
</div>
.foo > h1 {
color: red;
}
.foo > h1选择的是.foo内的所有元素,但只选择一代,所有只有 1 才显示为红色;
<div class="foo">11</div>
<div class="boo">22</div>
<div class="boo">33</div>
.foo + .boo {
color: red;
}
.foo + .boo选择的是.foo之后紧邻且同级的.boo元素。所以红色的为22,33并不会变红。
使用rem设置元素宽高在chrome中的问题
rem是相对于html根节点的长度单位。在使用rem替代px时,常设置:html: { font-size: 62.5% }, 16px为默认字体大小,1rem = 62.5% * 16px = 10px,方便计算,所以24px可以表示为2.4rem,即2.4 * 62.5% * 16px = 24px。
但在chrome中由于浏览器默认最小字体为12px,所以导致1rem = 12px,width:10rem渲染出来是width:120px,报道出了偏差...
解决
为了避免出现10px被设置为12px的问题,可将 62.5% 改为 625%,则1rem = 625% * 16px = 100px:
html: {
font-size: 625%;
}
100px可表示为1rem, 24px可表示为.24rem
小题
var obj1 = {
age: 20,
getAge: function() { return this.age; }
}
var obj2 = { age: 30 }
var getAge = obj1.getAge;
obj2.getAge = getAge;
console.log(obj1.getAge()); // 20
console.log(obj2.getAge()); // 30
这涉及到this的引用
this是函数内部的一个特殊对象(或this引用)--它引用的是函数据以执行的环境对象。(来源于JavaScript高级程序设计)
this引用是一种在JavaScript的代码中随时都可以使用的只读变量。 this引用,引用(指向)的是一个对象,它有着会根据代码上下文语境自动改变其引用对象的特性。
JavaScript是动态语言,this关键字在执行的时候才能确定是谁,所以this永远指向调用者,即对"调用对象"的引用。简单点说就是 调用的方法属于哪个对象,this就指向那个对象。根据函数调用方式的不同,this可以 指向全局对象,当前对象,或其他任意对象。this四个调用模式
因此,this只有在被调用时才确定指向,console.log(obj2.getAge()) 的结果是obj2.age,即30。
拓展:
动态语言:是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化,类型的检查是在运行时做的,优点为方便阅读,清晰明了,缺点为不方便调试。如JavaScript;
静态语言:静态类型语言的类型判断是在运行前判断(如编译阶段),比如C#、java。