Web前端第三阶段

阅读: 评论:0

Web前端第三阶段

Web前端第三阶段

Web前端第三阶段–JsCode


文章目录

  • Web前端第三阶段--JsCode
  • 声明提升
    • 面试题
  • 宿主环境
  • 作用域
  • 作用域链
  • 闭包Closure
    • 闭包应用
  • arguments
  • 函数重载
  • this
    • 面试题
  • 浅拷贝
  • 属性访问
  • 构造函数
  • 原型
      • 对象中的属性
  • 严格模式
  • 对象属性精确配置
    • 计算属性
  • 保护对象属性
  • 箭头函数
  • 数组高阶函数
  • let和const
    • 块级作用域
  • 展开语法
  • 解构语法
  • 函数增强语法
  • 函数的方法
    • 函数的触发方式
    • 作用与区别
  • class语法
  • 构造函数(JAVA)
  • 继承
  • 多态
  • 回调地狱
  • Promise
  • 正则表达式
    • 正则匹配
    • 正则替换
    • 正则验证
    • 构造方式


声明提升

  • 声明:在内存中创建一个内存块,然后起个名字
  • JS引擎先通篇扫描声明操作, 提升(移动)到作用域的顶部然后再执行调整过顺序后的代码

面试题

      function a() {console.log(1)}a()function a() {console.log(2)}a()

宿主环境

  • JS运行所在的环境,称为宿主
  • 浏览器提供了window,含有操作浏览器相关的Api 对象
  • window称为: 全局对象 或 全局作用域

作用域

  • 一类具有特殊功能的对象的称呼
  • 全局作用域:存储了系统的方法、属性–window
  • 局部作用域:函数在运行时 临时生成的对象, 用于存储函数中声明的变量们

作用域链

  • 当多层作用域嵌套时, 当使用变量时, 则遵循就近原则, 来找到对应的变量

闭包Closure

  • 闭包: 函数中使用了来自其他作用域的变量
  • 怕: 其他作用域销毁, 而导致自身无法使用其中的变量
  • 解决: 把其他作用域存储在自身的 scopes 属性里
  • 称呼: 这种被存储在scopes里的函数作用域: 叫闭包
    function a() {var aa = 11var bb = 22function b() {var bb = 33var cc = 44function c() {var cc = 55console.log(aa, bb, cc);}console.dir(c);}b()}a()

闭包应用

  • 为函数制造私有的变量,避免全局污染
  • 缺点:浪费内存
//制作一个函数displayName,每次可以调用都能打印出自身调用的次数var displayName = (function () {var i = 0return function () {i++console.log('调用次数:', i)}})()displayName()displayName()displayName()displayName()

arguments

  • 函数中, 隐藏自带的一个属性/变量
  • 作用: 保存函数收到的所有实参
  • 应用场景:
    • 制作实参个数不固定的函数, 例如: 求最大值
    • 函数重载: 制作多功能函数, 根据实参的个数 或 类型 不同, 内部做判断 然后执行不同的代码逻辑

函数重载

  // 任务: 制作一个计算折扣的函数function zhekou(money) {// 根据实参 来判定折扣的场景// console.log(arguments);// 如果是3个参数, 就是满减if (arguments.length == 3) {if (money >= arguments[1]) {money -= arguments[2]}console.log('您最终消费:', money);}if (arguments.length == 2) {if (typeof arguments[1] == 'number') {money *= arguments[1]}if (typeof arguments[1] == 'string') {var vip = arguments[1]// 语法糖: 作者提供了一些简化语法// if判断的{}中, 仅有一行代码, 可以省略{}if (vip == 'vip1') money *= 0.95if (vip == 'vip2') money *= 0.85if (vip == 'vip3') money *= 0.7}console.log('最终消费:', money);}}zhekou(3000, 0.7) //3000元 打7折zhekou(3000, 2000, 400) // 满2000 减400zhekou(3000, 'vip1') //打95折zhekou(3000, 'vip2') //打85折zhekou(3000, 'vip3') //打7折

this

  • 函数的this属性: 代表当前函数运行时所在的对象
    • 对象.函数() 或 对象函数名 : this就是对象
    • 函数(): this就是window

面试题

var length = 10function fn() {// this = window// this.length == window.length == console.log(this.length);}var obj = {length: 5,method: function (fn) {fn() // 直接触发的函数, 其this是window   -- 10arguments[0]()// [0]: 序号0的参数,就fn.  fn是在arguments对象中, // 所以: fn的this就是 arguments, 其length属性就是实参个数--2console.log(arguments);}}hod(fn, 1)

浅拷贝

  • 浅拷贝: 把对象复制一份 而不是简单的 地址传递
var emp1 = {ename: "mike",age: 19,phone: '18989898988'}// 1. 制作一个新的空对象var emp2 = {}// 2. 遍历 emp1 , 把其中的属性挨个复制到空对象里for (key in emp1) {console.log('key:', key);//通过属性名读值var value = emp1[key]// 相同的 属性名和值, 存入到 emp2 对象里emp2[key] = value}// 修改emp1的属性, 不会影响到emp2, 因为他们是不同的对象emp1.age = 100console.log(emp2);

属性访问

 var obj = { gege: '格格', xuan: '子轩' }var gege = 'xuan'console.) // 点语法, .后是属性名   -- '格格'// 方括号, 值是JS代码. gege是个变量, 其值是'xuan'// 实际读取的是 obj['xuan']   - 子轩console.log(obj[gege]) 

构造函数

  • 用于构造创建对象的函数
// 构造函数: 用于 构造对象 的函数// 矩形对象: // 命名规范: 用 大驼峰写法 给构造函数命名// 目的: 让使用者 见名知意function Rect(length, width) {// 准备个空对象, 把值放进去, 返回对象var obj = {}obj.length = lengthobj.width = widthreturn obj}// 调用构造函数, 传入值. 会返回一个对象var r1 = Rect(10, 5)console.log(r1);var r2 = Rect(100, 30)console.log(r2)

原型

  • 一个共享的存储区域, 专门存放对象共享的方法
  • __proto__原型链用于 链接到原型的属性

对象中的属性

  • 独有的:不同对象有不同属性值,分别存在不同的对象里面
  • 共享的:函数,可以按照固定的逻辑处理对象的属性
    • 为了节省内存:把共享的函数存储在 构造函数的prototype的属性里
    • 生成对象时,要通过其__proto__属性关联到共享的prototype属性
    • prototype:原型–构造函数,存共享方法
  • 使用时
    • 对象.方法(): 对象会到其 __proto__ 链接到的 prototype 中查找方法并使用
  • new运算符:简化构造函数的代码, 省3
    • var this = {} //有的面试答案: 这是两步 声明空对象, 然后赋值给this
    • this.__proto__ = 构造函数.prototype
    • return this

严格模式

ES5 提供了更多的报错, 辅助程序员写出更健康的代码use stirct

对象属性精确配置

  • Object : 是对象类型的构造函数, 其中还包含很多操作对象类型的方法
  • defineProperty
  • 参数1: 要配置的对象
    参数2: 要配置的属性名
    参数3: 具体的配置项
    Object.defineProperty(emp, 'eid', {// ctrl+i: 弹出提示writable: false  // 是否可写入新的值,  true可以  false不可以})
  • writable: false // 是否可写入新的值, true可以 false不可以
  • enumerable: false //是否遍历 true可 false不可
  • defineProperties此方法可以一次配置多个属性
    Object.defineProperties(emp, {// 属性名: 配置项salary: { enumerable: false },// configurable: 是否可重新配置  true可  false不可eid: { writable: false, configurable: false } //w回车 : f 回车})

计算属性

  • get:属性是函数类型,使用时不需要()触发
  • set:可以监听的赋值属性,对值进行判定是否合法
    • 合法:准备一个额外的属性,通常名称_xxx用于存储合法的值
      • 读取时:搭配get计算属性,来从_xxx读值
    • 不合法:抛出错误
    var emp = { ename: "凯凯" }// 细节: _salary 是为了辅助监听器而生, 属于幕后, 不应该被遍历出来// 用 define方式新增的属性, 默认是 不可遍历, 不可配置, 不可赋值Object.defineProperty(emp, '_salary', { writable: true })// 任务: 添加 salary属性监听器...Object.defineProperty(emp, 'salary', {enumerable: true, //可以被遍历到get() { return this._salary },set(value) {if (value >= 5000 && value <= 50000) {this._salary = value} else {throw Error('薪资错误:' + value)}},})// 设置薪资: 范围 5000~50000 // emp.salary = 1200 //报错: 薪资错误emp.salary = 24000 //正常赋值console.log(emp.salary) //打印出 24000console.log(emp);

保护对象属性

  • 不能删:preventExtensions
  • 不能增删:seal
  • 不能增删改:freeze

箭头函数

匿名化了匿名函数的书写,带有两个语法糖

  • 参数只有1个,省略形参的()
  • 函数体只有一行,省略return 和 {}
    • 如果返回值是对象类型,{}用()包围,防止歧义
  • 箭头函数的this指向
    • 箭头函数自身没有this属性
    • 根据作用域的就近原则,使用上级作用域中的this

数组高阶函数

every:判断数组每一个元素都符合条件–类似逻辑与
some:判断数组中有至少一个元素符合条件–类似逻辑或
filter:把满足条件的元素组合成新的数组
map:映射-把数组的元素 按照固定的规范,返回值组合成新的数组

<body><table><thead><tr><th>序号</th><th>名称</th><th>单价</th><th>数量</th><th>总价格</th></tr></thead><tbody id="box"><tr><td>1</td><td>香蕉</td><td>¥9</td><td>4</td><td>¥36</td></tr></tbody></table><script>var products = [{ pname: "香蕉", price: 9, count: 4 },{ pname: "葡萄", price: 25, count: 14 },{ pname: "西瓜", price: 40, count: 6 },{ pname: "桃子", price: 12, count: 8 },{ pname: "杨梅", price: 29, count: 11 },]// 1. 是否所有单价都超过10元var p = products.every(v => v.price > 10)console.log(p ? '都超过10元' : '非都超过10元');// 2. 是否有数量少于5个的var p = products.some(v => v.count < 5)console.log(p ? '有数量少于5个' : '没有数量少于5个');// 3. 找出总价格高于100元的产品var a = products.filter(v => v.price * v.count > 100)console.log(a)// 4. 商品显示在表格里var a = products.map((v, index) => `<tr><td>${index + 1}</td><td>${v.pname}</td><td>¥${v.price}</td><td>${v.count}</td><td>¥${v.price * v.count}</td></tr>`)box.innerHTML = a.join('')</script>
</body>
  • forEach:遍历

    • 遍历数组的方案
      • for 普通循环
      • for…in 遍历对象类型
      • for…of 专为数组而生,直接遍历值
  • reduce 数组合并

    • 把每次累加后的值,传递给下一次循环的函数
      var nums = [1, 32, 54, 645, 2, 43, 46, 576];var a = duce((sum, value, index) => {return sum + value;}, 0);console.log(a);

let和const

  • 没有全局污染,声明的变量存储在脚本作用域
  • let可变 const不可变
  • 关于声明提升,有提升 但是 存在暂存死区

块级作用域

{}配合let/const快速形成块级作用域–代替闭包制作私有变量

展开语法

…数组
…对象

//灵活应用场景 互换的变量的值var a = 20;var b = 40;[a, b] = [b, a];console.log(a, b);
 var gname = {gname: "LOL",maker: "腾讯",teams: ["web", "edg", "rng", "v5"],desc: {year: 2018,},};var {gname,maker,teams: [t1, t2, t3, t4],desc: { year },} = gname;console.log(gname, maker, t1, t2, t3, t4, year);

解构语法

  • 数组:const [变量,变量] = 数组
  • 对象:const{变量,属性名:别名}=对象
  • 函数的形参可以直接解构
      var webs = [{ title: "新闻", href: "" },{ title: "hao123", href: "/" },{ title: "地图", href: "/" },{ title: "贴吧", href: "/" },{ title: "视频", href: "/" },{ title: "图片", href: "/" },];var a = webs.map(({ title, href }) => `<a href="${href}">${title}</a>`);box.innerHTML += a.join("");

函数增强语法

函数参数默认值:function(参数=值)

      function show(name = "亮亮") {console.log("name", name);}show();show("泡泡");

剩余参数 :function(…args){}

      function bb(x, y, ...args) {console.log(x, y, args);}bb(11, 22, 32, 3, 4, 5, 6, 7, 66, 55);

函数的方法

函数的触发方式

用(),apply,bind,call

作用与区别

  • call-调用函数时, 临时设置其this指向, 运行完毕会从对象里删除
  • bind-返回一个新的函数, 把this指向和参数绑定在其上方, 延时触发
  • apply-立刻触发函数, 区别是 参数用 数组来传递
//call
var r1 = { width: 10, height: 30 }var r2 = { width: 55, height: 60 }var r3 = { width: 13, height: 10 }// 制作一个函数, 分别计算出他们的面积// 把函数传入对象里, 执行function area() {console.log(this.width * this.height);}// area函数, 临时放到 r1 里执行. 函数中的this就是所在的对象area.call(r1)
//applyvar r1 = { x: 10, y: 20 }function bb(z, k) {console.log(this.x + this.y + z + k)}// 普通方案: 把bb临时放到r1里执行r1.bb = bbr1.bb(30, 40) // bb函数前方的对象就是其this指向delete r1.bb// 用call方法实现:  函数.call(要放到的对象, 其他参数...)bb.call(r1, 30, 40)// apply: 与call相似, 但是区别是参数要放数组里bb.apply(r1, [30, 40])console.log(r1)
//bind// bind: 用于绑定this指向, 延迟触发函数function a(x, y) {console.log(this, x, y);}var emp = { ename: "泡泡" }// bind: 其返回值是一个函数, 其内存储了this指向和其余参数var a_bind = a.bind(emp, 10, 20)console.dir(a_bind);// 2s后, 触发 a_bindsetTimeout(a_bind, 2000);

class语法

  var emp = {ename: "泡泡",age: 18,phone: '18898989898'}console.log(emp)console.ame)

构造函数(JAVA)

class Rect1 {// java的类中, 不需要写 function 关键词constructor(width, height) {this.height = heightthis.width = width}area() {return this.width * this.height}zc() {return (this.width + this.height) * 2}}console.dir(Rect1) // 查看其prototypevar r2 = new Rect1(100, 50)console.log(r2)console.log(r2.area());console.());

继承

面向对象有三大特征: 封装 继承 多态

  1. 封装: 用{}把代码封在一起, 起个名字. 以后通过名字来调用这段代码
  2. 继承: 自己没有的 到父中查找… JS的原型链 proto
  3. 多态: 重写理论
class Father {money = '500w'eat() {console.log('吃饭');}}class Son extends Father {phone = '19898989838'play() {console.log('玩游戏');}}var s = new Son()console.log(s) //查看其原型 __proto__

多态

多态: 一个父类 可以拥有不同的子类. 由于子类中可以重写, 所以不同的子类调用相同的方法或属性 可以出现不同的状态

    // 多态: 一个父类 可以拥有不同的子类. 由于子类中可以重写, 所以不同的子类调用相同的方法或属性 可以出现不同的状态class Father {hair = "黑头发"eye = '黑眼睛'eat() {console.log('吃粗粮');}}// 子类 继承 父类, 拥有父类的所有属性和方法class Son extends Father {// 重写override: 子类中可以书写与父类中 属性同名的, 会覆盖hair = '金发'// 重写与父类同名的方法, 当使用eat方法时, 根据原型链的就近原则, 优先使用自身原型的eat方法eat() {// 强行使用父元素的eat, 通过关键词supersuper.eat()console.log('吃外卖');}}var s1 = new Son()console.log(s1)console.log(s1.hair, s1.eye);

回调地狱

// JS的异步操作 通常利用回调函数来实现 -- 网络请求
// 当多个异步操作需要同步执行时, 就会出现回调地狱问题
// 期望:点击注册按钮时, 要有序的验证: 用户名是否重复->邮箱..->手机号->注册

Promise

// ES6提供了 构造函数Promise, 可以从语法上规避回调地狱问题// 学习Promise, 必须背 其固定格式// resolve:解决    reject:拒绝   then:然后  catch:抓取// Promise有三种状态// 1. pending: 待定. new Promise之后处于的状态// 2. fulfilled: 已兑现. 调用resolve后的状态, 代表成功// 3. rejected: 已拒绝. 调用reject后的状态, 代表失败new Promise((resolve, reject) => {// 设定: 状态只能从pending 切换成其他状态// resolve: 会触发then中的函数, 其参数传递给then中的函数// resolve({ msg: '成功', code: 200 }) //进入 fulfilled状态// resolve(1111) //无法触发, 因为当前是fulfilled状态// 拒绝: 代表失败. 会触发catch中的函数, 参数会传给catch的函数, 进入rejected 状态reject(222222)}).then(res => {console.log('res:', res);}).catch(err => {console.log('err:', err);})
  <script>// 改造1: 用变量存储 new出来的promise对象; 再用p调用then和catchfunction checkUname() {return new Promise((resolve, reject) => {console.log('验证用户名...');setTimeout(() => {const n = Math.random() //获取随机数,范围 0~1if (n > 0.3) {// resolve代表成功, 触发thenresolve({ msg: "成功", n })} else {// reject代表失败, 触发catchreject({ msg: "失败", n })}}, 1000);})// return p}// 检查邮箱function checkEmail() {// prom : 前提安装 ES6提示插件, 详见B站 vscode视频return new Promise((resolve, reject) => {console.log('验证邮箱...');setTimeout(() => {const n = Math.random()if (n > 0.3) {resolve({ msg: "邮箱验证成功", n })} else {reject({ msg: "邮箱验证失败", n })}}, 1000);});}function checkPhone() {return new Promise((resolve, reject) => {console.log('验证手机号...');setTimeout(() => {const n = Math.random()if (n > 0.3) {resolve({ msg: "手机号正确!", n })} else {reject({ msg: "手机号错误!", n })}}, 1000);});}function register() {return new Promise((resolve, reject) => {console.log('开始注册!');setTimeout(() => {const n = Math.random()if (n > 0.3) {resolve({ msg: "注册成功", n })} else {reject({ msg: "注册失败", n })}}, 1000);});}// 通过调用函数, 返回值是 new Promise()// then: 然后checkUname().then(res => {console.log('res:', res);// 返回值会触发下一个 thenreturn checkEmail()}).then(res => {console.log('res:', res)return checkPhone()}).then(res => {console.log('res:', res)return register()}).then(res => {console.log('res:', res)}).catch(err => {console.log('err:', err)})</script><script>var a = 10// console.log(a * 2)function b() {// var a = 10return 10}// console.log(b() * 2)</script>

正则表达式

正则匹配

    // 正则特殊字符: d 代表1个数字, 等价于 [0-9]var words = '亮亮666 泡泡789 凯凯123'// 要求: 找出words中, 所有的数字// 字符串提供了 match 方法, 可以找出符合正则表达式要求的字符console.log(String.prototype);// 正则的特殊字符要放在 // 中, JS才能识别var a = words.match(/d/)  //match: 匹配单个console.log(a)

正则替换

  var phone = prompt("请输入手机号")console.log('phone:', phone)// 替换语法:  字符串.replace(正则, 替换成什么)// 需求1: 把所有的数字改成*var a = place(/d/g, '*')console.log('a:', a)

正则验证

  var phone = prompt('请输入手机号')console.log('phone:', phone)// 手机号的规则: // 1开头; 第二位 3-9; 共11个// ^: 代表字符串的开头// $: 代表字符串的结尾var r = /^1[3-9]d{9}$/// 验证语法: 正则.test(字符串)   返回值是true和false 代表对还是不对var a = r.test(phone)console.log(a ? '正确' : '格式错误');

构造方式

 // 正则的字面量写法: 简单var a = /d/console.dir(a)// 构造写法// 参数1: 正则   参数2: 修饰符//  : 在JS字符串中转义符.   例如 d 会转成 d// \: 把转义成普通   \d -> dvar b = new RegExp('\d', 'g')var words = 'abcd 1234'console.log(words.match(b))

本文发布于:2024-01-30 02:11:22,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170655188418499.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:第三阶段   Web
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23