10.1 JS面向对象
1.创建类和实例
class name{
//class body
}
var x = new name();
但ES6以前,对象不是基于类创建的,而是用一种 构建函数 的特殊函数来定义的。
//1. 对象字面量
var obj1 = {
}
//2. new Object()
var obj2 = new Object()
//3. 自定义构造函数
function obj3(username,age){
this.username=username;
this.age=age
this.say=function(name){
console.log('我是'+name)
}
}
var user=new Obj3('张三',20)
user.say(user.name)
2.构造函数constructor()
class Person {
constructor(name,age) {
// constructor 构造方法或者构造函数
this.name = name;
this.age = age;
}
say() {
console.log(this.name + '你好');
}
}
var ldh = new Person('刘德华', 18);
3.类的继承
3.1继承
子类继承父类的属性、方法
class Father{
// 父类
}
class Son extends Father {
// 子类继承父类
}
3.2super关键字
用于访问和调用父类上的函数(包括父类的构造函数)
(可以区分父类和子类中定义的函数)
class Father {
say() {
return '我是爸爸';
}
}
class Son extends Father {
// 这样子类就继承了父类的属性和方法
say() {
// super.say() super 调用父类的方法
return super.say() + '的儿子';
}
}
var damao = new Son();//new的时候类要大写
console.log(damao.say());
constructor 里面的this指向实例对象, 方法里面的this 指向这个方法的调用者
10.2 构造函数和原型
1.构造函数
1.构造函数用于创建某一类对象,其首字母要大写
2.构造函数要和 new 一起使用才有意义
new在执行时:
①在内存中创建一个新的空对象。
②让 this 指向这个新的对象。(构造函数中的this指向的是对象)
③执行构造函数里面的代码,给这个新对象添加属性和方法。
④返回这个新对象(所以构造函数里面不需要 return )。
1.1静态成员和实例成员
-
静态成员:在构造函数本上添加的成员称为静态成员,只能由构造函数本身来访问
//定义 Obj.sex="man" //访问: obj.sex
-
实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问
//定义 function obj(sex){ this.sex=sex } //访问 var ob=new Obj('man') ob.sex
1.2构造函数原型prototype(是个对象)
JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。注意这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。
- 原型是什么 ?
一个对象,我们也称为 prototype 为原型对象。
- 原型的作用是什么 ?
共享方法。(可以节约内存)
function User(name){
this.name=name
}
User.prototype.say=function(){
console.log('hi')
}
1.3对象原型 _ proto_
指向构造函数的原型对象(两者是等价的)
不能直接拿去赋值。
1.4constructor构造函数
对象原型( proto)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身。
user.prototype.constructor
==zs.__proto__.constructor
==构造函数constructor
1.5原型链⭐⭐⭐⭐⭐
原型链也是JavaScript的成员查找机制。
构造函数和原型对象中函数的this都指向的是实例对象。
1.6扩展内置对象的自定义方法
比如给数组增加自定义求和的功能
Array.prototype.sum = function(){
//函数体
var sum = e;
for (var i = e; i < this.length; i++){
sum+= this[i];
}
return sum;
}
//使用
var arr1=new Array(11,22,33)//var arr1=[11,22,33]
arr1.sum()
2.继承
ES6之前并没有给我们提供 extends 继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。
2.1call()
fn.call(thisArg, arg1, arg2, ...)//调用这个函数, 并且修改函数运行时的 this 指向
//thisArg :当前调用函数 this 的指向对象
//arg1,arg2:给fn传递的其他参数
如果通过this把父类型的this指向子类型的this,就可以实现子类型继承父类型。
//在子类中
function Student(name,age){
Person.call(this,name,age,sex);//此时调用这个函数,同时父类的 this 指向子类的 this
this.age=age//子类新数据成员
}
2.2借用原型对象继承父类型
一般情况下,对象的方法都在构造函数的原型对象中设置,通过构造函数无法继承父类方法。
①将子类所共享的方法提取出来,让子类的 prototype 原型对象 = new 父类()
②本质:子类原型对象等于是实例化父类,因为父类实例化之后另外开辟空间,就不会影响原来父类原型对象
③将子类的 constructor 从新指向子类的构造函数
//Son.prototype=Father.prototype XXX
Son.prototype=new Father();
Son.prototype.constructor=Son;
3.ES5新增方法
3.1数组方法(遍历)
-
forEach()
array.forEach(function(currentValue, index, arr))
currentValue:数组当前项的值
index:数组当前项的索引
arr:数组对象本身
-
map()
-
filter()
array.filter(function(currentValue, index, arr))
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组
注意它直接返回一个新数组
currentValue: 数组当前项的值
index:数组当前项的索引
arr:数组对象本身
-
some()
array.some(function(currentValue, index, arr))
some() 方法用于检测数组中的元素是否满足指定条件. 通俗点,查找数组中是否有满足条件的元素
注意它返回值是布尔值, 如果查找到这个元素, 就返回true , 如果查找不到就返回false.
如果找到第一个满足条件的元素,则终止循环. 不在继续查找.
currentValue: 数组当前项的值
index:数组当前项的索引
arr:数组对象本身
-
every()
3.2字符串方法
str.trim()
trim() 方法并不影响原字符串本身,它返回的是一个新的字符串的副本。
3.3.对象方法
-
Object.keys() 用于获取对象自身所有的属性
Object.keys(obj)
返回一个由属性名组成的数组
-
Object.defineProperty() 定义新属性或修改原有的属性
Object.defineProperty(obj, prop, {descriptor(是个对象)})
value: 设置属性的值 默认为undefined
writable: 值是否可以重写。true | false 默认为false
enumerable: 目标属性是否可以被枚举。true | false 默认为 false
configurable: 目标属性是否可以被删除或是否可以再次修改特性 true | false 默认为false
10.3 函数进阶
1.函数内this的指向
2.call apply bind方法
2.1call()
调用函数+改变函数的this指向
fun.call(thisArg, arg1, arg2, ...)
thisArg:在 fun 函数运行时指定的 this 值
arg1,arg2:传递的其他参数
返回值就是函数的返回值,因为它就是调用函数
因此当我们想改变 this 指向,同时想调用这个函数的时候,可以使用 call,比如继承
2.2apply()
调用函数+改变函数的this指向
fun.apply(thisArg, [argsArray])
thisArg:在fun函数运行时指定的 this 值
argsArray:传递的值,必须包含在数组里面
返回值就是函数的返回值,因为它就是调用函数
因此 apply 主要跟数组有关系,比如使用 Math.max() 求数组的最大值
2.3bind()
只改变函数内部this指向+不调用
fun.bind(thisArg, arg1, arg2, ...)
thisArg:在 fun 函数运行时指定的 this 值
arg1,arg2:传递给fun的其他参数
返回由指定的 this 值和初始化参数改造的原函数拷贝(可以赋值给新的变量)
因此当我们只是想改变 this 指向,并且不想调用这个函数的时候,可以使用 bind
3.严格模式
简介:
1.消除了 Javascript 语法的一些不合理、不严谨之处,减少了一些怪异行为。
2.消除代码运行的一些不安全之处,保证代码运行的安全。
3.提高编译器效率,增加运行速度。
4.禁用了在 ECMAScript 的未来版本中可能会定义的一些语法,为未来新版本的 Javascript 做好铺垫。比如一些保留字如:class, enum, export, extends, import, super 不能做变量名
3.1开启严格模式
-
为脚本开启(整体)
<script> "use strict"; </script>
-
为函数开启(部分)
放在函数体的第一行
function fn(){
"use strict";
//function body
}
3.2严格模式中的变化
3.2.1变量规定
正常模式:
- 可以使用未声明的变量,默认为全局变量
严格模式:
- 变量在使用之前必须先声明
- 已经声明的变量禁止删除,例如(delete x)是错误的
3.2.2this指向问题
正常模式:
- 全局作用域下,this指向window
- 构造函数不加new,可以当作普通函数调用,this指向的是全局对象window
严格模式:
- 全局作用域下,this指向undefined
- 构造函数不加new,调用时this指向undefined,给它赋值会报错
- new 实例化的构造函数指向创建的对象实例。
- 定时器 this 还是指向 window 。
- 事件、对象还是指向调用者。
3.2.3函数变化
严格模式:
- 函数不能有重名参数
- 函数必须声明在顶层
4.高阶函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。(操作对象是函数而不是变量)
典型:回调函数
5.闭包
闭包(closure)指有权访问另一个函数作用域中变量的函数。
闭包作用:延伸变量的作用范围。
<script>
function fn() {
var num = 10;
return function {
console.log(num); // 10
}
}
var f = fn();
f()
</script>
10.4 正则表达式(验证密码规范等)
正则表达式( Regular Expression )是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对象。
1.创建正则表达式
1.1通过调用RegExp对象的构造函数创建
var 变量名 = new RegExp(/表达式/);
1.2通过字面量创建
var 变量名 = =/表达式/;
2.测试正则表达式
test() 正则对象方法,用于检测字符串是否符合该规则,该对象会返回 true 或 false,其参数是测试字符串。
regexObj.test(str)
1.regexObj 是写的正则表达式
2.str 我们要测试的文本
3.就是检测str文本是否符合我们写的正则表达式规范.
3.正则表达式中的特殊字符
3.1边界符
边界符 | 说明 |
---|---|
^ | 首 |
$ | 尾 |
如果 ^ 和 $ 在一起,表示必须是精确匹配
3.2字符类
字符类表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符都放在方括号内。
3.2.1[ ]
/[abc]/.test('andy') // true
后面的字符串只要包含 abc 中任意一个字符,都返回 true 。
3.2.2[-] 方括号内部 范围符-
/^[a-z]$/.test('c') // true
方括号内部加上 - 表示范围,这里表示 a 到 z 26个英文字母都可以。
3.2.3[^] 方括号内部 取反符^
/[^abc]/.test('andy') // false
方括号内部加上 ^ 表示取反,只要包含方括号内的字符,都返回 false 。
注意和边界符 ^ 区别,边界符写到方括号外面。
3.2.4字符组合
/[a-z1-9]/.test('andy') // true
方括号内部可以使用字符组合,这里表示包含 a 到 z 的26个英文字母和 1 到 9 的数字都可以。
3.3量词符
3.4预定义类
预定义类指的是某些常见模式的简写方式。
例:分析:
1.手机号码: /^1[3|4|5|7|8] [0-9]{9}$/
2.QQ: [1-9] [0-9]{4,} (腾讯QQ号从10000开始)
3.昵称是中文: 1{2,8}$
10.5 ES6新增
1.变量
1.1 let ——ES6中新增的用于声明变量的关键字。
-
let声明的变量只在所处于的块级有效
var声明的变量不具备块级作用域特性
-
只能先声明再使用
-
暂时性死区
var tmp = 123; if (true) { tmp = 'abc';//undefined 因为和下面的let是绑定的 let tmp; }
1.2 const ——声明常量,赋值后不能修改。
var | let | const |
---|---|---|
函数级作用域 | 块级作用域 | 块级作用域 |
变量提升 | 不存在变量提升 | 不存在变量提升 |
值可更改 | 值可更改 | 值不可更改 |
2.解构赋值
对数据解构,按照对应位置,对变量赋值
2.1数组解构
let [a, b, c] = [1, 2, 3];
2.2对象解构
let person = {
name: 'zhangsan', age: 20 };
let {
name, age } = person;
3.箭头函数——ES6中新增的定义函数的方式
3.1定义
const fn = () => {
}
如果函数体只有一句代码,而且该代码就是返回值:可省略大括号
形参只有一个可以省略小括号
const sum=(num1,num2)=>num1+num2;
const num=num1=>num1
3.2this
箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this。
即,箭头函数没有自己的this,是继承而来的。
普通函数指向全局对象window。
3.3剩余参数
剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
function sum (first, ...args) {
console.log(first); // 10
console.log(args); // [20, 30]
}
sum(10, 20, 30)
剩余参数和解构配合使用
let students = ['wangwu', 'zhangsan', 'lisi'];
let [s1, ...s2] = students;
console.log(s1); // 'wangwu'
console.log(s2); // ['zhangsan', 'lisi']
4.Array的扩展方法
4.1扩展运算符(展开语法)
- 扩展运算符可以将数组或者对象转为用逗号分隔的参数序列。
let ary = [1, 2, 3];
// ...ary 1, 2, 3
console.log(...ary); // 输出都是:1 2 3
console.log(1, 2, 3)
-
扩展运算符可以应用于合并数组。
// 方法一 let ary1 = [1, 2, 3]; let ary2 = [3, 4, 5]; let ary3 = [...ary1, ...ary2]; // 方法二 ary1.push(...ary2);
-
将类数组或可遍历对象转换为真正的数组
let oDivs = document.getElementsByTagName('div'); oDivs = [...oDivs];
4.2构造函数方法:Array.from()
-
将类数组或可遍历对象转换为真正的数组
let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
-
方法还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
let arrayLike = { "0": 1, "1": 2, "length": 2 } let newAry = Array.from(aryLike, item => item *2)
4.3实例方法:find()/findIndex()/includes()
-
find()用于找出第一个符合条件的数组成员,如果没有找到返回undefined
let ary = [{ id: 1, name: '张三‘ }, { id: 2, name: '李四‘ }]; let target = ary.find((item, index) => item.id == 2);
-
findIndex()用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1
let ary = [1, 5, 10, 15]; let index = ary.findIndex((value, index) => value > 9); console.log(index); // 2
-
includes()表示某个数组是否包含给定的值,返回布尔值。
[1, 2, 3].includes(2) // true [1, 2, 3].includes(4) // false
5.String 的扩展方法
5.1模板字符串
ES6新增的创建字符串的方式,使用反引号定义。
模板字符串中可以换行。{}中可以是变量,也可以是函数。
let name = `zhangsan`;
let name = '张三';
let sayHello = `hello,my name is :
${
name}`;
// hello, my name is :
//zhangsan
5.2startsWith() 和 endsWith()
startsWith():表示参数字符串是否在原字符串的头部,返回布尔值
endsWith():表示参数字符串是否在原字符串的尾部,返回布尔值
let str = 'Hello world!';
str.startsWith('Hello') // true
str.endsWith('!') // true
5.3实例方法:repeat()
repeat方法表示将原字符串重复n次,返回一个新字符串。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
6.Set数据结构(集合)
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成 Set 数据结构。
const set = new Set([1, 2, 3, 4, 4]);
6.1实例方法
add(value):添加某个值,返回 Set 结构本身
delete(value):删除某个值,返回一个布尔值,表示删除是否成功
has(value):返回一个布尔值,表示该值是否为 Set 的成员
clear():清除所有成员,没有返回值
const s = new Set();
s.add(1).add(2).add(3); // 向 set 结构中添加值
s.delete(2) // 删除 set 结构中的2值
s.has(1) // 表示 set 结构中是否有1这个值 返回布尔值
s.clear() // 清除 set 结构中的所有值
6.2遍历
Set 结构的实例与数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值。
s.forEach(value => console.log(value))
\u4e00-\u9fa5 ↩︎