一:Css基础知识
1.布局
盒模型
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
#div1 {
width: 100px;
padding:10px;
border: 1px solid #ccc;
margin: 10px;
/* box-sizing: border-box; */
}
</style>
</head>
<body>
<div id="div1">
this is div1
</div>
</body>
<script type="text/javascript">
var div1 = document.getElementById('div1');
// div1.style.backgroundColor = 'red';
console.log(div1.offsetWidth,div1.offsetHeight);
</script>
</html>
设置box-sizing:border-box;把其余的宽度都算上。
margin纵向重叠问题
- 相邻元素,margin-top 与 margin-bottom 会发生重叠
- 空白内容的元素也会重叠
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
p{
font-size: 16px;
line-height: 1;
margin-top: 10px;
margin-bottom: 15px;
}
</style>
<body>
<p>AAA</p> //折叠10px
<p></p>
<p></p> // 变为零
<p></p>
<p>BBB</p> // 折叠15px
</body>
</html>
<!-- AAA BBB 之间的距离 15px -->
margin负值问题
margin-top 👆和 margin-left👈 负值,元素向上,向左移动。
margin-right 负值 右侧元素左移,自身不受影响(通过设置自身属性,影响其他元素的位置)
magrin-bottom 负值,下方元素上移,自身不受影响
2.定位
定位元素(带有position属性的)
position类型(相对:原来位置位移,绝对,参照定位元素,固定)
垂直,水平居中的写法。
水平居中:
行类元素:text-aglin:center;
块级:magrin: auto;
position:absolute; left:50%;margin-left:-width/2;
垂直居中:
行类元素:line-height:height;
块级:
position:absolute;top50%;magrin-top:-height/2;
transform:translate(-50%,-50%);
position:absolute; 上下左右:0;margin:auto;
flex:布局;
3.移动端响应式
1.rem(html:1/100px)根元素的1/100做单位比例
2.media qure(媒体插询)
12配合使用有弊端(阶梯形,分段式)
3.vh/vw (网页视口宽高 100vh 100vw)vmax vmin
4.动画/渐变(用处不大)
二:Js基础知识
我觉得,js基础知识的作用就是让自己知道代码的执行顺序。
Mark(待总结)
说到顺序那么运算符的顺序也同样重要
a || (b * c); // 首先对 `a` 求值,如果 `a` 为真值则直接返回 `a`
a && (b < c); // 首先对 `a` 求值,如果 `a` 为虚值则直接返回 `a`
代码执行顺序(变量,函数提升)
var 声明的变量会提升,多数返回undefined ,同样函数也会,表达式var fn = function(){} ,fn不会提升,返回not a function 。同名,funciton后执行,会覆盖var.
变量提升是将变量的声明提升到函数顶部的位置,而变量的赋值并不会被提升。
需要注意的一点是,会产生提升的变量必须是通过var关键字定义的,而不通过var关键字定义的全局变量是不会产生变量提升的。
不仅通过var定义的变量会出现提升的情况,使用函数声明方式定义的函数也会出现提升。
需要注意的是函数提升会将整个函数体一起进行提升,包括里面的执行逻辑。
而对于函数表达式,是不会进行函数提升的。
两者并存时,变量提升优先级高,所以,函数会在其后执行。
function fn() {
// 变量提升至函数顶部
var foo;
// 函数提升,但是优先级低,出现在变量声明后面,则foo是一个函数
function foo() {
return 'function';
}
console.log(typeof foo); // function
foo = 'variable'; // 变量赋值
console.log(typeof foo); // string
}
fn();
function foo() {
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
console.log(a); // 1
}
foo();
//代码执行
function foo() {
// 变量a的提升
var a;
// 函数声明b的提升
function b() {
// 内部的函数声明a的提升
function a() {}
a = 10; // 这里的跟外面的a 不同了。这里的a 被声明为函数了。
return;
}
a = 1;
b();
console.log(a); // 1
}
foo();
理解变量提升和函数提升可以使我们更了解这门语言,更好地驾驭它。但是在开发中,我们不应该使用这些技巧,而是要规范我们的代码,尽可能提高代码的可读性和可维护性。
具体的做法是:无论变量还是函数,都做到先声明后使用。对于ES6语法编写的代码,则全部使用let或者const关键字。
1.变量类型和计算
'100' + true = '100true';
'100' + 100 = '100100'
typeof 识别所有值类型;是否为引用类型(不可再细分);函数
识别全部基础类型,识别函数。引用类型全部返回object。最主要是注意null
let a; typeof a // 'undefined'
const str = 'abc' // 'string'
const n = 200 // 'number'
const b = true // 'boolean'
const s = Symbol('s') 'symbol'
typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
typeof function(){} // 'function'
=== 和 == 除了 == null 全部用===;
使用==就要注意了,字符 == 100,
//都是true
100 == '100'
0 == ''
0 == false
false == ''
null == undefined;
// 除了 == null 全部用===;
const obj = {x:100}
if(obj.a == null){} // 相当于 if(obj.a === null || obj.a === undefined){}
== 比较两个值的时候的5条规则
if语句和逻辑运算不是简单的 布尔值判断。
判断a 是以下的那种变量(if和逻辑运算是否执行的依据)
- truly 变量 : !!a === true
- falsely变量: !!a === false
如果是 truly 就if(a){执行}
//以下是falsely,除此都是truly
!!0
!!NaN
!!''
!!null
!!undefined
!!false
console.log(10&&0) // 0
console.log('' || 'abc') // 'abc'
console.log(!window.abc) // true;
//理解: window.abc 是undefined ,underfinded 是falsely,取反所以为true
值类型和引用类型
为什么要分类型?因为内存空间问题,值类型的体积小,引用类型如一个json
堆栈的数据存储格式:key value;
引用类型
堆 a 内存地址1
栈 内存地址1 { age:20}
值类型
堆:b 11
常见值类型:undefined ,'abc', 100,true,Symbol('s')
引用类型:
- 常见的:obj = {x:100} arr=[1,2,3] ,
- 特殊的:function(){} ,不用于存储数据,所以没有拷贝,复制函数这一说。
深拷贝
/**
* 深拷贝
*/
function deepClone(obj) {
if (typeof obj !== "object" || obj == null) { //1.不是对象或者数组,和null,undefined
return obj;
}
var result;
if (obj instanceof Array) { // 2.给变量初始的类型,用insatnceof
result = [];
} else {
result = {};
}
for (var key in obj) { //3.使用for in 遍历
// for in 一般用来遍历对象的key、for of 一般用来遍历数组的value
if(obj.hasOwnProperty(key)) { //备注:拷贝当然是拒绝复制 原型链上的属性。
result[key] = deepClone(obj[key]);
}
}
return result;
}
1.判断数据的类型 2.再过滤(空数组或空对象)3.属性赋值(for in 遍历)
备注:拷贝当然是拒绝复制 原型链上的属性。
2.原型和原型链
class
class 是ES6语法规范,由ECMA委员会发布
ECMA只规范语法规则,即是代码的书写规范,不规定如何实现
实现方式都是V8引擎的实现方式,也是主流的。
constructor,属性,方法
//新建一个学生的类
class Student {
constructor(name, number) {
this.name = name;
this.age = number;
}
sayHI() {
console.log("Hi, I am " + this.name);
}
}
// 创建一个新的学生实例
let Tom = new Student("Tom", 20);
// 输出 "Hi, I am Tom"
Tom.sayHI();
/**
* 类的继承
*/
class People {
constructor(name) {
this.name = name;
}
sayHi() {
console.log(`Hi, I am ${this.name}`);
}
}
// Child 继承了 People
class Child extends People {
constructor(name, number) {
super(name); // 调用父类的构造函数
this.number = number;
}
sayHi() {
console.log(`My number is ${this.number} ,${this.name}`);
}
}
// 创建一个新的 child 实例
let Mark = new Child("Mark", 18);
Mark.sayHi();
// class 实际上是一个函数 ,可见是语法糖
typeof Student; // "function"
//隐式原型和显示原型
Mark.__proto__ === Child.prototype; // true
// 原型关系(用图来表示)
// 隐式原型(每个实例都有__proto__属性):
//实例的原型对象(实例对象)的__proto__属性指向类的prototype属性
// 显式原型:(每个Class都有显示原型prototype):
//每个类都有一个prototype属性,指向一个对象,这个对象内部存放着类的方法。
类型判断
a(实例对象) instanceof b(构造函数) 是基于原型链实现的
instanceof
运算符
用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。xiaoluo.hasOwnProperty('sayHI') // 注意用字符串 说明它是否自身(非原型链上)的属性。
3.作用域,闭包,this
作用域的意思是,表示变量的合法范围的范围。主要分全局作用域,函数级作用域,块级作用域(es6);
闭包是一个有权访问另外一个函数作用域上的变量的函数。怎么产生呢?正常情况下,函数执行完毕后会立马销毁执行上下文环境,而闭包就是另外一个函数记住了它当前词法的作用域。
this.可以理解成一个调用的对象,多数考虑的是它的指向(那个对象)问题。决定它指向的取决于代码执行的时候(调用时);所以,箭头函数时没有this,如果使用this会指向当前执行上下文环境的上层。
详解箭头函数:
箭头函数不会创建自己的
this,它只会从自己的作用域链的上一层继承this
—mdn由于 箭头函数没有自己的this指针,通过
call()
或 apply()
方法调用一个函数时,只能传递参数(不能绑定this---译者注),他们的第一个参数会被忽略。(这种现象对于bind方法同样成立---译者注)—mdn箭头函数简写及其他书写规则—mdn
// 上面的普通函数可以改写成如下的箭头函数
elements.map((element) => {
return element.length;
}); // [8, 6, 7, 9]
// 当箭头函数只有一个参数时,可以省略参数的圆括号
elements.map(element => {
return element.length;
}); // [8, 6, 7, 9]
// 当箭头函数的函数体只有一个 `return` 语句时,可以省略 `return` 关键字和方法体的花括号
elements.map(element => element.length); // [8, 6, 7, 9]
//箭头函数在参数和箭头之间不能换行。要换就要用{}
//这是因为花括号({} )里面的代码被解析为一系列语句(即 foo 被认为是一个标签,而非对象字面量的组成部分)。
//所以,记得用圆括号把对象字面量包起来:
var func = () => ({foo: 1});
//记住用params => {object:literal}这种简单的语法返回对象字面量是行不通的
var func = () => { foo: 1 };
// Calling func() returns undefined!
var func = () => { foo: function() {} };
// SyntaxError: function statement requires a name
箭头函数使用总结:
1.call,bind 也不起作用,会忽略第一个参数,如果带参数,第一个参数(this指向)忽略也要写上
2.arguments 内部使用会失效,但是,可以使用剩余参数变相返回。
function f(arg1,agr2){
let fn = (...arg)=>arg[1]
return fn(arg1,agr2)
}
f(1,2) // 2;
插入一些关于js代码的执行的背景知识
引擎,从头到尾负责js代码的编译及执行过程。注意,它与传统编译器(词法分析,语法解释AST,可执行代码生成)要复杂些,如优化代码。
:一个变量的合法使用范围
Copy of 编程术语
由于每个人对同样东西,往往有着不同的见解,而且,每个人表达的方式也有所不同。那么,对于描述同样东西,知识概念的时候,就容易产生歧义。又由于受众的认知程度不同,接收的信息也有高低之别,那么,理解同样的东西的不同表述,就更加千变万化。
作用域
作用域:执行上下文,可以理解成变量的生命周期。严谨地说是变量被合法访问的范围。
负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。—不知道的JavaScript上
词法作用域,函数,块级作用域
闭包
闭包前置知识还有 绑定 作用域 调用栈 等,而闭包本质上来讲是函数。
const sayLater = function(text,when)=>{
let task = ()=> console.log(text)
setTimeout(task,when)
}
- 闭包是指有权访问另外一个函数作用域中的变量的函数。—《Javasc高级程序设计》
- 当函数记住并且访问所在词法作用域时,就产生闭包。如何产生闭包?《不知道的javastript..上 44》
- 带有自由变量(即代码中使用但没声明为参数或局部变量的变量,往上级作用域查找变量的值,不是在执行调用的地方,this,就是在函数调用的地方查找this的指向)的函数是闭包—《不知道的javastript..》
- 当函数可以记住并访问所在的词法作用域时,就产生闭包,即使函数是在当前词法作用域之外执行—《写给大忙人的现代JavaScript》
- ...每次调用都会重新创建局部绑定的事实,并且不同的调用不能在其他调用的局部绑定上进行操作。这个能够引用封闭作用域中的局部绑定的特定实例的功能称为闭包。(《JavaScript编程精讲》太长截图吧)
......
闭包的使用场景:
- 缓存数据,向外只提供接口访问
- 固定对象(原理同上:保存对象状态为私有的,即除通过提供的方法外,没有人可以修改它)
const createAccount = (balance)=>{
return Object.freeze({
deposit:amout=>{
blance+=amout
},
...
})
}
//工程函数
//状态被自动封装;避免使用this参数
//上图中的闭包 也可以是 函数柯里化
function test(other){
return number => number+other;
}
const vaule = test(2);
console.log(test(3)) // 5
//1.返回值
function fn(){
var name = 'hello';
return function(){
return name;
}
}
var fuc = fu();
console.log(fuc()); // hello
// 函数赋值
var fn2;
function fn(){
var name = 'hello';
fn2 = function(){
return name;
}
}
fn();
console.log(fn2()); // hello
//函数参数
function fn(){
var name = 'hello';
return function callback(){
return name;
}
}
var fn1 = fn();
function fn2(f){
console.log(f())
}
fn2(fn1)
//IIFE (自执行函数)
(function(){
var name = 'hello world';
var fn1 = function(){
return name;
}
fn2(fn1)
})();
function fn2(f){
console.log(f())
}
// 循环赋值
for(var i = 0;i<10;i++){
(function(j){
setTimeout(function(){
console.log(j)
},j*1000)
}(i))
}
//getter setter
function fn(){
var name = "hello";
setName = function(n){
name = n
};
getName = function(){
return name;
}
return {
setName:setName,
getName:getName
}
}
var fn1 = fn();
console.log(fn1.getName());
fn.setName('world');
console.log(fn1.getName());
//迭代器
var arr = ["aa","bb","cc"];
function incre(arr){
var i = 0;
return function(){
return arr[i++] || "数组值已经遍历完毕";
}
}
var next = incre();
console.log(next());//aa
console.log(next());//bb
console.log(next());//cc
console.log(next()); // 数组值已经遍历完毕
//缓存
var fn = (function(){
var cache = {};
var calc = function(arr){
var sum = 0;
for(var i = 0;i<arr.length;i++){
sum += arr[i];
}
return sum;
}
return function(){
var args = Array.prototype.join.call(arguments);
if(cache[args]){
return cache[args];
}
return cache[args] = calc(arguments);
}
})
this:
JavaScript 中的函数既可以被当作普通函数执行,也可以作为对象的方法执行,这是导致 this 含义如此丰富的主要原因
在箭头函数出现之前,每一个新函数根据它是被如何调用的来定义这个函数的this值:
- 如果该函数是一个构造函数,this指针指向一个新的对象
- 在严格模式下的函数调用下,this指向
undefined
- 如果该函数是一个对象的方法,则它的this指针指向这个对象
- 等等
This
被证明是令人厌烦的面向对象风格的编程。 所以出现了箭头函数。this对象是在运行时基于函数的执行环境绑定的。
this的绑定和函数声明的位置无关,只取决于函数的调用方式。
this不指向函数自身,也不指向函数的词法作用域作用域,完全取决于函数在哪里被调用(词法作用域:你在写代码时将变量和块级作用域写在哪里来决定的)ps大多数编程语言都采用此方式。
判断:
1.this指向全局对象,没有调用者,就指向全局
2.this指向所属对象
3.this指向对象实例,代码演示:
var number = 10;
funciton Person(){
number = 20;
this.number = 30;
}
Person.prototype.getNumber = funciton(){
return this.number
}
var p = new Person()
p.getNumber() // 30
4.闭包中的this,通常需要用一个变量保存 _this = this;
加深理解this的例子,有点绕
关键看代码的执行顺序,这个过程中的操作(赋值);
function f(k){
this.m = k;
return this; // 这里两个this,都是指向window。
}
var m = f(1) // window.m = window
var n = f(2) // window.n = window
//最后两句代码,来看看函数执行
//this.m = 1,window.m = window,this.m= 2(
作用域 闭包 this的相关描叙
- 作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象
- 一般来讲,当函数 执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象),但是闭包的情况又有所不同。
...
事实上,传递参数并非 apply() 和 call() 真正的用武之地,它们真正强大的地方是能够扩充函数赖以运行的作用域。使用 call() 或者 apply() 来扩充作用域的最大好处,就是对象与方法不需要任何耦合关系
4.异步编程与Promise
一:异步编程的背景
javaScript 引擎是基于单线程(single-threaded)事件循环的概念构建的,同一时刻只允许一个代码块在执行,与之相反的是Java 和 C++ ,基于线程的软件而言,多线程同步(同时访问并改变状态),程序很难维护并保证不会出错。
事件和回调函数(嵌套,回调地狱,实现复杂的功能,有局限性。例如:并行执行两个异步操作,当两个操作都结束时通知你;或者同时进行两个异步操作,只取优先完成的操作结果。那么,你需要跟踪多个回调函数并清理这些操作)不足以满足开发者…,但promise可以。为什么它可以?
来源:《深入理解ES6》
二:Posmise 基础知识
Prosmise 相当于异步操作结果的占位符,它不会去订阅一个事件,也不会传递一个回调函数给目标函数,而是让函数返回一个Promise.
// redeFile 承诺将在未来的某个时刻完成
let promise = readFile("example.txt");
//在这段代码中,readFile()不会立即开始读取文件,
//函数会先返回一个表示异步读取操作的Promise对象,
//未来对这个对象的操作完全取决于Promise的生命周期
生命周期:进行中(pending),此操作尚未完成,所以它也是未处理(unsettled),异步操作执行结束,已处理。
Fulfilled: Promise 异步操作成功完成。
Rejected:由于程序错误,或一些其他原因,Promise异步操作未能成功完成。
为什么有异步?
单线程和异步
应用场景
回调地域,promise
js和Dom渲染在同一个线程,js能够操作dom,那么要么只是执行js代码,要么进行Dom渲染
异步是为了解决单线程等待的问题
- js编程语言的特点:单线程语言(准确来说,是与运行的环境(
浏览器中的某个渲染线程)及使用的场景模式有关),也就是说js代码只能同时做一件事 (其他的js,资源加载,打印机),卡住就会导致后面的代码无法执行,那么异步编程的概念就由此而建立使用的。
...
三:Js-web-api
DOM
BOM
事件
ajax
存储
四:开发环境
Git
常用命令含义(常规操作)
git config user.name xxx
git config user.email xxx
git add./文件名(全部/文件)
git commit -m ""
git push origin master : 远程仓库和本地仓库 都有master.
git diff 查看修改的所有内容
git status 查看当前仓库的状态
git log 当前所有提交记录(有个commit 编码)
git show + commit 编码 某个记录的提交内容
git branch 看当前分支
git pull origin master 拉去代码(更新代码)
常用操作
- git clone git@....文件链接(当前目录由https ⇒ git 的方法: git remote set-url origin git@github.com:xxxx/xxx.git)
- ll 看 当前目录 查看 ssh id_rsa.pub (cat ~ ./ssh/id_ras.pub) 桌面前往文件 (shift + command+g) 公钥
- 新建分支 git checkout -b 分支名称
- 分支切换/撤回 git checkout 分支名称 /. (撤回所有修改)或文件名
- 在错误的分支上开发 git stash(放到暂存区) 切换 git checkout 分支名称 git stash pop 最后 常规操作走一遍
- 项目负责人(合并代码)
- git fetch (拉所有分支)
- 到某人分支下(git checkout aaa)
- git pull origin aaa(更新这人的代码)
- git merge aaa(把这人的分支合并到主分支。
- git push origin master(推到远程仓库)
** git merge 后 是需要 git push 到远程。此外,合并冲突在vscode 解决之后,也要看看git status ,然后 git add. ⇒git commit - m "" ⇒git merge ⇒ git push
Chrome 调试工具(技能手动)
常用模块
Elements
Console
debugger
Network
Application
抓包
移动端h5页 查看网络请求 需要工具抓包
windows fiddler
mac os charles
手机 电脑连同一局域网
将手记代理到电脑
手记浏览网页
查看网络请求
网址代理
https
webpack打包 babel转移(代码实操)
ES6模块化,浏览器暂不支持
ES6语法,浏览器并不完全支持
压缩代码,整合代码,让页面加载更快
npm init -y
真题
1.事件代理(委托)
2.闭包?特性?影响?
自由变量,函数执行完(内存会被释放)
//- 内存不会被释放
1.函数作为返回值
function c(){
let a = 100; //不会被释放
return function (){
console.log(a)
}
}
let fn = c();
let a = 200; // 会被释放
fn(); // 100
2.函数作为参数
function p(fn){
let a =200;
fn();
}
let a = 100;
function fn(){
console.log(a)
}
p(fn) // 100