第二十四节:Javascript 高级(三)

ES6中的类和对象

事务分为 具体(特指)事务 和 抽象(泛指)事务。

面向对象的思维特点:

  1. 抽象对象共用的属性和行为组织(封装)成一个类(模板)。
  2. 对类进行实例化,获取类的对象。

面向对象编程,我们考虑的是有哪些对象,按照面向对象的思维特点,不断的创建对象,使用对象,指挥对象做事。

对象

JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事务都是对象,例如:字符串、数值、数组、函数 等。

对象是由属性和方法组成:

属性:事物的特征,在对象中用属性来表示(常用名词)

方法:事物的行为,在对象中用方法来表示(常用动词)。

类 class

ES6 新增了类的概念,可以使用 class 关键字声明一个类,之后以这个类实例化对象。

抽象了对象的公共部分,它泛指某一大类(class)

对象特指某一个,通过类实例化一个具体的对象。

创建类

通过class 关键字创建类,类名首字母大写

类必须使用 new 实例化对象

ES6 中没有变量提升,所以必须要先定义类,才能通过类实例化对象。

/ 语法格式:
class Name {
    // calss body
}

/ 创建实例:
var xx = new Name();
类 constraint 构造函数

constructor() 方法 是类的构造函数(默认方法),用于传递参数,返回实例对象

  • 通过 new 命令生成对象实例时,自动调用该方法。
  • 如果没有显示定义,类内部会自动给我们创建一个 constructor()
/ 语法格式:
class Star {
    constructor(uname, age) {
        this.uname = uname;
        this.age = age;
    }
}

// 利用类创建对象 new
new bz = new Star('播仔', 18);

// 打印类
console.log(bz);	// Star {uname: "播仔", age: 18}

// 打印 uname、age
console.log(bz.uname);
console.log(bz.age);
类添加方法

语法格式:

  • 创建类 类名后面不加小括号;生成实例。
  • 类名后加小括号
  • 构造函数不需要加 function
  • 类中的方法都是挂载到 Star.prototype 上的
/ 语法格式:
class Star {
    // 类的共有属性放在 constructor 里面
    constructor (uname) {
        this.uname = uname;
    };
    // 共有方法
    sing (song) {
        console.log(`${this.uname}${song}`);
    }
}

// 利用类创建对象 new
new bz = new Star('播仔');
new hz = new Star('猴子');

// 打印
bz.sing('追光者');	// 播仔:追光者
hz.sing('晚婚');	// 猴子:晚婚
类的注意事项

类里的共有属性和方法一定要加 this 使用。

constructor 中的 this 指向的是创建的实例对象,方法中的 this 指向的是这个方法的调用者

class Star {
    constructor(option) {
        Object.assign(this, option);
        // 公有方法要加 this
        this.sing();
        // 获取按钮,点击触发 sing 方法
        this.btn = document.querySelector('button');
        // 方法不加 括号,不然会直接调用
        this.btn.onclick = this.sing;
    }
    sing() {
        console.log(this.uname);
    }
}

var star = new Star ({
    uname: '刘德华',
    age: '18',
});

类和继承

继承 extends

子类可以继承父类的属性和方法。

/ 语法格式:
calss Father {
    constructor() {
        
    }
    money() {
        console.log(100);
    }
}

// 子类:继承父类的属性和方法
class Son extends Father {
	constructor() {
        
    }
}

// 利用类创建对象 new
var son = new son();

// 打印子类,继承父类的属性和方法
son.money();	// 100
super 关键字

super 关键字 用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数。

/ 语法格式:
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum() {
        console.log(this.x + this.y);
    }
    
    // 子类
    class Son extends Father {
        constructor(x, y) {
            // 调用父类中的构造函数
            super(x, y);
        }
    }
}

// 利用类创建对象 new
let son = new Son(1,2);

// 打印
son.sum();	// 3
super 查找原则

继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的方法,如果没有,则找父类中有没有这个方法,如果有就执行父类的这个方法。

简单理解:super 取就近原则

class Father {
    // 
    say () {
        return '我是爸爸';
    }
}

class Son extends Father {
    say () {
        // 调用父类方法
        console.log(super.say() + '的儿子');
    }
}

// 创建实例化对象
let son = new Son();

// 打印子类方法
son.say();		// 我是爸爸的儿子
super 调用规则

子类在构造函数中使用 super,必须放到 this 前(必须先调用父类的构造方法,再使用子类的构造方法)

// 父类
class Father {
    constructor (x, y) {
        this.x = x;
        this.y = y;
    }
    // 求和运算方法
    sum () {
        console.log(this.x + this.y);
    }
}

// 子类
class Son extends Father {
    constructor (x, y) {
        // super 必须放在 this 前
        super (x, y);
        this.x = x;
        this.y = y;
    }
    
    // 减法运算方法
    sub () {
        console.log(this.x - this.y);
    }
}

// 创建实例对象
let son = new Son(3,1);

// 打印方法
son.sum();	// 4
son.sub();	// 2
静态属性、方法

通过 实例对象.属性名 来定义静态属性

通过 实例对象.方法 来定义静态方法

面向对象添加静态属性、方法
/ 语法格式:
实例对象.属性名
实例对象.方法名

function Star(uname) {
    // 添加实例属性
    this.uname = uname;
}

// 添加实例方法
star.prototype.sing = function () {
    console.log('唱歌');
}

// 添加静态属性
Star.age = 10;

// 添加静态方法
Star.play = function () {
    console.log('玩耍');
}

var star = new Star('刘德华');
类添加静态属性、方法
class Star {
    constructor (uname) {
    	// 添加实例属性
        this.uname = uname;
    }
    
    // 添加实例方法
    sing () {
        console.log('唱歌');
    }
    
    // 静态属性
    static.age = 20;
    
	// 静态方法
	static play () {
        console.log('玩耍');
    }
	
}

// 创建实例对象
var star = new Star('刘德华');

11-面向对象tab栏-思路分析以及布局介绍.mp4

正则表达式

正则表达式( Regular Expression )是用于匹配字符串中字符组合的模式。在JavaScript中,正则表达式也是对象。

正则表通常被用来检索、替换那些符合某个模式(规则)的文本,例如验证表单:用户名表单只能输入英文字母、数字或者下划线, 昵称输入框中可以输入中文(匹配)。此外,正则表达式还常用于过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等 。

正则表达式的特点
  1. 灵活性、逻辑性和功能性非常的强。
  2. 可以迅速地用极简单的方式达到字符串的复杂控制。
  3. 实际开发,一般都是直接复制写好的正则表达式。但是要求会使用正则表达式并且根据实际情况修改正则表达式。比如用户名: /1{3,16}$/
正则表达式的创两种创建方式

/ / 中的数据,不论数据类型,都不要加引号

/ 语法格式:
new RegExp(/正则表达式规则/);

// 利用 RegExp 对象来创建正则表达式
var reg = new RegExp(/abc/);

// 利用字面量的方式 创建正则表达式
var reg1 = /abc/;
校验数据

校验数据时,/ / 中的数据要加引号

test() 方法的返回值是 true || false

/ 语法格式:
正则变量名.test('要检索的字符串');

console.log( reg.test('bca') );
正则表达式的特殊符号
边界符

正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符

边界符说明
^表示匹配行首的文本(以谁开始)
$表示匹配行尾的文本(以谁结束)
//边界符
var reg = /^abc/;
console.log( reg.test('abcssasdasda') );	// true
console.log( reg.test('asbcsasdasda') );	// false

var reg1 = /abc$/;
console.log( reg1.test('ssasabc') );	// true
console.log( reg1.test('ssabcsa') );	// false

// 以abc开始,以abc结束
var reg2 = /^abc$/;
console.log( reg1.test('abc') );	// true
console.log( reg1.test('abcabc') );	// false
字符类

只要包含 [] 中的内容就为 true

如果括号里有 ^ 表示取反的意思,和边界符不一样

字符类说明
[]匹配包含 [] 中的内容就为 true
[a-z]匹配 a-z 之间的字母
2$匹配 a-z 之间的其中一个字母
[a-zA-Z]匹配 a-z A-Z 之间的其中一个字母
[^a-z]不允许出现 a-z 其中的字母
// 匹配 只要包含 abc 中的内容就为 true
var reg = /[abc]/;
console.log( reg.test('a') );	// true

// 匹配 a || b || c,其都为 false
var reg = /^[abc]$/;
console.log( reg.test('ab') );	// false
console.log( reg.test('abc') );	// false
量词符

用来设定某个模式出现的次数

量词符说明
*重复0次 或 更多次
+重复一次 或 更多次
?多个字符 重复0次 或 1次(单个字符无效)
{n}重复 n 次
{n,}重复 n次 或 更多次
{n, m}重复 n 到 m次
预定义类

预定义类指的是某些常见模式的简写方式

预定类说明
\d匹配0~9之间任意数字,相当于 [0, 9]
\D匹配0~9以外的字符,相当于 [^0, 9]
\w匹配任意字母、数字、下划线以外的字符,相当于 [A-Za-z0-9_]
\W除所有字母、数字和下划线以外的字符,相当于 [^A-Za-z0-9_]
\s匹配空格(包括换行符、制表符、空格符等),相当于 [\t\r\n\v\f]
\S匹配非空格的字符,相当于 [^\t\r\n\v\f]
括号总结
  1. 大括号 量词符. 里面表示重复次数
  2. 中括号 字符集合。匹配方括号中的任意字符
  3. 小括号表示优先级
//边界符
var reg = /^abc/;
console.log( reg.test('abcssasdasda') );	// true
console.log( reg.test('asbcsasdasda') );	// false

var reg1 = /abc$/;
console.log( reg1.test('ssasabc') );	// true
console.log( reg1.test('ssabcsa') );	// false

// 以abc开始,以abc结束
var reg2 = /^abc$/;
console.log( reg1.test('abc') );	// true
console.log( reg1.test('abcabc') );	// false
正则替换 replace

replace() 方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式。


面向对象案例

常量 const

使用 const 声明引用类型时,不允许进行赋值,但可以通过指针进行改值。

// 使用 const 声明引用类型
const arr = [];

arr[0] = 10;	// [10]
arr = [20];		// error:不允许赋值,但可以通过指针进行改值

解构赋值

ES6 新增一种方式——解构赋值

数组解构

例如:把数组 [1, 2, 3] 中的元素分别赋值给 a、b 和 c,传统的做法是单独声明变量和赋值

// 传统方式
var arr = [1, 2, 3];
var a = arr[0];
var b = arr[1];
var c = arr[2];

// 解构赋值
[a, b, c] = [1, 2, 3];

使用解构赋值时,会将 “=” 右侧 “[]” 中的元素依次赋值给左侧 “[]” 中的变量

  • 当左侧变量的数量小于右侧元素个数时,则忽略多余的元素

    [a, b] = [1, 2, 3];		// [1, 2]
    
  • 当左侧变量的数量大于右侧元素个数时,则多余的变量会被初始化为 undefined

    [a, b, c, d] = [1, 2, 3];	// [1, 2s, 3, undefined]
    

解构赋值 右侧的内容还可以是一个变量名,或是通过解构赋值完成两个变量数值的交换

var arr = [1, 2, 3];
[a, b] = arr;			// [1, 2]: 左边值少,舍弃 3
console.log(a + '-' + b);	// 	1-2

var n1 = 4, n2 = 8;
[n1, n2] = [n2, n1];	//可以是变量
console.log(n1 + '-' + n2);		// 8-4
对象解构
var obj = {
    name: '张三',
    age: 17,
    love: '干饭',
}

var {name, age, love} = obj;

console.log(name);	// 张三
console.log(age);	// 17
console.log(love);	// 干饭

箭头函数

/ 语法格式:
var fn = (属性1, 属性2) => {
    return 属性1 + 属性2;
}

// 属性写在括号里
var add = (num1, num2) => {
    return num1 + num2;
}
console.log( add(7) );	// 70


// 简写方式:如果函数体内只有一行代码,可以省略花括号
sum = (a, b) => a + b;

sum(1, 2);	// 3

注意:

箭头函数中没有 arguments,但可以使用 展开运算符 来访问所有的实参

  • 展开运算符的变量名 一般使用 arguments 的简写(args) 来声明

arguments 是伪数组,可以遍历,可以通过下标访问数据

但是通过箭头函数给伪数组设置变量名,可以让他变成正常的数组

var fn = (...args) => {
    console.log(args);	// [10, 20, 30, 40, '张三'];
}

fn(10, 20, 30, 40, '张三');

箭头函数的this指向问题

  • 箭头函数中没有自己的 this,所以指向 window

    var fn = () => {
        console.log(this);	// window
    }
    
    fn.call(this);
    
  • 箭头函数中没有自己的 this,不能创建实例

    var Star = (name) => {
        this.name = name;
        console.log(this);	// Star is not a constructor
    }
    
    var star = new Star('张三');
    
    • 想要创建自己的实例,只能通过 new 的形式创建对象

      var Star = (option) => {
          Object.assign(this, option);
      }
      
      var star = new Star({
          uname: '张三',
          age: 17,
      });
      
      console.log(star.age);	// 17
      

展开运算符

扩展运算符可以将数组或者对象转为用逗号分隔的参数序列

/ 语法格式:
... 变量名

扩展运算符可以应用于合并数组

let arr1 = [1, 2, 3];
let arr2 = [2, 3, 4];
// 方法一:
let arr3 = [...arr1, ...arr2];
// 方法二:
let arr4 = arr1.push(...arr2);

将类数组或可遍历对象转换为真正的数组

let lis = document.querySelectorAll('ul li');
lis = [...lis];

封装DOM

更方便使用,不需要一直写 document.querySelector

<ul class="box">
    <li>列表1</li>
    <li>列表2</li>
</ul>

<script>
	let box = get('.box');
    let lis = gets('li');
    
    /**
     * 封装一个DOM
     * @param {String} selector 选择器
     * @param {Object} element DOM对象
     */
    function get(selector, element = document) {
        return element.querySelector(selector);
    }
    function gets(selector, element = document) {
        return element.querySelectorAll(selector);
    }
</script>

严格判断数据类型

全等无法判断 NaN
NaN === NaN => false

Object.is(NaN, NaN);	// true

内置对象方法 扩展

Array.from()
实例方法:find()

根据条件筛选数据

/ 语法格式:
数组.find(回调函数);
var arr = [
    {name:'张三', age: 17, score: 90},
    {name:'李四', age: 17, score: 95},
    {name:'王五', age: 17, score: 100},
];


实例方法:findIndex()

查找数组中第一个满足条件项的下标

/ 语法格式:
数组.find(回调函数);
var arr = [
    {name:'张三', age: 17, score: 90},
    {name:'李四', age: 17, score: 95},
    {name:'王五', age: 17, score: 100},
];

var r = arr.findIndex(item => item.score == 95);	// 1
实例方法:includes()

查找数组是否存在某一项

var arr = [10, 20, 30, 40];

console.log(arr.includes(40));	// true
indexOf() 和 includes() 的区别

相同点:查找数组中是否存在某一项

不同点:

  • indexOf():

    1. 返回值是 当前项的下标,找不到返回 -1

      console.log(arr.indexOf(40)); 	// 3
      
    2. 如果数组中有 NaN,indexOf() 无法查找,会返回 -1

      var arr = [10, 20, NaN];
      
      console.log(arr.indexOf(NaN));	// -1
      
  • includes()

    1. 返回值是 布尔值,true || false

      console.log(arr.includes(40));	// true
      
    2. 如果数组中有 NaN,includes() 会进行查找

      var arr = [10, 20, NaN];
      
      console.log(arr.includes(NaN));	// true
      
startsWith 方法 和 endWith 方法

作用:查找字符串中是否以 … 开始,或者以 … 结束

返回值:布尔类型(true 包含 || false 不包含)

startsWith ()

以 … 开始

var str = 'hello wold';

console.log(str.startsWith('h'));	// true
endWith ()

以 … 结束

var str = 'hello wold';

console.log(str.startsWith('ld'));	// true
repeat() 方法

作用:将字符串重复指定次数,返回一个新字符串

/ 语法格式:
字符串.repeat(次数)var str = '张三';

console.log(str.repeat(3));		// 张三张三张三
Set() 方法
Set() 去重

作用:实现数组去重

方法中的 set 属性:新数组中的长度

var arr = [10, 10, 20, 20, 30];

var newArr = new Set(arr);

console.log(newArr);	// {10, 20, 30}
console.log(newArr.size);	// 3
Set() 添加数据

可以采用链式编程

var set = new Set();

Set.add(100)
   .add('李四');
Set() 查找是否包含
var set = new Set();

set.has(100);
Set() 删除数据
var set = new Set();

set.delect('李四')
Set() 清除所有数据
var set = new Set();

Set.clear();

**注意:**set() 方法,得到的数组是一个伪数组

不可以for循环遍历。不可以使用 数组的方法,需要使用 展开运算符 或 Array.from() 进行转数组

虽然 set()得到的是一个伪数组,但是可以使用 **for in **进行遍历

浅拷贝

将引用类型的指针拷贝给新对象

注意:

由于拷贝的是同一个指针,指针指向堆内存中同一块空间,所以修改数据时会相互影响

var o = {
    name: '张三',
}

var obj = o;

obj.name = '李四';

console.log(o);		// 李四

深拷贝

将引用类型各项属性的值拷贝给新对象

方式一:手动拷贝

手动拷贝要一个属性一个属性进行拷贝

var o = {
    name: '张三',
    info: {
        age: 17,
    }
}

var r = {
    name: o.name,
    info: o.info() {
    	age: o.info.age,
	}
}
方式二:Object.assign();

只能实现一层的深拷贝

重复的属性,后面会覆盖前面的属性

/ 语法格式:
Object.assign(目标对象, 待拷贝的对象1, 待拷贝的对象2, 待拷贝的对象3, );

方式三:JSON做字符串转换

只有可以转成JSON格式的对象才可以这样用,像function没办法转成 JSON

var o = {
    name: '张三',
    info: {
        age: 17,
    }
}

var r = JSON.parse(JSON.stringify(o));
方式四:slice()

slice() 截取也不会影响,所以可以使用 slice(0) 从第零项截取到最后一项,实现深拷贝。

var arr = [10, 20, 30];
var r = arr.slice(0);

r[0] = 100;

console.log(arr);	// [10, 20, 30]
方式五:递归拷贝
var o = {
    name: '张三',
    info: {
        age: 17,
    },
    arr: [10, 20],
    fn () {
        console.log(100);
    }
}

function deepCopy (obj) {
    // 如果当前类型是不是基本类型,是就 return,不是就继续
    if (typeof obj !== 'object' || typeof obj == null) {
        return;
    }
    // 判断当前是对象还是数组,用于创建存储器
    let result = obj.__proto__.constructor.name == 'object' ? {} : [];
    
    for (const key in obj) {
        // 如果当前项是object,就重新调用拷贝函数,遍历挡墙项,如果不是 object,则递归到新对象。
        result[key] = typeof obj[key] == 'object' ? deepCopy(obj[key]) : obj[key];
    }
    
    // 返回新对象
    return result;
}

deepCopy(o);
console.log(deepCopy(o));

  1. a-z0-9_- ↩︎

  2. a-z ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤安先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值