JavaScript深入理解(13课)笔记-ES6-语法解析

13.ES6-语法解析-let-const等

创建类继承自内置类

class HYArray extends Array {
    firstItem() {
        return this[0]
    }
    lastItem() {
        return this[this.length-1]
    }
}
var arr = new HYArray(1, 2, 3)
console.log(arr.firstItem())
console.log(arr.lastItem())


类的混入mixin【缘于JS只能单继承】
class Person{ }
class Runner{
    running() { }
}
// 在JS中类只能有一个父类:单继承 【虽然,下面这样写没报错】
class Student extends Person, Runner { }


类的混入示例:
class Person{ }

function mixinRunner(BaseClass) {
    class NewClass extends BaseClass {
        running() {
            console.log("running~")
        }
    }
    return NewClass
}

function mixinEater(BaseClass) {
    //直接返回一个匿名类也行
    return class extends BaseClass { 
        eating() {
            console.log("eating~")
        }
    }
}

//在JS中类只能有一个父类:单继承
class Student extends Person { }

// var NewStudent = mixinRunner(Student)
var NewStudent = mixinEater(mixinRunner(Student))
var ns = new NewStudent()
ns.running()
ns.eating()

//上面中,如果想混入一些属性 或 在构造函数中传入一些参数,就并不是特别好做了。
//所以用上面实现混入效果不是特别多,了解即可

【题外话】
react开发更加接近于原生js开发;react更加灵活(双刃剑)
vue是打包好的,比如:
export default {
    options { … },
    setup({更多函数的使用})
}


00:32:00
在react中的高阶组件【connect() 用到了很多技巧,也用到了混入】

class TopBanner extends Component { }
redux(状态) -> vuex
//柯里化函数
connect(props, dispatch)(TopBanner)  这里面有 return如下:
return class EnhanceComponent extends Component {
    render() {
        return<TopBanner props dispatch>
    }
}

export default connect(props, dispatch)(TopBanenr)

记忆力:神经元连接越紧密,记忆可能会越深刻!

00:52:00
JavaScript有多态吗?
· 维基百科对多态的定义:多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口,或使用一个单一的符号来表示多个不同的类型。
· 非常的抽象,个人的总结:不同的数据类型进行同一个操作,表现出不同的行为,就是多态的体现。

传统面向对象多态.ts        代码如下:
// Shape形状
class Shape {
    getArea() {}
}
class Rectangle extends Shape {
}
class Circle extends Shape {
}
var r = new Rectangle()
var c = new Circle()

function calcArea(shape: Shape) {
    console.log(shape.getArea())
}

calcArea(r)
calcArea(c)

上面这样写,是没有多态的。因为都是调用 Shape 类中的 getArea方法。
需要修改一下上面代码如下,就可形成多态:
class Rectangle extends Shape {
    getArea() {
        return 100
    }
}
class Circle extends Shape {
    getArea() {
        return 200
    }
}

// 传统的面向对象多态是有三个前提:
// 1>必须有继承(是多态的前提)
// 2>必须有重写(子类重写父类的方法)
// 3>必须有父类引用指向子类对象

var shape: Shap = new Rectangle0
父类的引用          子类的对象
       指向->


01:05:00
JS面向对象多态.js    代码如下【符合维基百科多态的定义】:
function calcArea(foo) {
    console.log(foo.getArea())
}
var obj1 = {
    name: "why",
    getArea: function() {
        return 1000
    }
}
class Person {
    getArea() {
        return 100
    }
}

var p = new Person()
calcArea(obj1)
calcArea(p)

//下面也是多态的体现
function sum(m, n) {
    return m+n
}
sum(20, 30)
sum("abc", "cba")


01:12:00
ES6 对象字面量增强的写法:
var name = "why"
var age = 18
var obj = {
    // 1.property shorthand(属性的简写)
    name,
    age,

    // 2.method shorthand(方法的简写)
    foo: function() {
        console.log(this)
    },
    bar() { //上面 foo: 这种写法的语法糖
        console.log(this)
    },
    baz: () =>{  //给它绑定箭头函数,箭头函数不绑定this,取上层作用域
        console.log(this)
    },

    // 3.computed property name(计算属性名)
    [name + 123]: 'hehehehe'
}

obj.baz()  //window对象
obj.bar()  //obj对象
obj.foo()  //obj对象

// obj[name +123] ="hahaha"  //以前是这样添加属性名 why123,现在可以用上上面的
console.log(obj)


ES6中新增了一个从数组或对象中方便获取数据的方法,称之为解构Destructuring。

var names = ["abc","cba","nba"]
// var item1 = names[0]
// var item2 = names[1]
// var item3 = names[2]

//对数组的解构:[]
var [iteml, item2, item3] = names
console.log(iteml, item2, item3)

// 解构后面的元素
var [, , itemz] = names
console.log(itemz)

// 解构出一个元素,后面的元素放到一个新数组中
var [itemx, ...newNames] = names
console.log(itemx, newNames)

// 解构的默认值
var [itema, itemb, itemc, itemd, iteme = 'aaa'] = names
console.log(itemd) //undefined
console.log(iteme) //'aaa'


01:33:00
var obj = {
    name: "why",
    age: 18,
    height: 1.88
}
// 对象的解构: {}
var { name, age, height} = obj
console.log(name, age, height)

var { age } = obj
console.log(age)

// 解构出来并重命名
var { name: newName } = obj
console.log(newName)

// 解构默认值
// var { address = "广州市"} = obj

// 解构重命名并赋予默认值
var { address: newAddress = "广州市"} = obj
console.log(newAddress)


解构目前在开发中使用是非常多的:
· 比如在开发中拿到一个变量时,自动对其进行解构使用;
· 比如对函数的参数进行解构;

function foo(info) {
    console.log(info.name,info.age)
}
foo(obj)

// 类似上面函数,用解构来写
function bar({name, age}) {
    console.log(name,age)
}
bar(obj)

01:49:00
在ES5中我们声明变量都是使用的var关键字,从ES6开始新增了两个关键字可以声明变量: let、const
· let、const在其他编程语言中都是有的,所以也并不是新鲜的关键字;
· 但是let、const确确实实给JavaScript带来一些不一样的东西;

var foo = "foo"
let bar = "bar"
// const constant(常量/衡量)
const name ="abc"
name = "cba" //报错

// 注意事项一:const本质上是传递的值不可以修改
// 但是如果传递的是一个引用类型(内存地址),可以通过引用找到对应的对象,去修改对象内部的属性,这个是可以的
const obj = {
    foo: "foo"
}
obj = {} //报错

obj.foo ="aaa" //这个是可以的
console.log(obj.foo) 

// 注意事项二:通过let/const定义的变量名是不可以重复定义
var foo ="abc"
var foo = "cba"

let foo = "abc"
let foo = "cba"  //报错:SyntoxError: Identifier 'foo' has already been declared


var作用域提升
console.log(foo)  //undefined
var foo="foo"

02:04:00
let/const作用域提升
let、const和var的另一个重要区别是作用域提升:
· 我们知道var声明的变量是会进行作用域提升的;
· 但是如果我们使用let声明的变量,在声明之前访问会报错;

【针对下面代码,从此处往下开始看】
// let/const他们是没有作用域提升
// foo被创建出来了,但是不能被访问
// 作用域提升:能提前被访问
console.log(foo)  //报错:ReferenceError: Cannot access 'foo' before initialization 【foo有被创建出来,但不能被访问】
let foo = "foo"

那么是不是意味着foo变量只有在代码执行阶段才会创建的呢?
· 事实上并不是这样的,我们可以看一下ECMA262对let和const的描述;
· 这些变量会被创建在包含他们的词法环境被实例化时,但是是不可以访问它们的,直到词法绑定被求值;


02:25:00
VO/VE/  再次提到
VE环境,还等于现在的 window吗?有点区别了,像 let/const 声明的 会放到 variables_ 中,它是 VariableMap 类型(哈希表)。
早期的v8引擎也只指向 GO(window),因为那里还没有 let/const 这东西,当出现时,为了兼容早期的v8 也会在 window中加入 let/const 声明的变量。
但是,最新的 v8引擎的浏览器,已经在 window 中不包含 let/const 声明的变量。


02:46:00

下面这两个是不一样的【别混淆】:
// 块代码(block-code)
{
    //表达式
    var foo = "foo"
}

// 声明对象的字面量
var obj = {
    name: "why"
}


// ES5中没有块级作用域【所以,下面这样外面的 { } 形同虚设】
// 块代码(block-code)
{
    //表达式
    var foo = "foo"
}
console.log(foo)


在ES5中只有两个东西会形成作用域【里面能访问外面的,外面不能访问里面的】
1.全局作用域
2.函数作用域

// ES6的代码块级作用域,对var无效
// 对let/const/function/class声明的类型是有效
{
    let foo = "why"
    function demo() {}  //function比较特殊
    class Person {}
}
console.log(foo)  //报错
// 不同的浏览器有不同实现的(大部分浏览器为了兼容以前的代码,让function是没有块级作用域)
demo()  //不会报错
var p = new Person()  //报错


if/switch/for 语句也是块级作用域,同样对 var 无效。
for(var i=0; i<10; i++) {
    //(……) 这边的 i 相当于是在 { …… }  中声明的
}

假设页面上有4个按钮
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>

const btns = document.getElementsByTagName('button')
for (var i = 0; i < btns.length; i++) {
    btns[i].onclick = function() {
        console.log("第"+ i+"个按钮被点击")
    }
}
console.log(i)

则这样,打印4;
且每个按钮点击时也是打印:第4个按钮被点击

为什么这样呢?因为这样的块级作用域,对 var 无效,访问到最外层的 i 时,已经是计算完成了的 i = 4。


以前是怎么解决呢?如下:弄个“立即执行函数”,里面写成这样:
    (function(n) {
        btns[i].onclick = function() {
            console.log("第"+ n+"个按钮被点击")
        }
    })(i)

这也相当于是一个闭包,用function形成作用域,var 变量作用域起作用。


【现在的,只需要把上上面的 var i = 0; 改成 let 声明即可解决(改成 const 会报错的),让 i 形成一个块级作用域】

for (let i = 0; i < btns.length; i++) {
    btns[i].onclick = function() {
        console.log("第"+ i+"个按钮被点击")
    }
}
console.log(i)  //报错

【现在的,i 去找上层作用域,因为 let 这个变量是有块级作用域的,那么在访问 i 的时候,实际是访问块级作用域的 let i = 0;
而这个 i 在第一次的时候是 0 的,第二次是为 1 的,…… 那么每次在这里绑定函数的时候,绑定到外层的 i 变量分别是 0 1 2 3 】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值