数组对象

Array 对象是用于构造数组的全局对象

创建数组

新建

1
2
3
let arr = [1, 2, 3]
let arr new Array(1, 2, 3)
let arr = new Array(3) // 长度

转化

1
2
3
4
5
6
7
8
9
10
11
12
let arr1 = '1, 2, 3'
arr1.split(',') // 将字符串用逗号隔开,转化为数组
let arr2 = '123'
arr2.split('') // 或用空字符串

// 示例
Array.from('123')
['1', '2', '3']
Array.from({0:'a',1:'b',2:'c',3:'d',length:4})
[ "a", "b", "c", "d" ]
Array.from({0:'a',1:'b',2:'c',3:'d',length:2})
[ "a", "b"]

伪数组

1
2
3
4
5
6
7
// 伪数组的原型链中没有数组的原型
array1 = {0:'a',1:'b',2:'c',length:3}

let divList = document.querySelectorAll('div')
// 获取的数组是 伪数组
let divArray = Array.from(divList)
// 转化为数组

1
2
3
4
5
6
7
8
9
10
11
12
13
// 合并两个数组,得到新数组
let arr1 = [1,2]
let arr2 = [3,4]
let arr3 = arr1.concat(arr2)
[1,2,3,4]
// 截取一个数组的一部分
arr3.slice(1) // 从第二个元素开始
let arr4 = arr3.slice(2)
[3,4]

arr5 = arr3.alice(0)
// 相当于复制数组
// 注意 JS 只提供浅拷贝

删除数组

1
2
3
4
5
6
7
8
9
let arr = ['a','b','c']
delete arr[0]
arr // [empty,'b','c']
// 长度没变

// 修改 length
arr.length = 1
arr //['a']
// 不要随便修改 length

删除头部元素

arr.shift() arr 被修改,并返回被删元素

删除尾部元素

arr.pop() arr 被修改,并返回被删元素

删除中间元素

arr.splice(index, 1) 删除 index 的一个元素

arr.splice(index, 1, ’x’) 并在删除位置添加 ‘x’

arr.splice(index, 1, ’x’, ’y’) 并在删除位置添加 ‘x’, 'y'

查看所有元素

查看所有属性名

1
2
3
4
5
6
7
let arr = [1, 2, 3, 4, 5];
arr.x = 'x'
Object.keys(arr)
Object.values(arr)
for(let key in arr) {
console.log('${keys}: ${arr[key]}')
}

查看数字(字符串)属性名和值

1
2
3
4
5
6
7
8
for(let i = 0; i < arr.length; i++){
console.log(`${i}: ${[i]}`)
}

arr.forEach(function(item, index){
console.log(`${index}: ${item}`)
})

forEach原理

1
2
3
4
5
6
7
8
9
10
11
12
function forEach(array,fn){
for(let i = 0; i < array.length; i++){
fn(array[i], i, array);
// 获取数组每一项,把数值传到 fn
}
}

forEach(['a', 'b', 'c'], function(x, y, z){
console.log(x, y, z);
})
// forEach 用 for 访问 array 的每一项
// 对每一项调用 fn(array[i], i, array)

查看单个属性

1
let arr = [11, 22, 33]arr[0]

索引越界

1
arr[arr.legnth] === undefinedarr[-1] === undefined// 示例let arr = [1,2,3,4,5,6,7]for(let i = 0; i<= arr.length; i++){    console.log(arr[i].toString());}// 报错: Cannot read property 'toString' of undefined// 意思是你读取了 undefined 的 toString 属性// 不是 toString 的 undefined// x.toString() 其中 x 如果是 undefined 就报这个错

查找某个元素是否在数组里 indexOf

arr.indexOf(item) 存在换回索引,否则返回 -1

使用条件查找元素 find

arr.find(item => item % 2 === 0) 找第一个偶数

使用条件查找元素的索引 findIndex

arr.findIndex(item => item % 2 === 0) 找第一个偶数的索引

增加数组中的元素

在尾部添加元素 push

arr.push(newItem) 修改数组,返回新长度

arr.push(item1, item2) 修改数组,返回新长度

在头部添加元素 unshitf

arr.unshift(newItem) 修改数组,返回新长度

arr.unshift(item1, item2) 修改数组,返回新长度

在中间添加元素 splice

arr.splice(index, 0, ‘x’) 在 index 出插入 ’x’

arr.splice(index. 0, ‘x’, ‘y’) 插入 ‘X’,’y’

Array.prototypr.splice() MDN

修改数组中的元素

反转顺序 reverse

arr.reverse() 修改原数组

自定义顺序 sort

arr.sort((a, b)) => a-b)

1
// 示例let arr = [1,4,2,3,5]arr.sort() // [1,2,3,4,5]arr.sort(function(a, b){    console.log('a:'+ a)    console.log('b:'+ b)    if(a>b){        return 1    }else if(a===b){        return 0    }else{        return -1    }})// 等价于arr.sort((a, b) => a-b) 
1
let arr1 = [    {name: 'jack', score: 99},    {name: 'erik', score: 96},    {name: 'evan', score: 100}]arr1.sort(function(a, b){    if(a.score > b.score){return 1}    else if(a.score === b.score){return 0}    else{return -1}})// 等价于arr1.sort((a, b) => a-b)

反转字符串

1
let s = 'abcdefg';s.plit('').reverse().join('')

数组变换

Snipaste_2021-09-01_19-41-33

map

Array.prototype.map() MDN

map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。

map() 方法按照原数组元素顺序依次处理元素

1
let arr1 = [1, 2, 3, 4, 5, 6]// 将数组每个值平方arr1.map((item) => (item * item))// 等价于for(let i = 0; i < arr1.length; i++){    arr1[i] = arr1[i] * arr1[i]}

filter

Array.prototype.filter() MDN

filter() 方法返回一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。

1
let arr1 = [1, 2, 3, 4, 5, 6]// 偶数arr1.filter(item => item % 2 === 0)// 返回数组元素长度大于6let words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];words.filter(word => word.length > 6)

reduce

Array.prototype.reduce.() MDN

reduce() 方法对数组中的每个元素执行一个由您提供的 reducer 函数(升序执行),将其结果汇总为单个返回值

reduce() 可以作为一个高阶函数,用于函数的 compose。

1
let arr = [1, 2, 3, 4, 5, 6]// 累加let sum = 0;for(let i = 0; i < arr.length; i++){    sum += arr[i]} consloe.log(sum)// 等价于arr.reduce((sum, item) => sum + item, 0)// 从5开始:5 + 1 + 2 + 3 + 4 + 5 + 6 = 26arr.reduce((sum, item) => sum + item, 5)
1
// let arr = [1, 2, 3, 4, 5, 6]// 平方 等价于 arr.map(item => Math.pow(item, 2))arr.reduce((result, item) => {return result.concat(item * item)}, [])
1
let arr = [1, 2, 3, 4, 5, 6]arr.filter(item => item %2 === 0)// 等价于arr.reduce((result, item) => {    if(item % 2 === 0){        return result    }else{        return result.concat(item)    }}, [])arr.reduce((result, item) => item % 2 === 1 ? result : result.concat(item), [])arr.reduce((result, item) => item % 2 === 1 ? result.concat([]) : result.concat(item), [])arr.reduce((result, item) => result.concat(item % 2 ? [] : item), [])

面试题: 数据变换

1
let arr = [    {名称: '动物', id: 1, parent: null},    {名称: '狗', id: 2, parent: 1},    {名称: '猫', id: 3, parent: 1}]// 数组变成对象{    id: 1, 名称: '动物', children: [        {id: 2, 名称: '狗', children: null},        {id: 3, 名称: '猫', children: null}    ]}// 答案arr.reduce((result, item) => {    if(item.parent === null){        result.id = item.id        result['名称'] = item['item']    }else{        result.children.push(item)        delete item.parent        item.chrldren = null    }    return result}, {id: null, children: []})

1

Object

对象就是一组”键值对“(key-value)的集合,是一种无序的复合数据集合。

1
2
3
4
5
6
7
8
9
let obj = {
'name': 'frank',
'age': 18
}
let obj = new Object({
name: 'frank',
age: 18
})
console.log({name: frank, age: 18})
  • 键名都是字符串,不是标识符,可以包含任意字符(必须加上引号)
  • 引号可以省略,省略后键名必须符合标识符的规则
  • 所有键名都会被自动转成字符串

特殊键名

1
2
3
4
5
6
7
8
9
10
let obj = {
1: 'a',
3.2: 'b',
1e2: true,
1e-2: true,
.234: true,
0xFF: true
};
Object.keys(obj) // 列出 obj 所有的 key
=> ["1", "100", "255", "3.2", "0.01", "0.234"]

用变量做键名 用 [ ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let p1 = 'name';
let obj = {
p1: 'frank' // 键名为 'p1'
}

let obj = {
[p1]: 'frank' // 键名为 name
}
// 不加 [] 的键名会自动变成字符串
// 加了 [] 则会当作变量求值
// 值如果不是字符串,则会自动变成字符串
var obj {
[1+2+3]: 'shi'
}
Object.keys(obj);

隐藏属性

  • JS中每一个对象都一个隐藏属性 _proto_
  • 这个隐藏属性存储着共有属性组成的对象的地址
  • 这个共有属性组成的对象叫做原型
  • 也就是说,隐藏属性存储着原型的的地址

示例

1
2
3
4
// 隐藏属性为 __proto__
var obj = {}
obj.soString() // 不报错
因为 obj 的隐藏属性 对应的对象 上有 toString()

删除属性

delete obj.xxx 或 delete obj[‘xxx’]

可删除 obj 的 xxx 属性

区分 【属性值为 undefined】和【不含属性名】

不含属性名

‘xxx’ in obj === false

含有属性名,但是值为 undefined

‘xxx’ in obj && obj.xxx === undefined

注意 obj.xxx === undefined

不能断定 ‘xxx‘ 是否为 obj 的属性


读取属性

查看属性

obj[‘key’]

obj[key]

obj.key

obj.name 等价于 obj[‘name’] 不等价于 obj[name] 这里的 name 是字符串,不是变量

查看自身所有属性

Object.keys(obj);

查看自身 + 共有属性

console.dir(obj)

或者依次用 Object.keys 打印出 obj._proto_

判断一个属性是自身的还是共有

obj.hasOwnProperty(‘toString’)

1
2
3
4
Object.keys(obj);
Object.values(obj);
Object.entries(obj);
console.dir(obj);

‘name’ in obj 和 obj.hasOwnPrototy(‘name’) 区别

前者判断 obj 是否含有 name 属性名,但不会区分自身属性和共有属性

后者判断 obj 的属性 name 是自身的属性还是共有属性,返回 false,不是自身属性;发返回 ture,是自身属性。


#### 原型

每个对象都有原型

原型里存着对象的共有属性

比如 obj 的原型就是一个对象

obj.__proto__存着这个对象的地址

这个对象里有 toString / constructor / valueOf 等属性

对象的原型也是对象

所以对象的原型也有原型

obj = {} 的原型即为所有对象的原型

这个原型包含所有对象的共有属性,是对象的根

这个原型也有原型,是 null。 console.log(_proto._proto)


修改属性

直接赋值

1
2
3
4
5
6
7
8
let obj = {name: 'frank'} // name 是字符串
obj.name = 'frank' // name 是字符串
obj['name'] = 'frank'
❌obj[name] = 'frank' // 错,因 name 不确定
obj['na' + 'me'] = 'frank'
let key = 'name'; obj['key'] = 'frank'
let key = 'name'; ❌ obj.key = 'frank' // 错
因为 obj.key 等价于 obj['key']

批量赋值

1
Object.assign(obj.{age: 18, gender: 'man'})

修改或增加共有属性

无法通过自身修改或增加共有属性

1
2
3
let obj1 = {},obj2 = {}  // 共有toString
obj.toString = 'xxxx' // 只会改 obj1 自身的属性
obj2.toString 还是在原型上

偏要修改共有属性

1
obj1.__proto__.toString = 'xxx'; // 不推荐使用__proto__Object.prototype.toString = 'xxx';一般不要修改原型

修改隐藏属性

不推荐使用_proto_

1
2
3
4
5
6
// 代码示例
let person = {name: 'frank'};
let person1 = {name: 'jack'};
let common = {kind: 'human'};
obj.__proto__ = common;
obj2.__proto__ = common;

强烈推荐使用 Object.create

1
2
3
4
5
let persion = Object.cteate(common); // 以 common 为原型创建 persion 对象
persion.name = 'frank'; // 然后添加属性,或批量添加
let persion2 = Object.create(common, { //
name: {value: 'jack'}
});

表达式与语句

表达式(expression),指一个为了得到返回值的计算式。

1 + 2 表达式的为3

add(1 + 2) 表达式的值为函数的返回值

console.log 表达式的值为函数本身

console.log(3) 表达式的值为undefined

语句(statement),是为了完成某种任务而进行的操作,例如赋值语句var a = 1 + 3;

var a = 1 是一个语句

var a = 1 + 3

var b = ‘abc’

二者区别

表达式一般都有值,语句可能有也可能没有

语句一般不会改变环境(声明、赋值)

以上并不绝对

语句主要为了进行某种操作,一般情况下不需要返回值;表达式则是为了得到返回值,一定会返回一个值。凡是 JavaScript 语言中预期为值的地方,都可以使用表达式。比如,赋值语句的等号右边,预期是一个值,因此可以放置各种表达式。

表达式不需要分号结尾。一旦在表达式后面添加分号,则 JavaScript 引擎就将表达式视为语句,这样会产生一些没有任何意义的语句。


标识符

指的是用来识别各种值的合法名称,最常见的标识符就是变量名,以及函数名。

JavaScript 语言的标识符对大小写敏感,所以aA是两个不同的标识符。

命名规则:

  • 第一个字符,可以是任意 Unicode 字母(包括英文字母和其他语言的字母),以及美元符号($)和下划线(_)。
  • 第二个字符及后面的字符,除了 Unicode 字母、美元符号和下划线,还可以用数字0-9

JavaScript 有一些保留字,不能用作标识符:arguments、break、case、catch、class、const、continue、debugger、default、delete、do、else、enum、eval、export、extends、false、finally、for、function、if、implements、import、in、instanceof、interface、let、new、null、package、private、protected、public、return、static、super、switch、this、throw、true、try、typeof、var、void、while、with、yield。


if else

if结构先判断一个表达式的布尔值(true or false),然后根据布尔值的真伪,执行不同的语句。

1
2
3
4
5
6
7
8
if (表达式) {
// 语句
}else if (表达式){
// 语句
}else if (表达式){
// 语句
}else {
}

switch

多个 if ...else 连在一起使用的时候,可以转为是使用 switch 结构。

1
2
3
4
5
6
7
8
9
10
11
switch (fruit) {
case "banana":
// ...
break;
case "apple":
// ...
break;
default:"nothing"
// ...
}
// switch 语句部分和 case 语句部分,都可以使用表达式。

三元运算符

1
2
3
4
5
6
(条件) ? 表达式1 : 表达式2

var even = (n % 2 === 0) ? true : false;
// 如果n可以被2整除,则even等于true,否则等于false

var msg = '数字' + n + '是' + (n % 2 === 0 ? '偶数' : '奇数');

逻辑运算符

逻辑与运算(&&)是 AND 布尔操作。只有两个操作数都为 true 时,才返回 true,否则返回 false。具体描述如表所示。

第一个操作数 第二个操作数 运算结果
true true true
true false false
false true false
false false false

逻辑与是一种短路逻辑,如果左侧表达式为 false,则直接短路返回结果,不再运算右侧表达式。运算逻辑如下:

  • 第 1 步:计算第一个操作数(左侧表达式)的值。
  • 第 2 步:检测第一个操作数的值。如果左侧表达式的值可转换为 false(如 null、undefined、NaN、0、””、false),那么就会结束运算,直接返回第一个操作数的值
  • 第 3 步:如果第一个操作数可以转换为 true,则计算第二个操作数(右侧表达式)的值。
  • 第 4 步:返回第二个操作数的值。
1
2
3
4
console.log(typeof ({} && true));  //返回第二个操作数的值  true的类型:布尔型
console.log(typeof (true && {})); //返回第二个操作数的值 {}的类型:对象
console && console.log && console.log(hi) // 返回 hi
fn && fn() // 常见写法 如果fn存在调用fn()

**辑或运**算`||`是布尔 OR 操作。如果两个操作数都为 true,或者其中一个为 true,就返回 true,否则就返回 false。
1
2
3
4
5
6
7
a = a || 100
// 等价于
if (a) {
a = a
} else {
a = 100 // 保底值
}

while

While 语句包括一个循环条件和一段代码块,只要条件为真,就不断循环执行代码块。

1
2
3
while (条件) {
语句;
}
1
2
3
4
5
6
7
// 例 死循环
var a = 0.1;
while (a !== 1) {
cconsole.log(a);
a = a + 0.1;
}
// 因为浮点数不精确

for

1
2
3
4
5
6
7
for (初始化表达式; 条件; 递增表达式) {
语句
}
先执行 初始化表达式
然后判断 条件
如果为 真,执行循环体,然后执行 递增表达式
如果为 假,直接退出循环。
1
2
3
4
5
6
7
// 例
for(var i = 0; i<5; i++) {
setTimeout(()=> {
console.log(i + '随机数:' + Math.random());
}, 0);
}// 输出5个5

参考


for in

for/in 语句是 for 语句的一种特殊形式。参考

1
2
3
4
5
6
7
for ( [var] variable in <object | array){
statement
}
/* variable 表示一个变量,可以在其前面附加 var 语句,用来直接声明变量名。in 后面是一个对象或数组类型的表达式。在遍历对象或数组过程中,把或取的每一个值赋值给 variable。

然后执行 statement 语句,其中可以访问 variable 来读取每个对象属性或数组元素的值。执行完毕,返回继续枚举下一个元素,以此类推知道所有元素都被枚举为止。
对于数组来说,值是数组元素的下标;对于对象来说,值是对象的属性名或方法名。*/
1
2
3
4
5
// 使用 for/in 语句遍历数组,并枚举每个元素及其值。
var a = [1,true,"0",[false],{}];
for (var n in a) {
document.write("a["+n+"] = " + a[n] + "<br>");
}

break 和 continue

break 语句能够结束当前 for、for/in、while、do/while 或者 switch语句的执行。

continue 语句用在循环结构内,用于跳过本次循环,继续执行下一次循环。


label

标签

1
2
3
4
5
6
7
8
9
10
foo: {
console.log(1);
break foo;
console.log('本行不会输出');
}
console.log(2);

// m 一个标签,内容为1
{foo:1}

参考自网道 JavaScript教程

JavaScript的历史

JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发 Web 页面的脚本语言而出名的,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。

1995年由于网景公司需要做出一款比 Java 还要简单的脚本语言,但是还要于Java相似。这时刚入职没多久的 Brendan Eich 就被安排了这项任务。

1995年5月Brendan Eich只用了10天,就设计完成了这种语言的第一版。

1996年11月,网景正式向 ECMA(欧洲计算机制造商协会)提交语言标准。1997年6月,ECMA以JavaScript语言为基础制定了ECMAScript 标准规范ECMA-262。JavaScript成为了ECMAScript最著名的实现之一。除此之外,ActionScript 和 JScript 也都是ECMAScript 规范的实现语言。尽管JavaScript作为给非程序人员的脚本语言,而非作为给程序人员的脚本语言来推广和宣传,但是 JavaScript 具有非常丰富的特性。

JavaScrip 特点

一般来说,完整的 JavaScript 包括以下几个部分:

  • ECMAScript,描述了该语言的语法和基本对象
  • 文档对象模型 DOM,描述处理网页内容的方法和接口
  • 浏览器对象模型 BOM 浏览器对象模型,描述与浏览器进行交互的方法和接口

JavaScript的基本特点如下:

  • 是一种解释性脚本语言(代码不进行预编译)。
  • 主要用来向HTML页面添加交互行为
  • 可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。

JavaScript常用来完成以下任务:

  • 嵌入动态文本于HTML页面
  • 对浏览器事件作出响应
  • 读写HTML元素
  • 在数据被提交到服务器之前验证数据
  • 检测访客的浏览器信息
  • 控制 cookie,包括创建和修改等

JavaScript 语法有多个来源:

  • 基本语法:借鉴 C语言和 Java 语言。
  • 数据机构:借鉴 Java语言,包括将值分为原始值和对象两大类。
  • 函数的用发:借鉴 Scheme语言 (Smalltalk的一种变种)。
  • 正则表达式:借鉴 Perl语言。
  • 字符串和数组处理:借鉴 Python语言。

为了保持简单,这种脚本语言缺少一些关键的功能,比如块级作用域、模块、子类型(subtyping)等等,但是可以利用现有功能找出解决办法。这种功能的不足,直接导致了后来JavaScript的一个显著特点:对于其他语言,你需要学习语言的各种功能,而对于JavaScript,你常常需要学习各种解决问题的模式。而且由于来源多样,从一开始就注定,JavaScript的编程风格是函数式编程和面向对象编程的一种混合体。

JavaScript的缺陷

  1. 不适合开发大型程序

    Javascript没有名称空间(namespace),很难模块化;没有如何将代码分布在多个文件的规范;允许同名函数的重复定义,后面的定义可以覆盖前面的定义,很不利于模块化加载。

  2. 非常小的标准库

    Javascript提供的标准函数库非常小,只能完成一些基本操作,很多功能都不具备。

  3. null 和 undefined

    null属于对象(object)的一种,意思是该对象为空;undefined则是一种数据类型,表示未定义。

  4. 全局变量难以控制

    Javascript的全局变量,在所有模块中都是可见的;任何一个函数内部都可以生成全局变量,这大大加剧了程序的复杂性。

  5. 自动插入行尾分号

    Javascript的所有语句,都必须以分号结尾。但是,如果你忘记加分号,解释器并不报错,而是为你自动加上分号。有时候,这会导致一些难以发现的错误。

  6. 加号运算符

    +号作为运算符,有两个含义,可以表示数字与数字的和,也可以表示字符与字符的连接。

    1
    2
    alert(1+10); // 11
    alert("1"+"10"); // 110

    如果一个操作项是字符,另一个是数字,则数字自动转化为字符

    1
    2
    alert(1+"10") // 110
    alert("10"+1) // 101
  7. NaN

    NaN是一种数字,表示超出了解释器的极限。

  8. 数组和对象的区分

    由于Javascript的数组也属于对象(object),所以要区分一个对象到底是不是数组,相当麻烦

  9. == 和 ===

    ==用来判断两个值是否相等。当两个值类型不同时,会发生自动转换,得到的结果非常不符合直觉。

    推荐任何时候都是用 “===”

    1
    2
    3
    4
    5
    6
    7
    8
    "" == "0"  // false
    0 == "" // true
    0 == "0" // frue
    false == "false" // false
    false == undefined // false
    false == null // false
    null == undefined // true
    " \t\r\n" == 0 // ture
  10. 基本类型的包装对象

    Javascript有三种基本数据类型:字符串、数字和布尔值。它们都有相应的建构函数,可以生成字符串对象、数字对象和布尔值对象。

资料连接:

JavaScript 的历史

JavaScript 诞生记

JavaScript 的10个设计缺陷

万维网(World Wide Web)包含三个部分分别是:

WWW=URL(Uniform)+HTTP(HyperText Transfer Protocol)+HTML(HyperText Markup Language)

URL= 协议+域名或IP+端口号+路径+查询字符串+锚点

http://www.baidu.com/s?wd=hi&rsv_spt=1#5

协议 —— http://
域名 —— www.baidu.com
路径 —— /s
查询参数 —— ?wd=hi&rsv_spt=1
锚点 —— #5

协议

服务器使用的协议一般有两种:

一种为HTTP(HyperText Transfer Protocol,超文本传输协议)
一种为HTTPS(Hyper Text Transfer Protocol over SecureSocket Layer,超文本传输安全协议)


IP(Internet Protocol)

作用

一、如何定位一台设备(手机、电脑、路由器…)
二、如何封装数据报文,以跟其他设备交流

换句话说,只要你在互联网中,你就至少会有一个独立的IP

IP分为内网和外网

外网IP

如何获取外网的IP(过程)

第一步:从电信租用带宽

第二步:光猫(调制解调器)

作用:拨号上网

第三步:路由器

作用:起到分配的作用

把电脑和手机分别连接由路由器广播出来的无线WIFI

只要路由器通过“光猫”连接上外面(电信)的服务器时,路由器就会有一个「外网IP」,比如「147.17.32.211」就是一个外网IP,这个IP地址就是在互联网中的地址(所有的通过路由器连接设备都是同一个外网IP地址)

但是如果重启路由器,那么很有可能被重新分配一个「外网IP」,换句话说你的路由器没有「固定的外网IP」

拓展:查询自己的外网IP

内网IP

路由器会在家里(区域)创建一个内网,内网中的设备使用时内网IP,一般来说内网IP格式为「http://192.168.xxx.xxx

一般路由器会给自己分配一个好记的内网IP:192.168.1.1(一般会让出一个位置留给光猫)

然后路由器会给每一个内网中的设备分配一个不同的内网IP,如电脑是192.168.1.2,手机是192.168.1.3,以此类推。

路由器

路由器有两个IP:一个外网IP和一个内网IP

内网中的设备可以互相访问,但是不能直接访问外网

内网设备想要访问外网,就必须经过路由器中转

外网中的设备可以互相访问,但无法直接访问内网设备

外网设备想要把内容送到内网,也必须通过路由器

换句换说内网和外网就像两个隔绝的空间无法互通,唯一的联通点就是路由器

所以路由器有时候也被叫做网关

特殊IP

127.0.0.1 本地

localhost 本地

0.0.0.0(不表示任何设备)

域名

域名就是IP的别称

知识:

  • 一个域名可以对应不同的IP
  • 这个叫做均衡负载,防止一台机器扛不住

终端输入ping baidu.com 会生成几个IP地址来对应不同的服务器,这些服务器分别对应各个地区(华中、华南、华北..),进行使用

  • 一个IP可以对应不同域名
  • 这个叫做共享主机

公司太小公用服务器或者一个公司有两个网站,公用一个IP地址

疑问 ️:www.xiedaimala.com与xiedaimala.com是同一个域名吗?

答案:不是同一个域名

拓展:

com(company,公司)是顶级域名
http://xiedaimala.com二级域名(俗称一级域名)
http://www.xiedaimala.com三级域名(俗称二级域名)

他们是父子关系(越长越小)

github.io 把子域名xxx.github.io免费给用户使用 xx.com与www.xx.com可以是同一家公司,也可以不是同一家公司(只是公用父域名) www是非常多余的!

端口

什么是端口

我们知道URL的作用是定位服务器比如定位百度服务器),我们可以通过上面的IP/域名来定位服务器,但是我们定位服务器的根本目的是需要为服务的(不然我们定位服务器干啥!! )
所有现在接下来的事情就是定位服务,而端口就是为了对应不同服务的

端口号

一台服务器(设备)可以提供很多服务,每个服务都有对应号码,这个号码被称为端口号

很多服务

要提供HTTP(超文本传输协议)服务最好使用80端口

要提供HTTPS(超文本传输安全协议)服务最好使用443端口

要提供FTP(文件传输协议)服务最好使用443端口

一共有65535个端口,基本够用

我们怎么知道什么服务对应(提供)什么端口


路径

在一个服务器(设备)上,如何请求不同的页面 通过路径可以做到

例:

https://developer.mozilla.org/zh-CN/docs/Web/HTML

https://developer.mozilla.org/zh-CN/docs/Web/css

查询参数

同一页面,不同内容

https://www.baidu.com/s?wd=hi&pn=10

https://www.baidu.com/s?wd=hello

/s:搜索页面
?wd=:查询参数 word(单词/词语)
wd:word(单词/词语)

锚点

在一个内容上,如何请求不同位置 通过锚点可以做到

举 :

https://develop.mozilla.org/zh-CN/docs/web/HTML#参考书 https://develop.mozilla.org/zh-CN/docs/web/CSS#教程

注意:

锚点看起来有中文,实际不支持中文 #参考书传输到服务器会变成一堆乱码 锚点无法在Network面板看到 因为锚点不会传給服务器

DNS

DNS全称为Domain Name System,域名系统

DNS 的作用就是对域名和IP进行相互对应的

验证下:当我们输入http://baidu.com回车后,域名是如何与IP进行相互对应的?

  • 在Chrome浏览器下输入http://baidu.com后,先经过路由器向外网的(电信/联通提供的DNS服务器)发出询问,询问内容就是http://baidu.com所对应的IP地址
  • 电信/联通提供的DNS服务器收到请求后,就会回答一个IP地址
  • 然后Chrome浏览器把回答的IP地址和以及IP对应的端口(80/443端口)再次通过路由器向对应的服务器发送请求
  • 请求内容:查看http://baidu.com的页面
  • 服务器通过路由器再传回给浏览器(HTML、CSS、JS等)
  • 最终我们就可以看到http://baidu.com的页面了

通过nslookup 命令查看域名下所有提供服务的服务器

语法:nslookup 网站域名

拓展:ping与nslookup区别:

ping:查看域名对应本地区的服务器,更为准确 nslookup:查看域名对应所有提供服务的服务器

curl命令

用 curl 可以发 HTTP 请求

1
2
curl -v http://baidu.com
curl -s -v -- https://www.baidu.com

理解:

url 会被 curl 工具重写,先请求 DNS 获得 IP

先进行 TCP 连接,TCP 连接成功后,开始发送 HTTP 请求

请求内容看一眼

响应内容看一眼

响应结束后,关闭 TCP 连接(看不出来)

真正结束

选择器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1.群组选择器  如:p, body, img, div{}

2.兄弟选择器 如:p + p { color:#f00; }

3.属性选择器 如: p[title] { color:#f00; }

4.包含(后代)选择器 如:body ul li{}

5.子元素选择器 如:div > p{}

6.ID选择器 如:#myDiv{}

7.类选择器 如:.class1{}

8.伪元素选择器 如:E:first-line,E:before

9.伪类选择器 如:E:first-child ,E:visited,E:focus,E:enabled

10.标签选择器 如:p { font-size:1em; }

优先级: !important > 行内样式 > ID选择器 > class选择器 > 标签 > 通配符 > 继承

定位(position)

  1. static,默认,待在文档流里
  2. relative,相对定位,原位置不变,显示的位置偏移
    • 用于做位移(很少用)
    • 用于给 absolute 元素做父元素
    • 配合 z-index,z-index :auto 默认值,不创建新层叠上下文
  3. absolute,绝对定位,定位基准是祖先里的非static即相对于祖先元素中最近的一个定位元素
    • 脱离原来的位置,另起一层,比如对话框的关闭按钮,祖先元素得加 relative
    • 某些浏览器不写 top / left 会位置错乱。善用 left: 100% left: 50% 加负 margin
  4. fixed,固定定位,定位基准是 viewport,视口代表当前可见的计算机图形区域,transform 有bug
    • 手机上尽量不要使用 fixed
  5. sticky,粘滞定位,兼容差

Tips:

  • 如果写了 absolute,一般都得补一个 relative

  • 如果写了 absolute 或 fixed,一定要补 top 和 left

position MDN

盒模型

20180324150509906
  1. content-box 内容就是盒子的边界
    • content-box width = 内容宽度
  2. border-box 边框才是盒子的边界 (推荐使用)
    • border-box width = 内容宽度 + padding + border
1
box-sizing: border-box | content-box;

CSS 基础框盒模型介绍 MDN

float 布局

步骤:

  1. 子元素加上 float: left 和 width
  2. 在父元素上加 .clearfix

经验:

  • 有经验者会留一些空间或者最后有一个不设 width
  • 不需要响应式,因为手机上没有 IE,而这个布局是专门为 IE准备的

IE 6/7 存在双倍 margin bug, 两个解决办法(基本不用):

  1. 针对 IE 6/7 把 margin 减半
  2. 加一个 display: inline-block
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.clearfix:after {
/* 清除浮动 */
content: '';
display: block;
clear: both;
}

IE bug
/* margin 减半 && inline-block */
.class {
margin-left: 10px;
_margin-left: 5px;
display: inline-block;
}

为什么要清除浮动

float demo

Tips:

  • border 有时候会干扰尺寸,可以改成 outline
  • 用 float 做平均布局时,可以在布局中增加一个x图层,其多余的右边距可以用 负的 margin 来改善布局
Snipaste_2021-08-20_08-33-25

浏览器渲染原理

  • 根据 HTML 构建 HTML 树(DOM)
  • 根据 CSS 构建 CSS 树 (CSS DOM)
  • 将两棵树合并成一颗渲染树 (render tree)
  • Layout 布局(文档流、盒模型、计算大小和位置)
  • Paint 绘制 (把边框颜色、文字颜色、阴影等画出来)
  • Compose 合成(根据层叠关系展示画面)
render-tree-construction

渲染树构建、布局及绘制

动画

transition

css中的transition允许css的属性值在一定的时间区间内平滑地过渡。这种效果可以在鼠标单击、获得焦点、被点击或对元素任何改变中触发,并圆滑的以动画效果改变css的属性值。

transition属性是个复合属性 transition: property name | duration | timing function | delay;,包括以下几个子属性:

  • transition-property :规定设置过渡效果的css属性名称
    • transition-property: none |all |property
  • transition-duration :规定完成过渡效果需要多少秒或毫秒
    • transition-duration: time
  • transition-timing-function :指定过渡函数,规定速度效果的速度曲线
    • transition-timing-function:linear| ease| ease-in| ease-out| ease-in-out| cubic-bezier(n,n,n,n);
  • transition-delay :指定开始出现的延迟时间
    • transition-delay: time

animation

animation

1
2
3
4
5
animation: 时长|过渡方式|延迟|次数|方向|填充模式|是否暂停|动画名;

方向:reverse | alternate | alternate—reverse
填充模式:forwards | none | backwards | both
暂停:paused | running

keyframes语法格式

让动画停在最后一帧 加forwards ,例 animation: xxx 1.5s forwards;

一个 div 的分层

Snipaste_2021-07-12_21-36-28
Snipaste_2021-07-12_22-04-00

position

  1. static,默认,待在文档流里
  2. relative,相对定位,原位置不变,显示的位置偏移
    • 用于做位移(很少用)
    • 用于给 absolute 元素做父元素
    • 配合 z-index,z-index :auto 默认值,不创建新层叠上下文
  3. absolute,绝对定位,定位基准是祖先里的非static即相对于祖先元素中最近的一个定位元素
    • 脱离原来的位置,另起一层,比如对话框的关闭按钮,祖先元素得加 relative
    • 某些浏览器不写 top / left 会位置错乱。善用 left: 100% left: 50% 加负 margin
  4. fixed,固定定位,定位基准是 viewport,视口代表当前可见的计算机图形区域,transform 有bug
    • 手机上尽量不要使用 fixed
  5. sticky,粘滞定位,兼容差

Tips:

如果写了 absolute,一般都得补一个 relative

如果写了 absolute 或 fixed,一定要补 top 和 left

position MDN

层叠上下文

Snipaste_2021-07-13_21-47-35

比喻:

  • 每个层叠上下文既是一个小世界(作用域)
  • 这个小世界里面的 z-index 跟外界无关
  • 处在同一个小世界的 z-index 才能比较
  • 负 z-index 逃不出小世界,

那些属性可以创建,查mdn

浏览器渲染原理

步骤:

  • 根据 HTML 构建 HTML 树(DOM)
  • 根据 CSS 构建 CSS 树 (CSS DOM)
  • 将两棵树合并成一颗渲染树 (render tree)
  • Layout 布局(文档流、盒模型、计算大小和位置)
  • Paint 绘制 (把边框颜色、文字颜色、阴影等画出来)
  • Compose 合成(根据层叠关系展示画面)
render-tree-construction

JS三种更新样式方式

  1. JS/CSS > 样式 > 布局 > 绘制 > 合成

    frame-full

    如果修改元素的“layout”属性,也就是改变了元素的几何属性(例如宽度、高度、左侧或顶部位置等),那么浏览器将必须检查所有其他元素,然后“自动重排”页面。任何受影响的部分都需要重新绘制,而且最终绘制的元素需进行合成。

  2. JS/CSS > 样式 > 绘制 > 合成

    frame-no-layout

    如果修改“paint only”属性(例如背景图片、文字颜色或阴影等),即不会影响页面布局的属性,则浏览器会跳过布局,但仍将执行绘制。

  3. JS/CSS > 样式 > 合成

    frame-no-layout-paint

    如果更改一个既不要布局也不要绘制的属性,则浏览器将跳到只执行合成。

    对于应用程序生命周期中的高压点(例如动画或滚动),此最终版本是开销最小和最理想的。

    This final version is the cheapest and most desirable for high pressure points in an app’s lifecycle, like animations or scrolling.

例:勾选 Paint flashing查看

  1. div.remove() 会触发当前消失,其他元素 relayout ,再 repaint + composte
  2. change bg color 直接 repaint + composite
  3. change transform 只需 composite

查看css属性变更时触发的改变 CSSTrigers

渲染树构建、布局及绘制

渲染性能

使用 transform 实现动画

文档流

  1. 流动方向
    • inline 从左到右,到达最右边才会换行
    • block 从上到下,每一个都另起一行
    • inline-block 从左到右
  2. 宽度
    • inline 宽度为内部 inline 元素的和,不能用 width 指定
    • block 默认自动计算宽度 auto ,可用 width 指定
    • inline-block 结合前两者特点,可用 width
  3. 高度
    • inline 高度由行高 line-height 间接确定,跟 height 无关
    • block 高度由文档流元素决定,可设 height
    • inline-block 跟 block 类似,可设置 height

overflow 溢出

当内容大于容器

  • 等内容的款年度或高度大于容器的,会溢出
  • 可用 overflow 来设置是否显示滚动条
  • auto 是灵活设置
  • scroll 是永远设置
  • hidden 是直接隐藏移除部分
  • visible 是直接显示溢出部分
  • overflow 可分为 overflow-x 和 overflow-y 很少用

脱离文档流

block 高度由内部文档流元素决定,可以设 height,这句话的意思是不是说,有些元素可以不在文档流中

  • position: absolute/fixed;
  • float

盒模型

  1. content-box 内容就是盒子的边界
    • content-box width = 内容宽度
  2. border-box 边框才是盒子的边界 (推荐使用)
    • border-box width = 内容宽度 + padding + border

margin 合并

  • 父子。兄弟之间会合并,只有上下合并
  • 阻止合并:
    • 父子合并用 padding / border 挡住
    • 父子合并用 overflow:hidden 挡住
    • 父子合并用 display: flex
    • 兄弟合并是符合预期的,可以用 display: inline-block 消除

采用网格布局的区域,称为“容器(container)”。容器内部的采用网格定位的子元素称为“项目(item)”

container

1
2
3
4
.container {
/* 指定一个容器为 */
display: grid | inline-grid;
}

columns row

1
2
3
4
.container {
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
}
Snipaste_2021-07-10_23-02-04
1
2
grid-template-columns: repeat(4,1fr); // 宽度平均分成四等份 
grid-template-columns: 1fr 2fr 3fr; // 列宽这样是分成6份各占 1 2 3

grid-template-areas

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.item-a {
grid-area: header;
}
.item-b {
grid-area: main;
}
.item-c {
grid-area: sidebar;
}
.item-d {
grid-area: footer;
}

.container {
display: grid;
grid-template-columns: 50px 50px 50px 50px;
grid-template-rows: auto;
grid-template-areas:
"header header header header"
"main main . sidebar"
"footer footer footer footer";
}
Snipaste_2021-08-20_12-33-29

gap

1
2
3
4
5
6
7
8
9
10
.container {
grid-template-columns: 100px 50px 100px;
grid-template-rows: 80px auto 80px;
column-gap: 10px;
row-gap: 15px;
}

.container {
grid-gap: <grid-row-gap> <grid-column-gap>;
}
Snipaste_2021-08-20_13-02-30

item

1
2
3
4
5
6
.item-a {
grid-column-start: 2;
grid-column-end: five;
grid-row-start: row1-start;
grid-row-end: 3;
}
Snipaste_2021-08-20_13-18-20
1
2
3
4
5
6
.item-b {
grid-column-start: 1;
grid-column-end: span col4-start;
grid-row-start: 2;
grid-row-end: span 2;
}
Snipaste_2021-08-20_13-33-02
1
2
3
4
.item-c {
grid-column: 3 / span 2;
grid-row: third-line / 4;
}
Snipaste_2021-08-20_13-23-08

grid 游戏

参照 A Complete Guide to Grid