JavaScript(二)

原型链

JavaScript
是一门弱类型的(typeScript)、动态的脚本语法, JavaScript基于原型对象来实现,支持面向过程、面向对象和函数式编程范式

面向对象:注重的是解决问题需要的对象
面向过程:注重的使解决问题需要的过程(具体的步骤)

面向对象编程的特性
[1] 封装(复用、信息隐蔽)
[2] 继承(复用)
[3] 多态(JavaScript天生就是一门支持多态的语言)
多种形态(当发出了某个命令后,不同的对象接收到这个命令会做出不同的反应)

对象的创建
[1] 字面量创建 简单快速,不适合批量的创建对象
var o1 = {}; //空对象
var o2 = {
name: "zs",
age: 19
}

[2] 内置构造函数(Object)
var personA = new Object(); //空对象 var obj1 = {}

[3] 工厂函数来创建 : 对内置构造函数(Object)方式封装,解决了代码复用的问题
问题:无法区分对象的类型
function createPerson(name, age, price) {
var personA = new Object();
personA.name = name;
personA.age = age;
personA.price = price;
personA.showName = function() {
console.log("姓名:" + this.name);
}
return personA;
}

[4] 自定义构造函数(核心)
特点:
(1) 函数的名字首字母大写(约定-建议)
(2) 在调用的时候,使用new关键字来调用

内部操作:
1-默认会创建一个空对象
var o = new Object()
2-默认会把这个空对象赋值给this
this = o
3-设置this的原型对象指向构造函数的原型对象
this.__proto__ = Person.prototype
4-通过this来添加属性和方法
this.name = name
this.showName = function() {
console.log("姓名:" + this.name);
}
5-在函数的最后默认总是会把this返回
· return this

function Person(name, age, price) {
this.name = name;
this.age = age;
this.price = price;
this.showName = function() {
console.log("姓名:" + this.name);
};
}

var person1 = new Person("zs", 19, 300);
var person2 = new Person("ls", 34, 100);

构造函数的返回值
1、如果没有return , 那么默认在函数的最后总是会把新创建的实例对象返回
2、主动return
[1] return 值类型的数据(字符串 数字 布尔值)
忽略,返回的仍然的默认返回的实例对象
[2] return 引用类型的数据(对象 数组 函数 日期)
直接返回

自定义构造函数(问题:浪费性能)
解决: 把属性添加到实例对象身上,把方法添加在原型对象身上
function Person(name, age) {
this.name = name;
this.age = age
}
Person.prototype.showName = function() {
console.log("姓名:" + this.name);
}

构造函数(首字母大写)、构造函数.prototype(原型对象)、
new 构造函数(实例对象) 三者的关系

实例对象.constructor(构造器) == 构造函数
原型对象.constructor == 构造函数

构造函数.prototype == 原型对象
实例对象.__proto__ == 原型对象

总结访问原型对象的方式
[1] 构造函数.prototype
[2] 实例对象.__proto__
[3] Object.getPrototypeOf(实例对象)
备注
__proto__ 属性是ES6+(2015)新特性,因此在ES6-前不能直接使用该属性,需要使用Object.getPrototypeOf方法来获取

如果替换了原型对象,那么会存在潜在的问题
解决 constructor: Person(修正构造器属性)

重要概念
/* 构造函数:Person */
/* 原型对象: Person.prototype */
/* 实例对象:p1 */
/* 成员:对象的属性和方法叫做成员 */

// 原型成员:原型对象的属性(Person.prototype.name\Person.prototype.age)和方法(Person.prototype.showName\Person.prototype.showAge)。

/* 实例成员:实例对象的属性( this.name \ this.age)和方法(this.showInfo)。 */
/* 静态成员:构造函数自己的属性(Person.tt)和方法(Person.show)。 */

/* 私有成员:构造函数内部声明的私有变量(className)和私有函数(showClassName函数)。 */

/* 特权方法:特殊的实例方法(该方法可以访问到私有成员)。 */
/* 实例化:构造函数创建实例对象的过程,我们叫做实例化。 */

查找操作
1、in关键字:检查对象中是否存在指定的成员(属性和方法)
语法 "成员名" in 对象
2、Reflect.has(对象,"成员名字")
3、hasOwnProperty() 检查指定的成员是否是实例成员

in关键字和hasOwnProperty的区别
in关键字在检查的时候 : 实例成员 + 原型成员
hasOwnProperty方法 : 实例成员

/* 遍历d1对象 */
for (var key in d1) {
/* 检查只有当成员是实例成员的时候才打印(排除原型成员) */
if (d1.hasOwnProperty(key)) {
console.log(key, d1[key]);
}
}

原型链
/* [1] 每个构造函数都有一个默认相关联的原型对象(每个人天生都有一个对象) */
/* [2] 所有的对象可以理解为都是由构造函数创建出来的(每个人都是妈生的)。 */
/* [3] 原型对象也是对象,因此原型对象也有自己的构造函数。*/
/* [4] 原型对象自己的构造函数,也有自己的原型对象,这个原型对象也是对象因此也有自己的构造函数,这个构造函数也应该有关联的原型对象。 */
注意
1、JavaScript原型链有顶端(Object.prototype),它的原型对象是null
2、__proto__是对象的属性
3、prototype是函数的属性
4、函数也是对象
5、Function实例化自己

instanceOf 关键字的基本使用
指定构造函数的原型对象是否在当前实例对象的原型链上
p1 instanceof Person
检查Person.prototype是否在p1的原型链上

isPrototypeOf方法的基本使用
指定构造函数的原型对象是否在当前实例对象的原型链上
Person.prototype.isPrototypeOf(p1)
Person.prototype是否在p1的原型链上面

创建对象第五种方法 Object.create()
Object.create(o,[options])
作用:创建新的对象并且设置该对象的原型对象为o【在创建对象的时候可以设置该对象的成员】

this

this的指向取决于函数的调用方式:
001-普通函数调用 函数名()
this->window(非严格) this->undefined(严格)
002-以对象方法调用 对象.函数名()
this->对象
003-以构造函数调用 new 函数名()
this->内部新创建的实例对象
004-函数上下文调用(call方法和apply方法|bind方法)
this->第一个参数
005-箭头函数

call和apply方法
作用:借用其它对象的方法,并且绑定函数中的this,this绑定给call方法和apply方法的第一个参数
区别:
(1) call方法传递给函数的实际参数以参数列表的方式来处理,apply方法传递的实际参数以数组或者是伪数组的方式来处理
(2) 最少形参的个数(call的形参个数=1,apply方法的形参个数=2)

语法:对象1.方法名.call(绑定this,参数1,参数2,参数3...)
语法:对象1.方法名.apply(绑定this,[参数1,参数2,参数3...])
语法:对象1.方法名.apply(绑定this,伪数组)

bind绑定的方法
该方法用来绑定函数中的this并且把绑定之后的函数返回
var f = fn.bind([1, 2, 3, 4]); //绑定this之后会把这个函数返回
f();

ES6

let 声明变量
001-不允许声明同名的变量
002-let必须要先声明才能使用,不会进行变量声明的提升
003-let + {} 会形成局部作用域(块级作用域)
JavaScript原本没有块级作用域{}

const 声明常量
常量的名字建议使用大写(约定)
变量的值是可以变化的,是可以改变和修改的
常量的值是不可以变化的,是不可以被修改的+

增强写法
001-对象中的方法可以省略:function
002-如果属性的名字和属性值相同,那么可以简写
let o2 = {
name: "zs",
age,
showName: function() {
console.log("姓名:" + this.name);
},
showAge() {
console.log("年龄:" + this.age);
},
}

函数的默认参数
function point(x = 1000, y = 1000) {
return `(${x},${y})`;
}

箭头函数
let sum2 = (a, b) => {
return a + b;
}
简写
(1) 如果函数的函数体只有一行,那么{}可以省略并且return关键字也可以省略
let sum3 = (a, b) => a + b;
(2) 如果函数的形参只有1个,那么()可以省略
var computedB = a => a * 2;
(3)箭头函数主要用在回调函数中
setInterval(() => console.log("task"), 1000)

箭头函数中注意点
[1] this 箭头函数中没有this,箭头函数中访问的this来源于离当前作用域最近的那个this
[2] 箭头函数不能作为构造函数来调用,因为没有this
[3] 箭头函数中没有arguments

剩余参数 function fn(...rest){
//rest
}
箭头函数中没有arguments
剩余参数,它是一个真正的数组,因此可以直接使用数组的方法
注意
默认参数和剩余参数不会被计算到形参的数量中(形参意味着这是期望传递的参数个数)

扩展运算符 (...)
作用:展开数据为列表
1、var data = [10, 203, 324, 2184, 2189, 1];
Math.max(...data)
2、合并数组
var arr4 = [...arr1, ...arr2, 100, 200];
3、展开字符串
...str

数组扩展
001-Array.from(likeArray)
作用:把伪数组转换为真正的数组
伪数组:本身是对象,但是跟数组很像(key从0开始依次递增,并且拥有length属性,length属性的值==最大key +1)

002-Array.of()
作用:以统一的方式来创建数组

003-Array.includes()
作用:检查数组中是否包含某个特定的元素,返回布尔值

004- arr.find() arr.findIndex()
查找满足条件的元素,如果找到那么就返回该元素|索引

字符串扩展
001-str.includes
检查字符串中是否包含指定的字符,如果包含那么就返回true,否则就返回false

002-repeat()
重复字符串多少遍

003-padEnd()
从后面填充字符串到特定的长度,默认用空格填充

004-padStart()
从前面填充字符串到特定的长度,默认用空格填充

解构语法
解构表示的是从对象或者是数组中把数据取出来保存在变量的身上
对象的解构
let o = { name: "zs", age: 18, score: 99 };
let { score, age, name } = o;
注意
对象的解构语法(根据名字来取值,要对应)

数组的解构
let arr = ["小奶狗", "绿色", 13];
let [dogName, dogColor, dogAge] = arr;
注意
数组的解构语法(按照顺序赋值)
例子
交换两个变量的值
[a, b] = [b, a];

Class (类)
Class用来取代构造函数和原型对象
class Person {
/* 设置实例成员 */
constructor(name, age) {
this.name = name;
this.age = age;
}
/* 设置原型成员 */
showName() {
console.log("姓名-", this.name);
}
showAge() {
console.log("年龄-", this.age);
}
/* 设置静态方法 */
static showInfo() {
console.log("info-", this.name);
}
}

let p1 = new Person("lw", 99);
console.log(p1);

for...of循环(数组,不推荐,无法获取索引)
for (let element of data) {
console.log(element);
}

构造函数 Set(集合)
跟数组很像,特点是集合中的数据是唯一的
基本操作
1、添加数据 add()
2、删除数据 delete()
3、清空数据 clear()
4、检查Set中是否存在指定的数据 has()
5、获取长度(数据的个数) 只读 size
6、forEach方法遍历
7、for..of方法遍历

数组的去重(Set方法)
//01-该方法内部会自动完成数组去重
let setData = new Set(arr1);
//02-把集合转换为数组
(1) Array.form(伪数组|集合)
let arr2 = Array.from(setData);
(2) 扩展运算符(...)
let arr3 = [...new Set(arr1)];

字符串的去重(Set方法)
运用上面数组的去重之后,再用 join("") 变成字符串

构造函数 Map(映射)
和对象很像
基本操作
1、清空:clear()
2、删除:delete(“key”)
参数是指定的key,如果删除成功那么返回true,否则返回false
3、遍历:forEach()
4、获取:get(“key”)
5、检查:has(“key”)
检查映射中是否存在指定的key
6、添加:set("name", "zs")
7、长度(数据的个数):size
8、for...of
for (let [key, val] of mapData) {
console.log(key, val);
}

注意
1、对象:对象中所有的key都必须是字符串
2、映射:map的key可以是任意类型,甚至可以是对象

Symbol(基本数据类型-符号类型)
特性
1、符号类型是唯一的
2、创建符号类型数据的时候传递参数(名字)

符号类型的作用:
主要用来作为对象的私有属性(在for..in循环中无法被遍历出来的成员)

Object.assign() 合并对象
语法:Object.assign(target,source1,source2,source3)
Object.assign(o1, o2, o3, o4); //表示把o2\o3\o4的成员拷贝一份都添加到o1身上

对象内置的方法

原型成员
001-构造器属性 constructor
002-检查是否有实例成员 hasOwnProperty(key)

003-检查当前对象是否是指定对象的原型对象 isPrototypeOf()
o.isPrototypeOf(p1) o是p1的原型对象吗?

004-检查属性是否可以被枚举(遍历for..in循环) propertyIsEnumerable(key)

005-返回对象自己 valueOf()
006-转换为字符串(本地化) toLocaleString()
007-转换为字符串 toString()
o4.toString() [object Object] = [对象类型 构造函数]
注意
1、都是toString,但不是同一个方法
o.toString == Object.prototype.toString
对象的toString可以检测数据类型(借用)
检测数据类型:Object.prototype.toString.call(数据)

arr.toString = Array.prototype.toString
数组的toString是转换为字符串

date.toString() == Date.prototype.toString
日期的是转为字符串

(数字).toString == Number.prototype.toString()
数字的是以多少进制来表示该数字

2、valueOf() 日期.valueOf() 返回的是时间戳

静态成员(调用:Object.xxx)
001-合并对象 assign()
002-创建对象并且设置原型对象 create()

// 形参个数:length: 1
// 函数名字:name: "Object"
// 原型对象 __proto__: ƒ()[[Scopes]]: Scopes[0]

003-获取指定对象的原型对象 getPrototypeOf(实例对象)

004-比较两个数据 is()
Object.is()方法 几乎和全等运算符功能一样,有两点区别
(1) 比较NaN
Object.is(NaN, NaN) true
Object.is(NaN, "测试" / 3) true
(2) 比较0
Object.is(+0, -0) false

005-获取对象中指定属性的属性描述符对象
getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor(o, "name")

006-获取对象中所有属性的属性描述符对象
getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors(o)

007-设置对象中指定属性的属性描述符对象 defineProperty()
Object.defineProperty(o, "name", {
configurable: false,
enumerable: false,
value: "lw",
writable: false
});

008-设置对象中多个属性的属性描述符对象 defineProperties()
Object.defineProperties(o, {
name: {
configurable: false,
enumerable: false,
value: "lw",
// writable: false 如果不写,那么默认为true
},
age: {
configurable: true,
enumerable: false,
value: "19",
writable: false
},
address: {
value: "广州", //如果这个属性是新增的,那么配置项不写默认为false
}
})

009-禁止对象扩展 (不能添加新的成员) preventExtensions()
Object.preventExtensions(对象)

010-密封对象 (不能添加新的成员 && 不能删除) seal()
Object.seal(对象)

011-冻结对象 (不能添加新的成员 && 不能删除 && 不能修改) freeze() Object.freeze(对象)

012-检查对象是否扩展 isExtensible()
013-检查对象是否被密封 isSealed()
014-检查对象是否被冻结 isFrozen()

015-获取所有实例属性的名字,返回的是数组
getOwnPropertyNames()
016-获取所有实例属性中的符号类型数据,返回的是数组
getOwnPropertySymbols()

017-所有的key keys()
018-所有的值 values()

对比:getOwnPropertyNames && keys()
区别:keys方法只能获取所有可以枚举的属性

getter和setter
Object.defineProperty(target, key, {
configurable: true,
enumerable: true,
set(val) {
console.log(`监听${key}到-写`);
element = val;
},
get() {
console.log(`监听${key}到-读`);
return element;
}
})

正则表达式

正则表达式: 文本匹配和校验 在前端开发中主要用来进行表单验证。 正则相关的方法:正则的方法 + 字符串的方法(split replace search)
正则表达式的基本写法: 元字符 + 规则 */

创建正则表达式
[1] 字面量方式来创建正则表达式
let reg1 = /123/g
[2] 通过构造函数方式来创建、
let reg2 = new RegExp("123", "g")

test方法
作用:测试字符串能够匹配这个正则表达式
/123/.test("123456")

正则的主要成员
0、exec()
1、test()
2、flags 获取当前正则的参数
3、global 是否全局匹配(g)
4、ignoreCase 在匹配的时候是否忽略大小写(i)
5、multiline 再匹配的时候应用多行(m)
6、sources 正则本身

符号
1、 | 或者
2、 [] 搭配 - 或者 [0-9]/[a-z]

量词
{3} 匹配3个
{min,max} /{2,5}/ 匹配2个|3个|4|5个
量词存在简写形式
+ == {1,} 1个或者是多个
? == {0,1} 0个或者是1个
* == {0,} 0个或者是多个

元字符
1、\w 数字、字母、下划线
2、\W 非数字、字母、下划线
3、\d 数字
4、\D 非数字
5、\s 空格
6、\S 非空格
7、. 除换行以外的字符

位置限定符
1、^ 限定的是开头位置
2、$ 限制的是结尾位置
注意
^ 如果在[]里面表示非

正则表达式相关方法的使用(replace\split\match\search)
字符串中可以使用正则表达式的方法
1、str.split(/[,,]/)
2、str1.search(/动物$/)
在字符串中匹配指定的子串,如果匹配成功那么就返回索引,如果失败那么返回-1
3、str1.match(/动物/g)

边界处理 断言
1、\b : 匹配一个单词边界,也就是指单词和空格间的位置
2、\B : 匹配非单词边界

(): 表示分组(n是以最左边括号出现的顺序排列)
+ $1: 表示第一个分组
+ $n: 表示第n个分组(不能写在正则表达式里)
+ \n: 在正则分组后面使用,表示对第n个分组的引用(一定要写在正则表达式里)
建议:编写的正则分组数量越少越好

posted @ 2020-02-29 22:16  ImbaCOOL  阅读(211)  评论(0)    收藏  举报