方方-前端体系课程(三)

文章目录

20.【JS全解】JavaScript 概览

20.1 视频:学JS的基本要求

  • 软要求
    • 逻辑能力
    • 质疑自己的能力
      不要相信人类, 包括你自己
      在这里插入图片描述
      通过double check可以缓解
    • 抽象思维
      高级程序员必备能力
      在这里插入图片描述
  • 硬要求
    • 足够的代码量
      如何统计自己的代码行数
      • 安装
        yarn global add cloc
        统计该文件夹代码(cloc = count line of code)
        cloc --vcs=git .
      • 注意
        如何仓库有node_modules目录等不相关内容
        需要吧/node_modules/写入 .gitignore文件
    • 了解足够多的概念
      • 常用常考
        闭包, 原型
        类, 继承
        MVC, Flux
        高级函数
        前端工程化
      • 如何积累
        在课程中提炼
        在大脑中思考
        在博客上总结
        在代码中实践
    • 有足够的采坑经验
      • 何为专家
        把该领域内所有的错误都犯完的人, 就是专家
      • 如何踩坑
        做项目, 而且是个人项目
        个人项目的意思是所有代码都是你一个人写的
        这样才可以全方位踩坑

20.2 视频:JS的历史

JS之父-布兰登(Brendan Eich)

ECMAScript标准的制定:

  • 1997年6月, 第一版ECMAScript发布
  • 1999年12月, 第三版发布, 这个版本使用最广
  • 第四版, 流产.
  • 2009年12月, 第五版发布, 增加了一些功能
  • 2015年6月, 第六版发布, 新浏览器都支持这一版
  • 之后每年发布一版, 版本号以年份命名

JS与ECMAScript的关系

  • ECMAScript是纸上的标准, JS是浏览器的实现.
  • 纸上标准往往落后浏览器, 先实现, 再写进标准

JS的兴起:

  • 2004年愚人节, 谷歌发布Gmail在线网页
  • 2005年, jesse将谷歌用到的技术命名为AJAX
  • 2006年, jQuery发布(很好的兼容的IE浏览器 ), 是 目前最长的JS库, 直到IE不行了, 稍微不火.

20.3 视频:中国前端的发展

前端的来源:

  • 一部分来自自学的后端程序员, 他们把Java的思想代入JavaScript, 面向对象成了JS的主流思想.
  • 一部分来自设计师, 他们开始学习CSS, 并独创了 「重构工程师」岗位(现已没落)

缺人:

  • 大学没有推出相关课程
  • 由于早期前端工资比不上后端, 所有大部分人选后者
  • 高材生选择机器学习
  • 一不小心进入前端领域科班生成长迅速

V8快如闪电:

  • Chrome的JS引擎叫做V8(V1到V7是其他语言的引擎)
  • 2009年, Ryan基于V8创建了Node.js
  • 2010年, Isaac基于Node.js写出了npm

总结:

  • JS是历史的选择:

    • 一开始浏览器支持很多东西:Java, Flash, VBScript
    • 只有JS活到最后
  • JS的低开高走:

    • 一开始JS就是一个玩具语言
    • 但是JS每次都走对了风口
  • 学习JS时需注意:

    • 旧的, 过时的东西了解就好, 考前记忆一些
    • 跟IE相关的知识一律忽略

21.【JS全解】内存图与JS世界(精品课)

21.1 视频:进程与线程

在这里插入图片描述
一切都在内存中运行

  • 开机:

    • 操作系统在c盘里(macOS在根目录下多个目录里)
    • 按下开机键, 主板通电, 开始读取固件(固件就是固定在主板上的存储设备, 里面有开机程序)
    • 开机程序将文件里的操作系统加载到内存中运行
  • 操作系统(以Linux为例)

    • 首先加载操作系统内核
    • 然后启动初始化进程, 编号为1, 每个进程都有编号.
    • 启动系统服务: 文件, 安全, 联网
    • 等待用户登录:输入密码登录/ssh登录
    • 登录后, 运行shell, 用户就可以和操作系统对话
    • bash也是一种shell, 图形化界面可认为是一种shell
  • chrome.exe

    • 双击Chrome图标, 就会运行chrome.exe文件
    • 开启Chrome进程, 作为主进程
    • 主进程会开启一些辅助进程, 如网络服务, GPU加速
    • 你每创建一个网页, 就有可能会开启一个子进程
  • 浏览器的功能

    • 发起请求, 下载HTML, 解析HTML, 下载CSS, 解析CSS, 渲染界面, 下载JS, 解析JS, 执行JS等
    • 功能模块: 用户界面, 渲染引擎, JS引擎, 存储等(一般各自处于不同的线程)
      在这里插入图片描述

21.2 视频:JS引擎

JS引擎:

  • Chrome用的是V8引擎, C++编写的
  • 网景用的是
  • spiderMonkey, 后被Firefox使用, C++
  • Safari用的是JavaScriptCore
  • IE用的是 Chakra(JScript9)
  • Edge用的是Chakra(JavaScript), 现在内核用的是V8.
  • Node.js用的是V8引擎

JS引擎的主要功能:

  • 编译: 把JS代码翻译为机器能执行的字节码或机器吗
  • 优化:改写代码, 使其更高效
  • 执行:执行上面的字节码或机器码
  • 垃圾回收: 把JS用完的内存回收, 方便之后再次使用

21.3 视频:瓜分内存

准备工作:

  • 提供API:window, document, setTimeout(这些不是JS自身具备的功能)
  • 以上的API称为运行环境runtime env

JS运行在内存中
在这里插入图片描述
红色区域的作用:

  • 红色区域用来存放数据
  • 红色区域并不存放变量名, 变量名在「不知什么区」
  • 每一种浏览器的分配规则并不一样
  • 上图的区域并不完整, 没有画调用栈, 任务队列等区域

Stack和Heap

  • 红色区域分为Stack栈和Heap堆
  • Stack区特点: 每次数据顺序存放
  • Heap区特点: 每次数据随机存放

规律:

  • 数据分为两种: 非对象(数字, 字符串, boolen)和对象
  • 非对象都存放在Stack
  • 对象都存放在Heap
  • =号总是会把右边的东西复制到左边(不存在什么传值和传地址)

21.4 视频:JS入门三座大山之原型

JS的世界需要的前提:

  • window
    以下的都是挂到window, 挂在window上可以在任何地方直接用
    • console
    • document
    • object
      var person = new Object()等价于var person = {}(前者正规写法, 后者方便好用)
    • array
      var a = new Array(1, 2, 3)等价于var a = [1, 2, 3](同上)
    • function
      var f = new Function() 等价于 function f(){}(同上)

在这里插入图片描述
更简单的画法(灰色部分是不存在的,首字母大写的, 一般都有prototype属性):
在这里插入图片描述
window细节:

  • window变量和window对象是两个东西
  • window变量是一个容器, 存在window对象的地址
  • window对象是Heap里的一坨数据

同理:

  • console和console对象不是同一个东西
  • Object和Object函数对象不是同一个东西
  • 前者是内存地址, 后者是一坨内存

21.5 视频:JS世界

以下代码为什么可以运行, 不报错?

var obj = {}
obj.toString()

obj有一个隐藏属性, 隐藏属性存储了Object.prototype对象的地址, obj.toString()发现obj上没有toString, 就去隐藏属性对应的对象里面找, 于是就找到了Object.prototype.toString

在这里插入图片描述

原型让你无需重复声明共用属性

每一个对象都有一个隐藏属性(指向原型(对象))

隐藏属性: __proto__

暂时只理解:

  • 每个大写字母开头的对象只关心prototype
  • 小写开头的对象关心__proto__

21.6 视频:犀利提问

22.【JS全解】Canvas 实践—画图板

22.1 视频:画点

用div来模仿简单画图工具, 但是用JS来操作HTML性能低下.

<!DOCTYPE html>
<html lang="ch-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div id="canvas"></div>
    <script>
        canvas.onmousemove = (e) => {
            console.log(e)
            console.log(e.clientX)
            console.log(e.clientY)
            let div = document.createElement('div')
            div.style.position = 'absolute'
            div.style.left = e.clientX + 'px'
            div.style.top = e.clientY + 'px'
            div.style.width = '6px'
            div.style.height = '6px'
            div.style.marginLeft = "-3px"
            div.style.marginTop = "-3px"
            div.style.borderRadius = '50%'
            div.style.background = 'black'
            canvas.appendChild(div)
        }
    </script>
</body>

</html>
* {
    border: 0;
    padding: 0;
    box-sizing: border-box;
}

#canvas {
    height: 100vh;
    border: 1px solid red;
}

22.2 视频:画线

使用canvas来模仿简单画图工具

@@@canvas类似image,可以直接设置宽高, 但是会被CSS覆盖@@@
@@@canvas必须直接设置好宽高, 不然css覆盖后会不清晰@@@
@@@canvas默认display:inline@@@

<!DOCTYPE html>
<html lang="ch-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <canvas id="canvas" width="100" height="100"></canvas>
    <script>
        function drawLine(x1, y1, x2, y2) {
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.stroke();
        }

        let canvas = document.getElementById('canvas');

        // 获取当前浏览器的宽高
        canvas.width = document.documentElement.clientWidth
        canvas.height = document.documentElement.clientHeight

        // 画线
        let ctx = canvas.getContext('2d');
        // 图形的填充颜色
        ctx.fillStyle = 'green';
        // 图形轮廓的颜色
        ctx.strokeStyle = 'green'
        ctx.lineWidth = '30'
        // 将线的两头变圆
        ctx.lineCap = "round";

        //开关
        let painting = false;
        // 记录上一次的clientX, clientY
        let last

        // 按下开始画
        canvas.onmousedown = (e) => {
            painting = true
            last = [e.clientX, e.clientY]
        }

        canvas.onmousemove = (e) => {
            if (painting === true) {
                drawLine(last[0], last[1], e.clientX, e.clientY)
                last = [e.clientX, e.clientY]
            }
        }

        // 松开停止画
        canvas.onmouseup = (e) => {
            painting = false
        }
    </script>
</body>

</html>
* {
    border: 0;
    padding: 0;
    /* 这里我和方方老师不一样的地方, body多了margin:8px, 则我这里初始化一下margin为0, 可达到刷新页面没有滚动条效果*/
    margin: 0;
    box-sizing: border-box;
}

#canvas {
    display: block;
}

使用canvas来模仿简单画图工具(兼顾手机端)

<!DOCTYPE html>
<html lang="ch-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <canvas id="canvas" width="100" height="100"></canvas>
    <script>
        function drawLine(x1, y1, x2, y2) {
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.stroke();
        }

        let canvas = document.getElementById('canvas');

        // 获取当前浏览器的宽高
        canvas.width = document.documentElement.clientWidth
        canvas.height = document.documentElement.clientHeight

        // 画线
        let ctx = canvas.getContext('2d');
        // 图形的填充颜色
        ctx.fillStyle = 'black';
        // 图形轮廓的颜色
        ctx.strokeStyle = 'black'
        ctx.lineWidth = '4'
        // 将线的两头变圆
        ctx.lineCap = "round";


        // 记录上一次的clientX, clientY
        let last

        // 判断是手机还是PC
        var isTouchDevice = 'ontouchstart' in document.documentElement;

        if (isTouchDevice) {
            canvas.ontouchstart = (e) => {
                let x = e.touches[0].clientX
                let y = e.touches[0].clientY
                last = [x, y]
            }
            canvas.ontouchmove = (e) => {
                let x = e.touches[0].clientX
                let y = e.touches[0].clientY
                drawLine(last[0], last[1], x, y)
                last = [x, y]
            }
        } else {

            //开关
            let painting = false;
            // 按下开始画
            canvas.onmousedown = (e) => {
                painting = true
                last = [e.clientX, e.clientY]
            }

            canvas.onmousemove = (e) => {
                if (painting === true) {
                    drawLine(last[0], last[1], e.clientX, e.clientY)
                    last = [e.clientX, e.clientY]
                }
            }

            // 松开停止画
            canvas.onmouseup = (e) => {
                painting = false
            }
        }
    </script>
</body>

</html>
* {
    border: 0;
    padding: 0;
    /* 这里我和方方老师不一样的地方, body多了margin:8px, 则我这里初始化一下margin为0, 可达到刷新页面没有滚动条效果*/
    margin: 0;
    box-sizing: border-box;
}

#canvas {
    display: block;
}

23.【JS全解】JS语法

23.1 视频:JS语言评价

JS版本:

  • ES3, IE6支持, 总体评价:垃圾
  • ES5, 总体评价:还是垃圾
  • ES6, 大部分浏览器支持, 总体评价:一半垃圾(兼容旧版本:稳定), 一半好
  • ES 2019与ES6差别不大

一门语言的价值:由其产生的价值决定

  • JS是世界上使用最广的语言
  • JS是门槛极低的语言(只要你不学糟粕)
  • JS是一门能产生生产价值的语言(虽然不美)

JSON之父-道格拉斯.克罗克福特(Douglas Crockford)

23.2 视频:表达式, 语句, 标识符

表达式:

  • 1 + 2表达式的为3
  • add(1+2)表达式的值为函数的返回值
  • console.log表达式的值为函数本身
  • @@@
    console.log(3)表达式的值为:undefined
    @@面试题@

语句: var a = 1 是一个语句

表达式与语句的不同:

  • 表达式一般都有值, 语句可能有
  • 语句一般会改变环境(变量, 赋值)
  • 以上两句话并不是绝对的

大小写敏感

空格大部分没有实际意义

回车:
@@@
只有return后不能加空格,不然返回值就是默认为undefined
@@面试题@

标识符:

  • Unicode字母(不仅仅是英文字母)
  • $
  • _
  • 中文
  • 以上四种开头都行

注释:

  • 不好的注释:
    • 把代码翻译成中文
      没必要, 可能会隐藏关键的注释
    • 过时的注释
      注释中有一些时长改变的值, 有事会忘记改, 从而可能会导致一些影响.
    • 发泄不满的注释
      程序员要有自己的素养, 发泄情绪不要在职业上.
  • 好的注释:
    • 踩坑的注释
      描述踩坑, 怎么解决这个坑等, 方便日后的接手的程序员方便阅读
    • 为什么代码会写的这么奇怪
      因某种原因, 这部分代码不符合常规, 需要描述说明
    • 遇到什么bug
      遇到bug, 无论解决否都需要注释一下, 方便以后维护, 以及若解决了, 注释上解决方案.

区块block(常常与if/ for/ while合用):

{
	let a = 1
	let b = 2
}

23.3 视频:if…else…语句

if(表达式){语句1}else{语句2}

a = 1
if(a === 2)
	console.log('a')
	console.log('a等于2')

在这里插入图片描述

最推荐的写法:

if (表达式) {
    语句
} else if (表达式) {
    语句
} else {

}

@@@
以上的else if本质上是两个if语句拼接的第一个else部分省略了区域block, 则直接接了另一个if语句, 同时逻辑感觉就是else if.

if (表达式) {
    语句
} else 
	if (表达式) {
	    语句
	} else {

}

@@细节@

次推荐的语句:

function fn(){
    if(表达式){
        return 表达式
    }
    if(表达式){
        return 表达式
    }
    return 表达式
}

switch语句:
大部分情况下都需要加break, 设置break的初衷就是为了, 2个case在一个下执行. 一些新的语言如swift就不需要break了, 若存在多种情况直接在case后用,隔开即可.

三元运算符(问好冒号表达式):表达式1 ? 表达式2 : 表达式3

&&短路逻辑:

  • A&&B&&C&&D取第一个假值或者D
  • @@@
    并不会去true/false
    @@细节@
  • 用的最多的情况为:fn函数存在
fn && fn()

||短路逻辑:

  • A||B||C||D取第一个真值或者D
  • @@@
    并不会去true/false
    @@细节@
  • 用的最多的情况为:保底值
A = A || 100

23.4 视频:while, for循环语句

while循环这里Chrome会莫名多输出一个10, 但是下面接一个console.log就没有了.
在这里插入图片描述
@@@

while(a !== 1){
	console.log(a)
	a = a + 0.1
}

这是一个死循环, 原因浮点数
在这里插入图片描述
@@面试题@

@@@
加入setTimeout会过一会执行, 则输入的都是5
在这里插入图片描述
新语法中用let替代var则可以避免这种问题
在这里插入图片描述
@@面试题@

label:

{
	foo:1
}

24.【JS全解】JS数据类型

24.1 视频:数据类型

  • JS中, 数字使用64位浮点数的形式存储的
  • JS中, 字符串是用类似UTF8形式存储的(UCS-2)

ASCII码中:

  • 0: 48

  • A: 65

  • a: 97

  • GB2312(国标2312):一开始用这个来给汉字编号, 但是只收录了6000多的汉字, 西文字母和日文假字

  • GBK(国标扩): 因GB2312的局限, 微软推出了国标扩展, 收录了21886个汉字和图形符号, 收录了中日韩使用的几乎所有汉字完全兼容GB2312

  • GB18030:后来国标局推出了GB28030, 但是不兼容GB2312, 所以不受欢迎.

  • Unicode: 后来, 又多了藏文, 泰文等,万国码就诞生了, 收录了13万字符(大于16位), 全世界通用(以后还会继续更新), 但是缺点第一, 两个字节不够用, 每个字节要用三个及以上字节, 第二, 所以这样所有文件都扩大50%.

  • UTF-8:最少可用8位存一个字符, 相对Unicode优化了Unicode来带的缺点.

24.2 视频:数字number

写法:

  • 整数写法:1
  • 小数写法:0.1
  • 科学计数法:1.23e4
  • 八进制写法(用的少): 0123, 00123, 0o123
  • 十六进制写法: 0x3F, 0X3F
  • 二进制写法: 0b11, 0B11

特殊值:

  • 正0和负0:都等于0, 要严谨
  • 无穷大: infinity, +infinity, -infinity
    在这里插入图片描述
  • 无法表示的数字: NaN(Not a Number), 但是是一个数字

64位浮点数:
浮点就是浮动的店, 意思就是小数点会动
123.456可以表示为1.23456e10^2,
也可以表示为12345.6e10/^-2
在这里插入图片描述

  • 符号占1位
  • 指数占11位(-1023~1024)
  • 有效数字占52位(开头的1省略)

范围和精度:

  • 范围(忽略符号位)
    • 最大值
    Number.MAX_VALUE
    1.7976931348623157e+308
    
    *最小值
    Number.MIN_VALUE
    5e-324
    
  • 精度(有效数字)
    2^53: 9007 1992 5474 0992

24.3 视频:字符串String

写法:

  • 单引号
    ‘你好’
  • 双引号
    “你好”
  • 反引号(推荐)
    `你好`

转义:

  • \uFFFF 表示对应的Unicode字符
  • \xFF 表示对应的Unicode前256个字符
    在这里插入图片描述
    如果有多个换行现在推荐用反引号:
    在这里插入图片描述
    字符串的属性:
  • length
  • string[index]

base64转码: 一般用于隐藏邮箱

  • window.btoa: 正常字符串转为Base64编码的字符串.
  • window.atob:Base64编码的字符串转为原来的字符串.

在这里插入图片描述

24.4 视频:布尔值boolen

@@@
5个falsy值:

  • undefined
  • null
  • 0
  • NaN
  • ''
    @@细节@

24.5 视频:两个空undefined和null

JS的原(La)创(Ji)之处
区别(没有本质区别):

  • 如果一个变量声明了, 但没有赋值, 那么默认值就是undefined, 而不是null
  • 如果一个函数, 没有写return, 那么默认return为undefined, 而不是null
  • 前端程序员习惯上, 把非对象的空值写为undefined, 把对象的空值写为null, 但这仅仅只是习惯上.

symbol符号:不怎么常用的数据类型
JS 中的 Symbol 是什么?

24.6 视频:变量声明

三种声明方式:

  • var a = 1
  • let a = 1
  • const a = 1

区别:

  • var是过时的(ES3), 不好用的方式
  • let是新的, 更合理的方式
  • const是声明时必须赋值, 且不能再改的方式

let声明:

  • 遵循块作用域, 即使用范围不超过{}

  • 不能重复声明

  • 可以赋值, 也可以不赋值

  • 必须先声明再使用, 否则报错

  • 全局声明的let编码, 不会变成window的属性
    在这里插入图片描述

  • for循环配合let有奇效(for循环部分展示过了)

  • const声明

  • 跟let几乎一样

  • 唯一不同:声明时就需要赋值, 赋值后不能改

24.7 视频:类型转换

  • number -> string
var n = 1
undefined
String(n)
"1"
//通常使用以下这种
n + ''
"1"
  • string -> number
var s = '1'
undefined
Number(s)
1
//通常使用以下方式
s - 0
1
+s
1
  • x -> bool
var s = 1
undefined
Boolean(s)
true
//通常使用以下这种
!!s
true

x -> string

var s = true
undefined
s.toString()
"true"
1..toString()
"1"
1 .toString()
"1"
(1).toString()
"1"

25.【JS全解】JS 对象

25.1 视频:对象的语法

七种数据类型:

  • 4基: number, string, boolen, symbol
  • 2空: null, undefined
  • 1对象: object

五种falsy值:

  • null
  • undefined
  • 0
  • ‘’
  • NaN(Not A Number)

对象定义:

  • 无序的数据集合
  • 键值对的集合

写法:

//常用写法
let obj = {'name': 'zxc', 'age': 23}
//规范写法
let obj2 = new Object({'name': 'zxc', 'age': 23})
//可以直接console.log一个无名对象, 注意:不要和lable混淆了.
console.log({'name': 'zxc', 'age': 23})
{name: "zxc", age: 23}

细节:

  • 键名是字符串, 不是标识符, 可以包含任意字符.
  • 引号可省略, 省略之后就只能写标识符
  • @@@
    就算引号省略了, 键名还是字符串
    @@细节, 重要@

奇怪的属性名(都是字符串):
在这里插入图片描述

变量作为属性名:
在这里插入图片描述
以前的写法(变量作为属性名):
在这里插入图片描述
对象的隐藏属性:

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

超纲知识:
除了字符串, symbol也能做属性名

let a = Symbol()
let obj = {[a]: "Hello"}

25.2 视频:删属性

删除属性和查看是否含有该属性名:
在这里插入图片描述
不能用obj.xxx === undefined 来判断xxx是否为obj的属性

25.3 视频:查属性

查看自身所有属性名:Object.keys(obj)
查看自身所有属性值:Object.values(obj)
查看自身以及共用属性:console.dir(obj)推荐这种, obj.__proto__推荐前面这种
判断一个属性是自身的还是共用的: obj.hasOwnProperty('toString')

原型:

  • 原型里面存着对象的共用属性
  • 比如obj的原型就是一个对象
  • obj.__proto__存着这个对象的地址

原型也是对象:

  • 原型也是有原型的
  • 原型是对象的跟
  • 虽然原型有原型, 但是为null
    在这里插入图片描述

查看属性:
中括号语法: obj[‘key’]
点语法: obj.key

25.4 视频:写属性

批量赋值:
Object.assign(obj, {age: 23, gender: “men”})

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

let obj = {}, obj = {}//共用toString属性
obj.toString = 'xxx'//只会在改obj自身属性
obj2.toString //还是原型上的

偏要修改或增加原型的属性:一般来说不要修改, 会引起很多问题, 这也是JS的脆弱之处.

obj.__proto__toString = 'xxx' //推荐使用下面这种
Object.prototype.toString = 'xxx'//推荐使用这种

修改隐藏属性:

//不推荐使用__proto__这种
let obj = {name: 'zxc'}
let obj2 = {name: 'cxz'}
let common = {kind: 'human'}
obj.__proto__ = common
obj2.__proto__ = common
//推荐使用这种
//Object.create尽量初始化空对象, 然后再进行追加, 这样方便.
let obj = Object.create(common)
obj.name = 'zxc'
let obj2 = Object.create(common)
obj2.name = 'cxz'

推荐的理由: 要改就一开始就要改, 别后面再改

26.【JS全解】JS 对象分类

26.1 视频:构造函数

输出正方形的面积和长度:

  1. 利用原型:为了解决每次都开辟新的内存空间, 来使用原型来共用对象的属性.
let squareList = []
let widthList = [5, 6, 5, 6, 5]
let squarePrototype = {
	getArea(){
		return this.width * this.width
	},
	getLength(){
		return this.width * 4
	}
}

for(let i = 0; i<12; i++){
	squareList[i] = Object.create(squarePrototype)
	squareList[i].width = widthList[i]
}
//创建square的代码太分散
  1. 抽离到函数:为了解决square太分散, 那就把代码抽离到一个函数里, 然后调用函数
let squareList = []
let widthList = [5, 6, 5, 6, 5]
//此函数叫做构造函数:构造对象的函数就是构造函数
function createSquare(width){
	//以squarePrototype为原型创建空对象
	let obj = Object.create(squarePrototype)
	obj.width = width
	return obj
}
let squarePrototype = {
	getArea(){
		return this.width * this.width
	},
	getLength(){
		return this.width * 4
	}
}
for(let i = 0; i<12; i++){
	squareList[i] = createSquare(widthList[i])
}
//squarePrototype原型和createSquare函数还是分散的
  1. 函数和原型的结合:为squarePrototype原型和createSquare函数还是分散的,将两者结合起来,使得更紧密.
let squareList = []
let widthList = [5, 6, 5, 6, 5]
function createSquare(width){
	let obj = Object.create(createSquare.squarePrototype)
	obj.width = width
	return obj
}
//因为函数也是一个对象, 则这里可以直接用点访问形式.
createSquare.squarePrototype = {
	getArea(){
		return this.width * this.width
	},
	getLength(){
		return this.width * 4
	},
	//方便通过原型找到构造函数
	constructor: createSquare
}
for(let i = 0; i<12; i++){
	squareList[i] = createSquare(widthList[i])
	//constructor 可以知道谁够着了这个对象
	console.log(squareList[i].constructor)
}
  1. 函数和原型结合(重写): 通过new操作符来重写
let squareList = []
let widthList = [5, 6, 5, 6, 5]
function Square(width){
	//JS之父帮你写了这句let obj = Object.create(createSquare.squarePrototype)
	this.width = width
	//JS之父帮你写了这句return obj
}
//因为函数也是一个对象, 则这里可以直接用点访问形式.
Square.prototype.getArea = {
	return this.width * this.width
}
Square.prototype.getLength = {
	return this.width * 4
}
for(let i = 0; i<12; i++){
	squareList[i] = new Square(widthList[i])
	//constructor 可以知道谁够着了这个对象
	console.log(squareList[i].constructor)
}

对比:
在这里插入图片描述
@@@
总结:

  • new X()自动做了四件事情:JS之父的❤️
    • 自动创建对象
    • 自动为空对象关联原型, 原型地址指定为X.prototype
    • 自动将空对象作为this关键字运行构造函数
    • 自动return this
  • 构造函数X:
    • X函数本事负责给对象本身添加属性
    • X.prototype对象负责保存对象的共用属性

代码规范:

  • 大小写:
    • 所有构造函数(专门用于创建对象的函数)
    • 所有被构造出来的对象, 首字母小写
  • 词性:
    • new后面的函数, 使用名词形式: 如new Person(), new Object()
    • 其他函数, 一般使用动词开头: 如createSquare(5), createElement(‘div’)
      @@细节, 重点@

26.2 视频:原型与公用属性的关系

在这里插入图片描述
结论: 你是谁构造的你的原型就是谁的prototype对应的对象
原型公式: 对象.proto === 其构造函数.prototype
在这里插入图片描述
参考资料:JS 中 proto 和 prototype 存在的意义是什么?

Object的属性的值为途中右边的window.object值下面的#101, Object:#101起到了一个找到这个对象的作用.
为什么直接打印对象的时候的时候, 是直接打印出来的对象的属性?
在这里插入图片描述
@@@
Object.prototype是由Object函数构造出来的.
Object.prototype的原型是: Object.prototype.__proto__ = null
在这里插入图片描述

@@细节@

26.3 视频:对象需要分类

26.4 视频:类型 V.S. 类

类型:类型是JS数据的分类, 有7种(4基2空1对象)
类:类是针对对象的分类, 有无数种, 常见的有Array, Funciton, Date, RegExp等

@@@
JS终极一问:

  • window是谁构造的: Window
    在这里插入图片描述
  • window.Object是谁构造的:window.Function(所有的函数都是window.Function构造的)
    在这里插入图片描述
  • window.Function 是谁构造的:window.Funciton(通过上帝(浏览器)构造了Function, 然后自己构造自己)
    在这里插入图片描述
    @@细节@

26.5 视频:class语法

class现在是主流, 但是prototype也不过时, 角度不一样:我为什么一定要学 prototype?
ES6新语法class:跟方方老师学, 老师教的都是常用的

class Square{
	constructor(width){
		this.width = width
	}
	//函数的两种写法都对
	//新语法
	getArea(){
		return this.width * this.width
	}
	//旧语法
	getLength: fucntion(){
		return this.width * 4
	}
}

方方老师总结的ES6的新语法

类和对象的新语法:

27.【JS全解】JS数组

27.1 视频:数组是什么

数组对象是一种特殊的对象, JS其实没有真正的数组(只是用对象模拟数组)

典型的数组:

  • 元素的数据类型相同
  • 使用连续的内存存储
  • 通过数字下表获取元素

JS的数组:

  • 元素的数据类型可以不同
  • 内存不一定是连续的(对象是随机存储的)
  • 不能通过数字下表, 而是通过字符串下标

创建一个数组:

  • 新建
let arr = [1, 2, 3]
let arr = new Array(1, 2, 3,)
//创建长度为3的数组
let arr = new Array(3)
  • 转化
let arr = '1, 2, 3'.split(',')
let arr = '123'.split('')
//字符串和带length的数组可以一下方式转化为数组
Array.from('123')
Array.from({0:'a', 1:'b', length:2})
  • 伪数组
    伪数组的原型链中并没有数组的原型
    <div>1</div>
    <div>2</div>
    <div>3</div>

    <script>
        //获取出来的不是数组
        let divList = document.querySelectorAll('div')
        //需要转换为数组
        let divArr = Array.from(divList)
        console.log(divArr)
    </script>

在这里插入图片描述
@@@
没有数组共有属性的「数组」就是伪数组
@@重点, 细节@

  • 合并两个数组,的到一个新数组
    arr1.concat(arr2)
  • 截取一个数组的一部分
    @@@
    JS只提供浅拷贝
    @@细节@
//从第二个元素开始
arr1.slice(1)
//全部截取(可以拷贝一个数组) 
arr1.slice(0)

27.2 视频:删除数组中的元素

  • 跟对象一样:
    在这里插入图片描述
    数组的长度并没有变, 稀疏数组

  • 直接修改length可以删元素:
    不要随便改length长度
    以上两种都不是删数组元素的方法.

删数组元素:

  • 删除头部的元素
    arr.shift(), arr被修改, 并返回被删除的元素
  • 删除尾部的元素
    arr.pop(), arr被修改, 并返回被删除的元素
  • 删除中间的元素
//删除index的一个元素, 1表示删除长度
arr.splice(index, 1)
//并在删除位置添加'x'
arr.splice(index, 1, 'x')
//并在删除位置添加'x', 'y'
arr.splice(index, 1, 'x', 'y')

27.3 视频:遍历数组

查看所有属性名:

let arr=[1, 2,3 ,4, 5]
arr.x = 'xxx'
Object.keys(arr)
for(let i in arr){
	console.log(`${i}: ${arr[i]}`)
}

@@@
不用以上方法来操作数组, 因为数组是索引是下标0到length-1的数
@@细节@

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

  • for循环
  • forEach
arr.forEach(function(item, index, array){
	console.log(`${index}: ${item}`)
})

自己实现forEach

function forEach(array, fn){
	for(let i = 0; i<array.length; i++){
		fn(array[i], i, array)
	}
}

forEach([1, 2, 3], function(value, key){
    console.log(key, value)
})

查看单个属性:

  • 索引越界
arr[arr.length] === undefined
arr[-1] === undefined
  • 查看某个元素是否在数组里
    arr.indexOf(item), 存在返回索引, 否则返回-1
  • 使用条件查找元素
    arr.find(item=> item%2 === 0), 找到第一个偶数, 否则返回undefined
  • 使用条件查找元素的索引
    arr.findIndex(item=> item%2 === 0), 找到第一个偶数索引, 否则返回-1

27.4 视频:增加数组中的元素

@@@
在这里插入图片描述
不实用上面直接通过索引来添加数组元素.
@@细节@

  • 在尾部加元素
//修改arr, 返回新长度
arr.push(newItem)
//修改arr, 返回新长度
arr.push(item1,item2)
  • 在头部加元素
//修改arr, 返回新长度
arr.unshift(newItem)
//修改arr, 返回新长度
arr.unshift(item1,item2)
  • 在中间添加元素
//在index处插入'x'
arr.splice(index, 0, 'x')
arr.splice(index, 0, 'x', 'y')
  • 反转顺序
    arr.reverse(), 修改原数组
  • 自定义顺序
    arr.sort()默认是从小到大排序

如果要求从大到小排序呢?
可以使用sort和reverse来实现
但是我就是要用sort来实现呢
原始代码:

//1的话数字从左边开始, -1的话数字从右边开始
arr.sort(function(a, b){
	if(a > b){
		return 1
	}else if(a === b){
		return 0
	}else{
		return -1
	}	
})

简写代码:
arr.sort((a, b)=> a-b)

27.5 视频:数组变换

在这里插入图片描述

  • map: n变n
    在这里插入图片描述
  • filter:n变少
    在这里插入图片描述
  • reduce:n变1
    在这里插入图片描述
    通过reduce来实现平方
    在这里插入图片描述
    通过reduce来实现过滤奇数
    法一:
    在这里插入图片描述
    法二:用三元运算符
    在这里插入图片描述
    法三:通过拼接一个空的[]
    在这里插入图片描述

在这里插入图片描述

28.【JS全解】JS 函数

28.1 视频:四种方式定义函数

@@@
JS中函数是对象
@@细节@

  1. 具名函数
function 函数名(形式参数1, 形式参数2){
	语句
	return 返回值
}
  1. 匿名函数:具名函数去掉函数名就是匿名函数
    let a = function(x, y){return x+y}
    function(x, y){return x+y}部分叫做函数表达式

  2. 箭头函数

let f1 = x => x*x
let f2 = (x,y) => x+y
let f3 = (x,y) => {return x+y}

@@@
如果要返回一个对象
let f4 = (x, y) => ({name:x, age:y})
@@JS并不是一门好语言@

  1. 用构造函数
let f = new Function('x', 'y', 'return x+y')

基本没人用, 但是能让你知道函数是谁构造出来的
@@@
所有函数都是Function构造出来的
包括: Object, Array, Function
@@细节@

let fn = () => console.log('hi')
let fn2 = fn
fn2()

fn保存了匿名函数的地址
这个地址被复制给了fn2
fn2()调用了匿名函数
fn和fn2都是匿名函数的引用而已
真正的函数既不是fn也不是fn2

28.2 视频:调用时机

刻舟求剑

  • 例5:
let a = 1
function fn(){
	setTimeout(()=>{
		console.log(a)
	}, 0)
}
fn()
a = 2

打印结果为2
类似, 你正在打LOL, 马上最后一波互拆家的时候, 你妈(fn())叫你吃饭, 你是马上, 然后你是先把对面家拆了然后再去吃饭.

  • 例6
let i = 0
for(i = 0; i<6; i++){
	setTimeout(()=>{
		console.log(i)
	}, 0)	
}

答案:6个6
当setTimeout()的毫秒数设置为0的时候,是要先执行完函数调用栈中的代码,然后立即调用定时器。
因为定时器都被放在了一个队列中,等待上下文的可执行代码运行完毕后,才开始运行定时器,也就是定时器才刚开始计时。代码中声明一个let全局变量i,然后在for循环中改变i,所以在定时器的方法执行的时候,变量i已经变成了6,所以输出的全部是6。

这里的互拆家是for循环, 先要把这最后一波打完(循环结束), 此时的i的值为6, 然后再执行6个需要执行的setTimeout打印出6.

  • 例7
    因为例6不符合, 新人思路, 然后JS就’聪明的’用例7来实现新人的想法
for(let i = 0; i<6; i++){
	setTimeout(()=>{
		console.log(i)
	}, 0)	
}

答案:0, 1, 2, 3, ,4, 5
@@@
因为JS在for 和let一起用的时候回加东西, 保留每次循环i的值
每次循环会多创建一个i
@@JS并不是一门好语言@

28.3 视频:作用域 & 闭包

JS中是静态作用域(词法作用域)

JS的全局变量:

  • 在顶级作用域声明的变量
  • window的属性(无论是不是在顶级作用域定义)

作用域原则: 就近原则

闭包:
在这里插入图片描述

28.4 视频:参数和返回值

形式参数的意思就是非实际参数:

function add(x, y){
	return x+y
}
add(1, 2)

其中x和y就是形参, 因为并不是实际的参数
调用add时, 1和2是实际参数, 会被赋值给x和y

上面声明add函数代码等价于

function add(){
	var x = arguments[0]
	var y = arguments[1]
	return x + y
}

@@@
JS中形参可多可少
@@JS并不是一门好语言@

@@@
只有函数有返回值, 每一个函数都有返回值
console.log的返回值是undefined
在这里插入图片描述
@@细节@

28.5 视频:调用, 调用栈与爆栈

调用栈:JS引擎在调用一个函数前, 需要吧函数所在的环境push到一个数组里, 这个数组叫做调用栈,等函数执行完了, 就会把环境弹pop出来, 然后return到之前的环境, 继续执行后续代码.

递归: 先递进, 后回归

爆栈:

function computeMaxCallStackSize(){
	try{
		return 1 + computeMaxCallStackSize();
	}catch(e){
		return 1;
	}
}

chrome最多可用的栈:
在这里插入图片描述
函数提升:
function fn(){}
不管你把函数什么放在哪, 它都会跑到第一行

不是函数提升:
let fn=function(){}
这是赋值, 右边的匿名函数声明不会提升

28.6 视频:person.sayHi()的this

@@@
每一个函数的都有arguments和this, 除了箭头函数
@@细节@
在这里插入图片描述
当不传参数的时候, this打印出来的就是window

@@@
传arguments通过直接调用函数fn(), fn(1, 2, 3)那么arguments就是[1, 2, 3]伪数组
可通过Array.from转为数组
@@细节@
@@@
传this, 通过fn.call(xxx, 1, 2, 3)传入this和arguments
而且xxx会被自动转化为对象
在这里插入图片描述
@@JS并不是一门好语言@

方方总结:this是隐藏参数, arguments是普通参数

假设没有this

let person = {
	name: 'bens',
	sayHi(){
		console.log(`你好, 我叫` + person.name)
	}
}

可以直接保存了对象地址的变量获取’name’, 这种方法简称为引用

在这里插入图片描述
在这里插入图片描述
需要一种办法拿到对象, 这样才能获取对象的name属性
在这里插入图片描述
python就用了这种办法:
在这里插入图片描述
在这里插入图片描述
person.sayHi()会隐式地把person作为this传给sayHi, 方便sayHi获取person对应的对象

总结:

  • 我们想让函数获取对象的引用
  • 但是并不想通过变量名做到
  • Python通过额外的self参数做到
  • JS通过额外的this 做到:person.sayHI()会把person自动传给sayHi, sayHi可以通过this引用person

小白调法:
person.sayHi(), 会自动把perosn 传到函数里, 作为this

大师调用法(以后都用这种方法, 清晰明了):
person.sayHI.call(person), 需要自己手动把person传到函数里, 作为this

28.7 视频:call指定this

function add(x, y){
	return x + y
}

没有用到this:
add.call(undefined, 1, 2)

this的两种使用方法:

  • 隐式传递
fn(1, 2) //等价于fn.call(undefined, 1, 2)
obj.child.fn(1)//等价于obj.child.fn.call(obj.child, 1)
  • 显式传递
fn.call(undefined, 1, 2) 
fn.apply(1, [1, 2])

继续实现array.forEach(用this的版本)

function(fn){
	for(let i = 0; i<this.length; i++){
		fn(this[i], i)
	}
}

绑定this:

function f1(p1, p2){
	console.log(this, p1, p2)
}
let f2 = f1.bind({name:'bens'})//那么f2就是f1绑定this之后的函数
f2()//等价于f1.call({name: 'bens'})

还可以绑定其他参数

function f1(p1, p2){
	console.log(this, p1, p2)
}
let f3 = f1.bind({name:'bens'}, 'hi')
f3()//等价于f1.call({name: 'bens'}, 'hi')

28.8 视频:箭头函数

箭头函数:没有arguments和this

里面的this就是外面的this
在这里插入图片描述

28.9 视频:立即执行函数

ES5时代, 为了得到局部变量, 必须引入一个函数, 这个函数有名字, 就得不偿失, 于是这个函数为匿名函数.然后加()执行它,这种语法不合法, 则只能在前面加!
匿名函数直接执行, 前面加!最好
在这里插入图片描述

29.【JS全解】JS 实战,会动的代码

29.1 视频:搞清基本原理

29.2 视频:显示一段话

通过yarn来安装parcel(1.12.4)

yarn global add parcel

通过parcel来运行
parcel src/basics.html

会动的代码

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>会动的代码</title>
</head>

<body>
    <style id="style"></style>
    <span id="demo"></span>
    <script src="main.js"></script>
</body>

</html>

@@@
每x毫秒计时器动一次是setInterval(), 但是不建议用, 推荐使用setTimeout递归.
@@老手建议@

let html = document.querySelector('#demo')
let style = document.querySelector('#style')
let n = 0
let string = `
/*一二三四五
上山打老虎
老虎没达到
打到小松鼠*/
body{
    color:red;
}
`
let string2 = ``
let step = () => {
    setTimeout(() => {
        if (string[n] === '\n') {
            n !== 0 ? string2 += '<br>' : string2
        } else if (string[n] === ' ') {
            string2 += '&nbsp;'
        } else {
            string2 += string[n]
        }
        html.innerHTML = string2
        style.innerHTML = string.substring(0, n)
        console.log(string[n])
        if (n < string.length - 1) {
            n += 1
            step()
        }
    }, 100)
}
step()

29.3 视频:制作太极

通过parcel来运行
parcel src/taiji.html

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>会动的代码</title>
</head>

<body>
    <style id="style"></style>
    <span id="demo"></span>
    <div id="div1"></div>
    <style>
        #div1 {
            position: fixed;
            top: 20px;
            right: 20px;
        }

        #div1::before {
            content: '';
            display: block;
            position: absolute;
        }

        #div1::after {
            content: '';
            display: block;
            position: absolute;
        }
    </style>
    <script src="main.js"></script>
</body>

</html>
let html = document.querySelector('#demo')
let style = document.querySelector('#style')
let n = 0
let string = `
/*一二三四五
上山打老虎
老虎没达到
打到小松鼠*/
#div1{
    border: 1px solid red;
    width: 400px;
    height: 400px;
}

/* 接下来我把, div 变成一个圆
注意看好了
首先, 把div变成一个圆*/
#div1{
    border-radius: 50%;
    box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
    border: none;
}

/* 八卦是阴阳形成的
一黑一白(css gradient background generator)*/
#div1{
    background: linear-gradient(90deg, rgba(255,255,255,1) 0%, rgba(255,255,255,1) 50%, rgba(0,0,0,1) 50%, rgba(0,0,0,1) 100%);
}

#div1::before{
    width: 200px;
    height: 200px;
    background: #000;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255,255,255,1) 0%, rgba(255,255,255,1) 25%, rgba(0,0,0,1) 25%, rgba(0,0,0,1) 100%);
}

#div1::after{
    width: 200px;
    height: 200px;
    background: #fff;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    border-radius: 50%;
    background: radial-gradient(circle, rgba(0,0,0,1) 0%, rgba(0,0,0,1) 25%, rgba(255,255,255,1) 25%, rgba(255,255,255,1) 100%);
}
`

let string2 = ``
let step = () => {
    setTimeout(() => {
        if (string[n] === '\n') {
            n !== 0 ? string2 += '<br>' : string2
        } else if (string[n] === ' ') {
            string2 += '&nbsp;'
        } else {
            string2 += string[n]
        }
        html.innerHTML = string2
        style.innerHTML = string.substring(0, n)
        console.log(string[n])
        if (n < string.length - 1) {
            n += 1
            step()
        }
    }, 0)
}
step()

29.4 视频:永远都要考虑手机端

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
        content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
    <title>会动的代码</title>
</head>

<body>
    <style id="style"></style>
    <div id="html"></div>
    <div id="div1Wrapper">
        <div id="div1"></div>
    </div>

    <style>
        * {
            border: 0;
            padding: 0;
        }

        *::before {
            box-sizing: border-box;
        }

        *::after {
            box-sizing: border-box;
        }

        #html {
            word-break: break-all;
        }

        #div1 {
            position: fixed;
            top: 20px;
            right: 20px;
        }

        #div1::before {
            content: '';
            display: block;
            position: absolute;
        }

        #div1::after {
            content: '';
            display: block;
            position: absolute;
        }

        @media (max-width: 500px) {
            #html {
                height: 50vh;
                overflow: auto;
            }

            #div1Wrapper {
                height: 50vh;
            }

            #div1 {
                position: relative;
                top: 0;
                right: 0;
            }
        }
    </style>
    <script src="main.js"></script>
</body>

</html>
let html = document.querySelector('#html')
let style = document.querySelector('#style')
let n = 0
let string = `
/*一二三四五
上山打老虎
老虎没达到
打到小松鼠*/
#div1{
    border: 1px solid red;
    width: 200px;
    height: 200px;
}

/* 接下来我把, div 变成一个圆
注意看好了
首先, 把div变成一个圆*/
#div1{
    border-radius: 50%;
    box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
    border: none;
}

/* 八卦是阴阳形成的
一黑一白(css gradient background generator)*/
#div1{
    background: linear-gradient(90deg, rgba(255,255,255,1) 0%, rgba(255,255,255,1) 50%, rgba(0,0,0,1) 50%, rgba(0,0,0,1) 100%);
}

#div1::before{
    width: 100px;
    height: 100px;
    background: #000;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255,255,255,1) 0%, rgba(255,255,255,1) 25%, rgba(0,0,0,1) 25%, rgba(0,0,0,1) 100%);
}

#div1::after{
    width: 100px;
    height: 100px;
    background: #fff;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    border-radius: 50%;
    background: radial-gradient(circle, rgba(0,0,0,1) 0%, rgba(0,0,0,1) 25%, rgba(255,255,255,1) 25%, rgba(255,255,255,1) 100%);
}
`

let string2 = ``
let step = () => {
    setTimeout(() => {
        if (string[n] === '\n') {
            n !== 0 ? string2 += '<br>' : string2
        } else if (string[n] === ' ') {
            string2 += '&nbsp;'
        } else {
            string2 += string[n]
        }
        html.innerHTML = string2
        style.innerHTML = string.substring(0, n)
        //PC端滚动条
        window.scrollTo(0, 99999);
        //mobile滚动
        html.scrollTo(0, 99999);
        if (n < string.length - 1) {
            n += 1
            step()
        }
    }, 0)
}
step()

29.5 视频:部署到GitHub Pages

首先parcel要执行(每次修改后都需要这一步)
parcel build src/index.html --public-url .

然后将代码上传到GitHub

最后效果图

30.【JS全解】JS运算符

30.1 视频:JS运算符

  1. 算数运算符
    number运算:
    • 指数x ** 3
    • 自增自减: 尽量只在for循环中使用
      string运算:
      只有+(连接运算), 没有其他的
      不同类型不要加起来 eg:1 + '2'
  2. 比较运算符
  • >
  • <
  • >=
  • <=
  • ==
  • !=
  • ===
  • !==

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
@@@
NaN !== NaN
@@细节, 特例@

  1. 布尔运算符
  • ||
  • &&
  • !

console&&console.log&&console.log('hi'), 以防console不存在报错
a = a || 100, a的保底值, 但是如果是空字符串'', 也是false. 因为5个false(NaN, undefined, null, 0, ‘’)值都会为假.解决方法, 可以在函数参数赋一个默认值.

  1. 二进制运算符
    @@@
    用的很少, 面试的时候看看
    @@面试@
  • |: 或, 两位都为0, 则结果为0, 否则为1
  • &: 与, 两位都为1, 则结果为1, 否则为0
  • ~: 否
  • ^: 异或, 两位结果相同, 则结果为0, 否则为1
  • <<: 左移
  • >>: 右移
  • >>>:头部补零的优益运算符(正数情况下, 与右移效果一样)
    位运算符的妙用

使用与运算判断奇偶:
偶数 & 1 = 0
奇数 & 1 = 1
使用~, >>, <<, >>>, |来取整:
位运算会抹除小数位

console.log(~~ 6.83)
console.log(6.83 >> 0)
console.log(6.83 >>> 0)
console.log(6.83 << 0)
console.log(6.83 | 0)

答案都是6

使用^来交换a b的值

var a = 5
var b = 8
a ^= b
b ^= a
a ^= b
console.log(a)
console.log(b)
  1. 其他运算符
    点运算符:
  • 语法
    对象.属性名 = 属性值
  • 作用
    读取对象的属性值
  • 疑问: 不是对象, 为什么也可以有 属性? 'a-b-c'.split('-')
    JS有特殊逻辑, 点前面不是对象, 就会把它封装成对象.number, stirng和bool会变成Number, String和Boolean对象.(转成对象, 用对象, 对象消失)

void运算符:

  • 语法
    void 表达式或语句
  • 作用
    求表达式的值, 或执行语句, 然后void的值总是为undefined

逗号运算符:

  • 语法
    表达式1, 表达式2, …, 表达式n
  • 作用
    将表达式n的值作为整体的值
  • 使用
    let a = (1, 2, 3), 那么a的值就是3.通常用逗号运算符都要搭配括号使用

为了简写, 2句话不用return
let f = (x) => {console.log('平方值为:'); return x*x}
利用逗号运算符可改写为:
let f = (x) => (console.log('平方值为:'), x*x)

30.2 视频:JS运算符优先级

相同运算符:

  • 从左到右: a + b +c
  • 从右到左: a = b = c =d

@@@
优先级口诀: 元口号优先级最高, 会用圆括号就行了.
@@细节@

31.【JS全解】JavaScript 总结

31.1 视频:拨乱反正

知识点:

  • 基本概念
    内存, 变量, 数据类型和对象
  • 控制语句
    if…else
    for…
  • 对象
    原型, 原型链
    对象分类
    new一个新对象
    构造函数
    this的隐式传递和显式传递

难点:

  • JS三座大山
    原型
    this
    AJAX

@@@

  1. JS公式
    对象.__proto__ === 其构造函数.prototype
    JS唯一公式, 如果不会就套公式

  2. 根公理
    Object.prototype是所有对象的(直接或间接)原型

  3. 函数公理
    所有函数都是由Function构造的
    任何函数.__proto__ === Function.prototype
    任意函数: Object/Array/Function

@@重要的知识@

拨乱反正:

  • 乱一
    • XXX的原型
      {name:'bens'}的原型
      [1, 2, 3]的原型
      Object的原型
    • 解读
      Object的原型是Object.___proto__: 对
      Object的原型是Object.prototype: 错
    • 错在哪
      「的原型」等价于「.__proto__
      中文的「原型」无法区分__proto__和prototype
      我们约定原型默认表示__proto__
      只不过__proto__正好等于某个函数的prototype
  • 乱二
    • 矛盾
      [1, 2, 3]的原型是Array.prototype
      你又说Object.prototype是所有对象的原型
      那为什么Object.prototype不是[1, 2, 3]的原型
    • 错在哪
      原型分两种: 直接原型和间接原型
      对于普通对象来说, Object.prototype是直接原型
      对于数组, 函数来说, Object.prototype是间接原型
  • 乱三
    • Object.prototype不是根对象
    • 理由
      Object.prototype是所有对象的原型
      Object是Function构造出来的
      所以, Function构造了Object.prototype
      推论, Function才是万物之源
  • 错在哪
    Object.prototype和Object.prototype对象的区别
    对象里面从来都不会包含另一个对象

31.2 视频:再画JS世界

JS世界构造的顺序

  1. 创建根对象#101(toString), 根对象没有名字
  2. 创建函数的原型#208(call/apply), 原型__p为#101
  3. 创建数组的原型#404(push/pop), 原型__p为#101
  4. 创建Function#342, 原型__p为#208
  5. 用Function.prototype存储函数的于宁, 等于#208
  6. 此时发现Function的__proto__和prototype都是#208
  7. 用Function创建Object
  8. 用Object.prototype存储对象的原型, 等于#101
  9. 用Function创建Array
  10. 用Array.prototype存储数组的原型, 等于#404
  11. 创建window对象
  12. 用window的Object, Array属性将7和9种的函数命名
  13. 记住一点, JS创建一个对象时, 不会给这个对象的名字的

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

31.3 视频:JS三大定理

在这里插入图片描述

  1. Object.prototype的原型
    在这里插入图片描述
  2. Function.prototype的原型
    在这里插入图片描述
  3. var f = ()=>{}的原型
    在这里插入图片描述
  4. Array.prototype.toString的原型
    在这里插入图片描述
  5. Object的原型
    在这里插入图片描述

总结:

  • 构造函数
    是用来构造对象的
    会预先存好对象的原型, 原型的原型是根
    new的时候将对象的__p指向原型
    在这里插入图片描述

31.4 视频:JS学习计划

  • 第一阶段
    了解JS语法, 特性, 对象, 数组, 函数
    在这里插入图片描述
  • 第二阶段
    了解AJAX, 设计模式, 封装, 面向对象, MVC
  • 第三阶段
    Vue/React全家桶
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值