学习笔记 2020-10-25
JavaScript 高级程序设计(第4版) 阅读记录
代理与反射
代理模式
数据绑定与可观察对象
通过代理可以实现把被代理的类绑定到一个全局实例集合,让所有创建的实例都添加到这个集合中。再把集合绑定到一个事件分派程序,每次插入新实例时都会发送消息。
函数
函数实际上是个对象。每个函数都是 Function
类型的实例。
定义函数的方法有:
函数声明
函数表达式
箭头函数
Function
构造函数该构造函数接收任意多个字符串参数,最后一个参数始终会被当成函数体。
箭头函数
箭头函数语法简洁,但不能使用 arguments
、 super
和 new.target
,也不能用作构造函数。也没有 prototype
属性。
函数名
函数名就是指向函数的指针,与其他包含对象指针的变量具有相同的行为。一个函数可以有多个名称。使用不带括号的函数名会访问函数指针。
ECMAScript6
的所有函数对象都会暴露一个只读的 name
属性。如果函数是一个获取函数、设置函数或是使用 bind()
实例化,标识符前面会加上一个前缀。
function foo() {}
let bar = function () {};
let baz = () => {};
console.log(foo.name); // foo
console.log(bar.name); // bar
console.log(baz.name); // baz
console.log((() => {}).name); //(空字符串)
console.log(new Function().name); // anonymous
function foo() {}
console.log(foo.bind(null).name); // bound foo
let dog = {
years: 1,
get age() {
return this.years;
},
set age(newAge) {
this.years = newAge;
}
};
let propertyDescriptor = Object.getOwnPropertyDescriptor(dog, 'age');
console.log(propertyDescriptor.get.name); // get age
console.log(propertyDescriptor.set.name); // set age
理解参数
ECMAScript
函数的参数跟大多数其他语言不同,不关心传入参数的个数、类型。
原因是 ECMAScript
函数的参数在内部表现为一个数组。函数并不关心这个数组中包含什么。在使用 function
关键字定义非箭头函数时,可以在函数内部使用 arguments
对象来访问每个参数。
arguments
是一个类数组对象,可以和命名参数一起使用。它的值始终会和对应的命名参数同步。两者是相对应的,但仅限于传入的参数对应。未传入的参数位置使用 arguments
修改是不会反映到命名参数上的。
function doAdd(num1, num2) {
console.log(arguments); // Arguments [99, length: 1]
console.log(num1, num2); // 99 undefined
arguments[0] = 5;
arguments[1] = 10;
console.log(arguments); // Arguments [5, 1: 10, length: 1]
console.log(num1, num2); // 5 undefined
num1 = 1;
num2 = 2;
console.log(arguments); // Arguments [1, 1: 10, length: 1]
console.log(num1, num2); // 1 2
}
doAdd(99);
在严格模式下给 aguments[1]
赋值不会再影响 num2
。在函数中重写 arguments
对象会导致语法错误。
没有重载
ECMAScript
中后定义的同名函数会覆盖先定义的。
默认参数值
在 ECMAScript5.1
及以前,实现默认参数的常用方式是检查某个参数是否等于 undefined
。
ECMAScript6
之后支持显式定义默认参数。在函数定义中的参数后面用 =
赋默认值。
在使用默认参数时, arguments
对象的值不反映参数的默认值,只反映传给函数的参数。修改命名参数也不会影响 arguments
对象。
默认参数值不限于原始值或对象类型,也可以使用调用函数返回的值。
默认参数只有在函数被调用时才会求值,定义时不会求值。计算默认值的函数只有在调用函数但未传相应参数时才会被调用。
函数参数是某个作用域中求值的。给多个参数定义默认值实际上和使用 let
关键字顺序声明变量一样,所以后定义默认值的参数可以引用先定义的参数。
参数初始化顺序遵循 “暂时性死区” 规则。前面定义的参数不能引用后面定义的。
参数存在于自己的作用域中,不能饮用函数体的作用域。
现代 JavaScript 教程
任务
在对象字面量中使用
“this"
这里
makeUser
函数返回了一个对象。访问
ref
的结果是什么?为什么?function makeUser() { return { name: "John", ref: this }; }; let user = makeUser(); alert( user.ref.name ); // 结果是什么?
ref
会指向全局对象,非严格模式下是window
。因为this
是在被调用的那一刻确定。调用makeUser
时作为全局函数调用,this
绑定了window
。创建一个计算器
创建一个有三个方法的
calculator
对象:read()
提示输入两个值,并将其保存为对象属性。sum()
返回保存的值的和。mul()
将保存的值相乘并返回计算结果。
let calculator = { // ……你的代码…… }; calculator.read(); alert( calculator.sum() ); alert( calculator.mul() );
let calculator = { a: 0, b: 0, read: function() { this.a = +prompt('please enter the first number', 0); this.b = +prompt('please enter the second number', 0); }, sum: function() { return this.a + this.b; }, mul: function() { return this.a * this.b; } };
链式(调用)
有一个可以上下移动的
ladder
对象:let ladder = { step: 0, up() { this.step++; }, down() { this.step--; }, showStep: function() { // 显示当前的 step alert( this.step ); } };
现在,如果我们要按顺序执行几次调用,可以这样做:
ladder.up(); ladder.up(); ladder.down(); ladder.showStep(); // 1
修改
up
,down
和showStep
的代码,让调用可以链接,就像这样:ladder.up().up().down().showStep(); // 1
这种方法在 JavaScript 库中被广泛使用。
let ladder = { step: 0, up() { this.step++; return this; }, down() { this.step--; return this; }, showStep: function() { // 显示当前的 step alert( this.step ); return this; } };
MDN学习记录
多列布局
使用 column-gap
改变列间隙。
使用 column-rule
在列间加入一条分割线。属性值类似于 border
的值。并且该分割线不占用宽度。
列与内容折断
break-inside
属性用于表示该盒子不被拆开。
page-break-inside
拥有更好的浏览器支持。
响应式设计
响应式网页设计 ( responsive web design
),指的是允许 Web
网页适应不同屏幕宽度因素等,进行布局和外观的调整的一系列实践。
- 液态网格,这早先已由Gillenwater进行探讨,可以在Marcotte的文章《Fluid Grids》(出版于2009年的《A List Apart》上)中读到。
- 液态图像。通过使用相当简单的将设置
max-width
属性设置为100%
的技术,图像可以在包含它们的列变得比图像原始尺寸窄的时候,缩放得更小,但总不会变得更大。这使得图像可以被缩放,以被放到一个灵活尺寸的列,而不是溢出出去,同时也不会在列宽于图像的时候,使图像变得太大以至于画质变得粗糙。 - 媒体查询,媒体查询使以往
Cameron Adams
探讨过的、由JavaScript
实现的布局类型切换,可以只使用CSS实现。和所有尺寸的屏幕都使用一种布局不同的是,布局是可以改变的:侧栏可以在小屏幕上重新布局,而替代用的导航栏也可以显示出来。
媒介查询
下面的媒体查询进行测试,以知晓当前的Web页面是否被展示为屏幕媒体(也就是说不是印刷文档),且视口至少有800像素宽。用于 .container
选择器的CSS将只会在这两件前提存在的情况下应用。
@media screen and (min-width: 800px) {
.container {
margin: 1em 2em;
}
}
媒体查询,以及样式改变时的点,被叫做断点。
媒体查询
媒体查询基础
最简单的媒体查询语法看起来是像这样的:
@media media-type and (media-feature-rule) {
/* CSS rules go here */
}
它由以下部分组成:
- 一个媒体类型,告诉浏览器这段代码是用在什么类型的媒体上的(例如印刷品或者屏幕);
- 一个媒体表达式,是一个被包含的CSS生效所需的规则或者测试;
- 一组CSS规则,会在测试通过且媒体类型正确的时候应用。
可指定的媒体类型为:
all
print
screen
speech
朝向
一个受到良好支持的媒体特征是 orientation
,我们可以用它测得竖放(portrait mode)和横放(landscape mode)模式。要在设备处于横向的时候改变body文本颜色的话,可使用下面的媒体查询。
@media (orientation: landscape) {
body {
color: rebeccapurple;
}
}
使用指点设备
作为四级规范的一部分,hover
媒体特征被引入了进来。这种特征意味着你可以测试用户是否能在一个元素上悬浮,这也基本就是说他们正在使用某种指点设备,因为触摸屏和键盘导航是没法实现悬浮的。
@media (hover: hover) {
body {
color: rebeccapurple;
}
}
还是在四级规范中,出现了 pointer
媒体特征。它可取三个值:none
、fine
和 coarse
。fine
指针是类似于鼠标或者触控板的东西,它让用户可以精确指向一片小区域。coarse
指针是你在触摸屏上的手指。none
值意味着,用户没有指点设备,也许是他们正只使用键盘导航,或者是语音命令。
使用 pointer
可以在用户使用屏幕时进行交互时,帮你更好地设计响应这种交互的界面。例如,如果你知道用户正在用触摸屏设备交互的时候,你可以建立更大的响应区域。
媒体查询逻辑判断
- 与
and
- 或
,
- 非
not
特性查询
可以通过特性查询来判断浏览器是否支持某个特性。
@supports (display: grid) {
.item {
width: auto;
}
}