前端JS高级
1.对象与类
对象
对象是由属性和方法组成的:是一个无序键值对的集合,指的是一个具体的事物
属性:事物的特征,在对象中用属性来表示(常用名词)
方法:事物的行为,在对象中用方法来表示(常用动词)
类
类抽象了对象的公共部分,它泛指某一大类(class)对象特指某一个, 通过类实例化一个具体的对象
创建类
语法:
class name{
constructor( ){ ..... }
.....
}
var 变量名 = new name();
constructor构造函数
可以接受传递过来的参数,同时返回实例对象 ,只要 new 生成实例时,就会自动调用这个函数, 如果我们不写这个 函数,类也会自动生成这个函数
类创建添加属性和方法
// 1. 创建类 class 创建一个 明星类
class Star {
// 类的共有属性放到 constructor 里面
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
sing(song) {
// console.log('我唱歌');
console.log(this.uname + song);
}
}
// 2. 利用类创建对象 new
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 20);
console.log(ldh);
console.log(zxy);
// (1) 我们类里面所有的函数不需要写function
//(2) 多个函数方法之间不需要添加逗号分隔
ldh.sing('冰雨');
zxy.sing('李香兰')
类的继承
class son extends father { … }
// 1. 类的继承
// class Father {
// constructor() {
// }
// money() {
// console.log(100);
// }
// }
// class Son extends Father {
// }
// var son = new Son();
// son.money();
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); //调用了父类中的构造函数
}
}
var son = new Son(1, 2);
var son1 = new Son(11, 22);
son.sum();
son1.sum();
关键字super
用于访问和调用对象父类上的函数,必须在子类this之前调用
// super 关键字调用父类普通函数
class Father {
say() {
return '我是爸爸';
}
}
class Son extends Father {
say() {
// console.log('我是儿子');
console.log(super.say() + '的儿子');
// super.say() 就是调用父类中的普通函数 say()
}
}
var son = new Son();
son.say();
// 继承中的属性或者方法查找原则: 就近原则
// 1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
// 2. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
// 3.如果子类想要继承父类的方法,同时在自己内部扩展自己的方法,利用super 调用 父类的构造函数,super 必须在子类this之前调用
this的指向
- constructor中的this指向的是new出来的实例对象
- 自定义的方法,一般也指向的new出来的实例对象
- 绑定事件之后this指向的就是触发事件的事件源
insertAdjacentHTML( ‘position’ , text)
可以直接把字符串格式添加到父元素中,和element.append(‘内容’)和element.prepend(‘内容’)类似
position插入的位置:
1.beforebegin: 元素自身前面 2.afterend: 元素自身后面
3.afterbegin: 元素内部第一个子节点之前 4.beforeend: 元素内部最后一个子节点之后
text: 插入的内容
鼠标双击事件
element.ondblclick 但双击会默认选中文字 解决方法插入下面代码:
// 双击禁止选定文字
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
双击文本框让文字内容处于选中状态
input.select();
2.构造函数和原理、继承、新增方法
构造函数和原型
静态成员和实例成员
实例成员 :构造函数内部通过this添加的成员
静态成员:在构造函数本身上添加的成员 比如:构造函数名.静态成员名 = ’ 内容 ';
,静态成员只能 通过构造函数来访问 比如:构造函数名.静态成员名
构造函数原型prototype
构造函数通过原型分配的函数是所有对象所共享的,每一个构造函数都有一个prototype 属性,指向另一个对象。这个 prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有
可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可 以共享这些方法
对象原型
对象都会有一个属性 _ _ proto _ _ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 _ _ proto_ _ 原型的存在
_ _ proto_ _对象原型和原型对象 prototype 是等价的
_ _ proto_ _对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是 它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype
constructor构造函数
对象原型( _ _ proto_ _)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身。
constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来 的构造函数。
一般情况下,对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法,我们可 以给原型对象采取对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,这样修 改后的原型对象 constructor 就不再指向当前构造函数了。此时,我们可以在修改后的 原型对象中,添加一个 constructor 指向原来的构造函数
原型链
①ldh 对象实例 ——(ldh._ _ proto_ _ )——>
②Str原型对象 prototype ——(prototype. _ _ proto_ _ )——>
③ object原型对象prototype ——(prototype. _ _ proto_ _ )——>
④null
构造函数实例和原型对象三角关系
①ldh 对象实例 ——(ldh._ _ proto_ _ )——>
②Str原型对象 prototype ——(star.prototype.constructor)——>
③构造函数 ——>①
③构造函数 ——( star.prototype )——> ② Str原型对象 prototype
原型对象中this指向
构造函数中的this和原型对象的this,都指向我们new出来的实例对象
继承
call()
语法:函数名.call( thisArg, arg1 , arg2…)
thisArg:当前调用函数this的指向对象
arg1 , arg2…:传递的其他参数
子构造函数继承父构造函数中的属性 和 借用原型对象继承方法
<script>
// 借用父构造函数继承属性
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function() {
console.log(100000);
};
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score;
}
// Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father();
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Son.prototype.constructor = Son;
// 这个是子构造函数专门的方法
Son.prototype.exam = function() {
console.log('孩子要考试');
}
var son = new Son('刘德华', 18, 100);
console.log(son);
console.log(Father.prototype);
console.log(Son.prototype.constructor);
</script>
ES5新增方法
forEach遍历数组
arr.forEach(function(value, index, array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的整个数组 })
//相当于数组遍历的 for循环 没有返回值
filter过滤数组
var arr = [1,2,3,4,5];
arr.filter(function(value, index, array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的整个数组
return value <=2;
})
console.log(newArr);//[1,2] //返回值是一个新数组
some查找数组
some 查找数组中是否有满足条件的元素
var arr = [10, 30, 4];
var flag = arr.some(function(value,index,array) {
//参数一是:数组元素
//参数二是:数组元素的索引
//参数三是:当前的整个数组
return value < 3; });
console.log(flag);//false返回值是布尔值,只要查找到满足条件的一个元素就立马终止循环
some和forEach区别
1.如果查询数组中唯一的元素, 用some方法更合适,在some 里面 遇到 return true 就 是终止遍历 迭代效率更高
2.在forEach 里面 return 不会终止迭代
去除字符串两端的空格
str.trim()
获取对象的属性名
Object.keys(对象名) //获取到当前对象中的属性名 ,返回值是一个数组
Object.defineProperty设置或修改对象中的属性
Object.defineProperty(对象名,'修改或新增的属性名',{
value:修改或新增的属性的值,
writable:true/false,//如果值为false 不允许修改这个属性值 enumerable: false,//enumerable 如果值为false 则不允许遍历 configurable: false //configurable 如果为false 则不允许删除这个属性 属性是否可以被删除或是否可以再次修改特性 })
3.this、严格模式、高阶函数、闭包、递归、正则表达式
函数内部的this指向
调用方式 | this指向 |
---|---|
普通函数调用 | window |
构造函数调用 | 实例对象 原型对象里面的方法也指向实例对象 |
对象方法调用 | 该方法所属对象 |
事件绑定方法 | 绑定事件对象 |
window | |
window |
改变函数内部 this 指向
1.call()方法
语法:函数名.call( thisArg, arg1 , arg2…)
thisArg:当前调用函数this的指向对象
arg1 , arg2…:传递的其他参数
2.apply()方法
语法:fun.apply( thisArg, [argsArray] )
thisArg: 在fun函数运行时指定的this值
argsArray: 传递的值,为数组形式
3.bind()方法
语法:fun.bind( thisArg, arg1,arg2… ) //不会调用函数,但能改变函数内部this指向
thisArg: 在fun函数运行时指定的this值
arg1 , arg2…:传递的其他参数
返回由指定的this值和初始化参数改造的原函数拷贝
三者的异同
共同点 : 都可以改变this指向
不同点: 1.call 和 apply 会调用函数, 并且改变函数内部this指向;
- call 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递
- 3.bind 不会调用函数, 可以改变函数内部this指向.
开启严格模式
在所有语句或者函数内部最前面添加 ’ use strict ';
高阶函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。
闭包
闭包(closure)指有权访问另一个函数作用域中变量的函数。简单理解就是 ,一个作 域可以访问另外一个函数内部的局部变量。
代码示例:
<script>
//3秒后打印li的内容
// var lis = document.querySelectorAll('li');
// for (var i = 0; i < lis.length; i++) {
// (function(i) {
// setTimeout(function() {
// console.log(lis[i].innerHTML);
// }, 3000)
// })(i);
// }
// 计算打车价格
var car = (function() {
var price = 5;
var begin = 13;
return {
price: function(n) {
if (n <= 3) {
return begin;
} else {
return (n - 3) * price + begin;
}
}
}
})();
console.log(car.price(5));
</script>
递归
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。简单理解:函 数内部自己调用自己, 这个函数就是递归函数
代码示例:
<script>
//利用递归求斐波那契数列
function fn(n) {
if (n == 1 || n == 2) {
return 1;
}
return fn(n - 1) + fn(n - 2);
}
console.log(fn(6));
</script>
正则表达式的创建
var rg = /123/;
正则表达式测试
var rg = /123/;
console.log(rg.test(123));//匹配字符中是否出现123 出现结果为true console.log(rg.test('abc'));//匹配字符中是否出现123 未出现结果为false
边界符
1.^:表示匹配行首的文本(以谁开始)
2.$:表示匹配行尾的文本(以谁结束)
如果 ^和 $ 在一起,表示必须是精确匹配。
var rg = /abc/; // 正则表达式里面不需要加引号 不管是数字型还是字符串型
// /abc/ 只要包含有abc这个字符串返回的都是true
console.log(rg.test('abc'));
console.log(rg.test('abcd'));
console.log(rg.test('aabcd'));
console.log('‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐');
var reg = /^abc/; console.log(reg.test('abc')); // true console.log(reg.test('abcd')); // true
console.log(reg.test('aabcd')); // false
console.log('‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐');
var reg1 = /^abc$/; // 精确匹配 要求必须是 abc字符串才符合规范 console.log(reg1.test('abc')); // true
console.log(reg1.test('abcd')); // false
console.log(reg1.test('aabcd')); // false
console.log(reg1.test('abcabc')); // false
字符类
字符类表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符 都放在方括号内。
[ ]方括号
表示有一系列字符可供选择,只要匹配其中一个就可以了
var rg = /[abc]/; // 只要包含有a 或者 包含有b 或者包含有c 都返回为true console.log(rg.test('andy'));//true
console.log(rg.test('baby'));//true
console.log(rg.test('color'));//true
console.log(rg.test('red'));//false
var rg1 = /^[abc]$/; // 三选一 只有是a 或者是 b 或者是c 这三个字母才返回 true console.log(rg1.test('aa'));//false
console.log(rg1.test('a'));//true
console.log(rg1.test('b'));//true
console.log(rg1.test('c'));//true
console.log(rg1.test('abc'));//true ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐var reg = /^[a‐z]$/ //26个英文字母任何一个字母返回 true ‐ 表示的是a 到z 的范 围 console.log(reg.test('a'));//true
console.log(reg.test('z'));//true
console.log(reg.test('A'));//false ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
//字符组合
var reg1 = /^[a‐zA‐Z0‐9]$/; // 26个英文字母(大写和小写都可以)任何一个字母返回 true ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
//取反 方括号内部加上 ^ 表示取反,只要包含方括号内的字符,都返回 false 。 var reg2 = /^[^a‐zA‐Z0‐9]$/;
console.log(reg2.test('a'));//false
console.log(reg2.test('B'));//false
console.log(reg2.test(8));//false
console.log(reg2.test('!'));//true
量词符
量词 | 说明 |
---|---|
* | 重复>=0次 |
+ | 重复>=1次 |
? | 重复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] |
正则替换replace
replace() 方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正 则表达式
stringObject.replace( / 表达式 / switch, replacement )
表达式 :被替换的字符串或正则表达式
switch:g–全局匹配; i–忽略大小写; gi–全局匹配+忽略大小写
replacement:替换为的字符串
返回值是一个替换完毕的新字符串
4.ES6语法
let
1.使用let关键字声明的变量才具有块级作用域,使用var声明的变量不具备块级作用 域特性
2.使用let关键字声明的变量没有变量提升,要先声明才能使用
const
用来声明常量,常量就是值(内存地址)不能变化的量
1.具有块级作用域 ,声明 const时候必须要给定值
2.如果是常量不能重新进行赋值,如果是基本数据类型,不能更改值,如果是复杂数据 类型,不能更改地址值
解构赋值
ES6中允许从数组中提取值,按照对应位置,对变量赋值,对象也可以实现解构
1.解构赋值就是把数据结构分解,然后给变量进行赋值
2.如果结构不成功,变量跟数值个数不匹配的时候,变量的值为undefined
3.数组解构用中括号包裹,多个变量用逗号隔开,对象解构用花括号包裹,多个变量用 逗号隔开
箭头函数
() => {} //():代表是函数; =>:必须要的符号,指向哪一个代码块;{}:函数体
const fn = () => {}//代表把一个函数赋值给fn
1.函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号
2.如果形参只有一个,可以省略小括号
3.箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this
剩余参数
function sum (first, ...args) {
console.log(first); // 10
console.log(args); // [20, 30]
}
sum(10, 20, 30);
Array 的扩展方法
扩展运算符 //扩展运算符可以将数组或者对象转为用逗号分隔的参数序列
let ary = [1, 2, 3];
...ary // 1, 2, 3
console.log(...ary); // 1 2 3,相当于下面的代码
console.log(1,2,3)
构造函数方法:Array.from()
将伪数组或可遍历对象转换为真正的数组
//定义一个集合
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
//转成数组
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
该方法还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理, 将处理后的值放入返回的数组
find()
用于找出第一个符合条件的数组成员,如果没有找到返回undefined
let ary = [{
id: 1,
name: '张三'
}, {
id: 2,
name: '李四'
}];
let target = ary.find((item, index) => item.id == 2);//找数组里面符合条件 的值,当数组中元素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
String 的扩展方法
模板字符串 //用反引号
let name = '张三'; let sayHello = `hello,my name is ${name}`; // hello, my name is zhangsan模板字符串中可以解析变量、换行、调用函数
startsWith() 和 endsWith()
表示参数字符串是否在原字符串的头部/尾部,返回布尔值
repeat()
repeat方法表示将原字符串重复n次,返回一个新字符串
Set 数据结构
类似于数组,但是成员的值都是唯一的,没有重复的值。
const 常量名 = new Set();
包含的方法:
1.add(value):添加某个值,返回 Set 结构本身
2.delete(value):删除某个值,返回一个布尔值,表示删除是否成功
3.has(value):返回一个布尔值,表示该值是否为 Set 的成员
4.clear():清除所有成员,没有返回值