class Star{
constructor(uname){ //构造函数
this.uname = uname;
}
}
语法
class Father{ //父类
}
class Son exteneds Father { //子类继承父类
}
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);//调用了父类中的构造函数
}
}
继承中的属性或者方法查找原则:就近原则
1.继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
2.继承中,如果子类里面没有,就去查找弗雷有没有这个方法,如果有,就执行父类的这个方法(就近原则)
注意:子类在构造函数中使用super,必须放到this前面(必须先调用父类的构造方法,再使用子类构造方法)
class Person{ // 父类
constru## 标题ctor(surname){
this.surname = surname;
}
}
class Student extends Person //子类继承父类
constructor(surname, firstname){
super(surname); //调用父类的constructor
this.firstname = firstname; //定义子类独有的属性
}
}
1.在ES6中类没有变量提升,所以必须先定义类,才能通过实例化对象
2.类里面的共有的属性和方法一定要加this使用
3.this里面,谁调用指向谁
实例成员就是构造函数内部通过this添加的成员,只能通过实例化的对象来访问
function Star(uname, age){
this.uname = uname;
this.age = age;
this.sing = fuction(){
console.log('我会唱歌');
}
}
var ldh = new Star('刘德华', 18);
console.log(ldh.uname);
ldh.sing();//正常运行
console.log(Star.uname);//undefine,不可以通过构造函数来访问实例成员
静态成员 在构造函数本身上添加的成员 sex就是静态成员
Star.sex = '男';
//静态成员只能通过构造函数来访问
console.log(Star.sex);//正常运行
console.log(ldh.sex);//undefine
构造函数存在浪费内存问题,JS规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。我们可以把那些不变的方法,直接定义在prototype上,这样所有对象的实例就可以共享这些方法。
function Star(uname, age){
this.uname = uname;
this.age = age;
}
Star.prototype.sing = funtion(){
console.log('我会唱歌');
}
对象都会有一个属性__proto__指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在
注意:很多情况下,我们需要手动的利用constructor这个属性指回原来的构造函数
function Star(uname, age){
this.uname = uname;
this.age = age;
}
//constructor依旧存在
Star.prototype.sing = function(){
console.log('我会唱歌');
};
Star.prototype.movie = function(){
console.log('我会演电影');
}
//因为采用的是赋值形式,如果不重新指回,constructor将不存在
Star.prototype = {
//constructor:star,
sing: function(){
console.log('我会唱歌');
},
movie: function(){
console.log('我会演电影');
}
}
Star原型对象里面的__proto__原型指向的是Object.prototype
Object原型对象里面的__proto__原型指向的是null
①当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
②如果没有就查找他的原型(也就是__proto__指向的prototype原型对象)
③如果还没有就查找原型对象的原型(Object的原型对象)
④以此类推一直找到Object为止(null)
⑤__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
可以通过原型对象,对原来的内置对象进行扩展自定义的方法,比如给数组增加自定义求偶数和的功能。
Array.prototype.sum = function(){
var sum = 0;
for(var i = 0; i< this.length; i++){
var sum = 0;
for (var i = 0; i <this.length; i++){
sum += this[i];
}
return sum;
}
var arr = [1,2,3];
console.log(arr.sum());
ES6之前并没有给我们提供extends继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承
call
调用这个函数,并且修改函数运行时的this指向
fun.call(thisArg, arg1, arg2, …)
thisArg :当前调用函数this的指向对象
arg1, arg2:传递的其他参数
function fn(x, y){
console.log('我想喝手磨咖啡');
console.log(this);
}
var o = {
name: 'andy'
};
//1.call()可以调用函数
fn.call();
//2.call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o这个对象
//1传给x,2传给y
fn.call(o, 1, 2);
借用父构造函数继承属性
//1.父构造函数
function Father(uname, age){
//this指向福构造函数的对象实例
this.uname = uname;
this.age = age;
}
//2.子构造函数
function Son(uname, age){
//this指向子构造函数的对象实例
//此时这个函数的this 就指向了子对象的this
Father.call(this, uname, age);
}
var son = new Son('刘德华', 18);
console.log(son);
利用原型对象继承方法
//1.父构造函数
function Father(uname, age){
//this指向福构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function(){
console.log(1000000)
}
//2.子构造函数
function Son(uname, age){
//this指向子构造函数的对象实例
//此时这个函数的this 就指向了子对象的this
Father.call(this, uname, age);
}
var son = new Son('刘德华', 18);
//Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对象,那么父原型对象也会跟着一起变化
Son.prototype = new Father();
//如果利用对象的形式修改了原型对象,别忘了利用constructor指回原来的构造函数
Son.prototype.constructor = Son;
//这个是子构造函数专门的方法
Son.prototype.exam = function(){
console.log('孩子要考试');
}
console.log(son);
类的本质还是一个函数,可以简单的认为类是构造函数的另一种写法
(1)类有原型对象prototype
(2)类原型对象prototype里面有constructor指向类本身
(3)类可以通过原型对象添加方法
(4)构造函数创建的实例对象有__proto__ 原型指向构造函数的原型对象
数组方法
迭代遍历方法:forEach()、map()、filter()、some()、every();
array.forEach(function(currentValue, index, arr))
var arr = [1,2,3];
var sum = 0;
arr.forEach(function(value, index, array)){
console.log('每个数组元素' + value);
console.log('每个数组元素的索引号' + index);
console.log('数组本身' + array);
sum += value;
})
console.log(sum);
array.filter(function(currentValue, index, arr))
var arr = [12, 66, 4,88];
var newArr = arr.filter(function(value, index)){
return value >= 20;
});
console.log(newArr);
array.some(function(currentValue, index, arr))
var arr = [12, 66, 4,88];
var flag = arr.some(function(value)){
return value >= 20;
});
console.log(flag);
在forEach里面return不会终止迭代,在some里面return 会终止迭代
字符串方法
trim()方法会从一个字符串的两端删除空白字符
str.trim();
trim()方法并不影响原字符本身,它返回的是一个新的字符串
对象方法
Object.defineproperty()定义对象中新属性或修改原有的属性
Object.defineProperty(obj, prop, descriptor)
Object.defineProperty第三个参数descriptor说明:以对象形式{}书写
Object.defineProperty(obj, 'id', {
writable:false, //不允许修改这个id属性值,默认也是false
});
1. 函数的定义方式
function fn() {};
var fun = function() {};
var f = new Function(‘a’, ‘b’, ‘console.log(a + b)’;
f(1, 2);
2. 函数内this指向
this一般指向调用者
调用方式 | this指向 |
---|---|
普通函数调用 | window |
构造函数调用 | 实例对象 原型对象里面的方法也指向实例对象 |
对象方法调用 | 该方法所属对象 |
事件绑定方法 | 绑定事件对象 |
定时器函数 | window |
立即执行函数 | window |
3.改变函数内部this指向
1.call方法
call方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的this指向
fun.call(thisArg, arg1, arg2, …)
var o = {
name: 'andy'
}
funtion fn(a, b){
console.log(this);
console.log(a + b);
};
fn.call(o, 1, 2);
// call的作用是第一个可以调用函数,第二个可以改变函数内this的指向
2.apply方法
apply()方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的this指向.
fun.apply(thisArg, [argsArray])
var o = {
name: 'andy'
}
funtion fn(a, b){
console.log(this);
console.log(arr);
};
fn.apply(o, ['apple']);
//1.也是调用函数 第二个可以改变函数内部this的指向
//2. 但是它的参数必须是数组(伪数组)
//3.apply的主要应用 比如说我们可以利用apply 借助于数学内置对象求最大值
var arr = [1, 66, 3, 99, 4];
Math.max.apply(Math, arr);
fun.bind(thisArg, arg1, arg2, …)
var o = {
name: 'andy'
}
funtion fn(a, b){
console.log(this);
};
fn.bind(o);
//会返回一个新函数
//不想调用又想改变指向就用bind
严格模式中的变化
① 在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法,变量都必须先用var命令声明,然后再使用
②严禁删除已经声明的变量。例如,delete x; 语法是错误的
③严格模式下全局作用域中函数中的this是undefined ,如果给它赋值则会报错
④严格模式下,如果构造函数不加new调用,this会报错
⑤严格模式下,函数参数名不能重复
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。
function fn(callback){
callback&&callback():
}
fn(function(){alert('hi')}
function fn(){
return funtcion(){}
}
fn();
//此时fn就是一个高阶函数,最典型的就是作为回调函数
闭包(closure)指有权访问 另一个函数 作用域 中 变量 的 函数,简单理解就是,一个作用域可以访问另一个函数内部的局部变量
//闭包:我们fun这个函数作用域 访问了另外一个函数fn里面的局部变量num
function fn(){
var num = 10;
function fun(){
console.log(num);
}
fun();
}
fn();
//我们fn外面的作用域可以访问fn内部的局部变量
//闭包的主要作用:延伸了变量的作用范围
function fn(){
var num = 10;
function fun(){
console.log(num);
}
return fun;
}
var f = fn();
f();
函数内部自己调用自己
//利用递归函数求1~n的阶乘 1 * 2 * 3 * 4 * ... n
function fn(n) {
if (n==1){
return 1;
}
return n * fn(n - 1);
}
fn();
案例:遍历数据
var data = [{
id: 1,
name: '家电',
goods: [{
id:11,
gname: '冰箱'
},{
id: 12,
gname: '洗衣机'
}]
},{
id:2,
name: '服饰'
}];
//我们想要做输入id号,就可以返回的数据对象
//1.利用forEach去遍历里面的每一个对象
function getID(json, id){
json.forEach(function(item){
//console.log(item); //2个数组元素
if(item.id == id){
console.log(item);
//2.我们想要得里面层的数据 11 12可以利用递归函数
//里面应该有goods这个数组并且数组的长度不为0
} else if (item.goods && item.goods.length > 0){
getID(item.goods, id);
}
})
}
getID(data, 1);
getID(data, 2);
getID(data, 11);
浅拷贝和深拷贝
var obj = {
id: 1,
name: 'andy'
msg: {
age: 18
}
};
var o = {};
for(var k in obj){
//k是属性名 obj[k]是属性值
o[k] = obj[k];
}
var obj = {
id: 1,
name: 'andy'
msg: {
age: 18
}
};
var o = {};
function deepCopy(newobj, oldobj){
for(var k in oldobj){
//判断我们的属性值属于哪种类型
//1.获取属性值 oldobj[k]
var item = oldobj[k];
//2.判断这个值是否是数组
if(item instanceof Array){
newobj[k] = [];
deepCopy(newobj[k], item);
}else if(item instanceof Object) {
//3.判断这个值是否是对象
newobj[k] = {};
deepCopy(newobj[k], item);
} else{
//4.属于简单数据类型
newobj[k] = item;
}
}
}
deepCopy(o, obj);
Object.assign(target, …sources)
Object.assign(o, obj);
正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式。在JS中,正则表达式也是对象。正则表通常被用来检索、替换那些符合某个模式(规则)的文本,例如验证表单:用户名表单只能输入英文字母、数字或下划线,昵称输入框中可以输入中文(匹配)。此外。正则表达式还常用语过滤掉页面中的一些敏感词(替换),或从字符串中获取我们想要得特定部分(提取)等。
正则表达式的特点
1.灵活性、逻辑性和功能性非常的强
2.可以迅速地用极简单的方式达到字符串的复杂控制
3.实际开发中一般都是直接复制写好的正则表达式,但是要求会使用正则表达式并且根据实际情况修改正则表达式
创建正则表达式
在js中,可以通过两种方式创建一个正则表达式
//1.通过调用RegExp对象的构造函数创建
var regexp = new RegExp(/123/);
//2.通过字面量来创建
var rg = /123/;
测试正则表达式test
test()正则对象方法,用于建则字符串是都符合该规则,该对象会返回true或false,其参数是测试字符串
regexObj.test(str)
//只要包含有abc这个字符串返回的都是true
var rg = /123/;
rg.test(123);
正则表达式的组成
一个正则表达式可以由简单的字符构成,比如/abc/,也可以是简单和特殊字符的组合,比如/ab*c/,其中特殊字符也被称为元字符,在正则表达式中是具有特殊意义的专用符号,如^、$、+等
边界符
正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符
边界符 | 说明 |
---|---|
^ | 表示匹配行首的文本(以谁开始) |
$ | 表示匹配行尾的文本(以谁结束) |
如果^和$在一起,表示必须是精确匹配
var reg = /^abc/;
console.log(reg.test('abc');//true
console.log(reg.test('abcd');//true
console.log(reg.test('aabcd');//false
var reg = /^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 reg = /[abc]/;//只要包含有a或者包含有b或者包含有c都返回为true
console.log(rg.test('andy'));
var rg1 = /^[abc]$/;//三选一,只有是a或b或c者三个字母才返回true
console.log(rg1.test('aa'));//true
console.log(rg1.test('a'));//true
console.log(rg1.test('b'));//true
console.log(rg1.test('c'));//true
console.log(rg1.test('abc'));//false
var rg1 = /^[a-z]$/;//26个英文字母,任何一个字母才返回true
//字符组合
var rg1 = /^[a-zA-Z0-9_-]$/;//26个大小写英文字母,任何一个字母才返回true,下划线和短横线
var rg1 = /^[^a-zA-Z0-9_-]$/;//如果中括号里面有^ 表示取反的意思 也就是说不能包括上述字符
量词符
量词 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
var reg = /^a*$/;
console.log(reg.test('');//true
console.log(reg.test('a');//true
console.log(reg.test('aaaa');//true
var reg = /^a+$/;
console.log(reg.test('');//false
console.log(reg.test('a');//true
console.log(reg.test('aaaa');//true
var reg = /^a?$/;
console.log(reg.test('');//true
console.log(reg.test('a');//true
console.log(reg.test('aaaa');//fasle
var reg = /^a{3}$/;
console.log(reg.test('');//false
console.log(reg.test('a');//false
console.log(reg.test('aaa');//true
console.log(reg.test('aaaa');//fasle
var reg = /^a{3,}$/;
console.log(reg.test('');//false
console.log(reg.test('a');//false
console.log(reg.test('aaa');//true
console.log(reg.test('aaaa');//true
var reg = /^a{3,6}$/;
console.log(reg.test('');//false
console.log(reg.test('a');//false
console.log(reg.test('aaa');//true
console.log(reg.test('aaaa');//true
console.log(reg.test('aaaaaaa');//fasle
var rg1 = /^[a-zA-Z0-9_-]{6}$/;//只能输入26个大小写英文字母,下划线和短横线,可以重复六次
var reg = /^[abc]$/;
//a也可以 b也可以 c也可以 a||b||c
//大括号量词符,里面表示重复次数
var reg = /^abc{3}$/; //它只是让c重复三次 abccc
console.log(reg.test('abc'));
console.log(reg.test('abcabcabc'));
console.log(reg.test('abccc'));
//小括号 表示优先级
var reg = /^(abc){3}$/; //它是让abc重复三次
console.log(reg.test('abc'));
console.log(reg.test('abcabcabc'));
console.log(reg.test('abccc'));
预定义类
预定类 | 说明 |
---|---|
\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()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式
stringObject.replace(regexp/substr, replacement)
var str = 'andy和red';
var newStr = str.replace('andy', 'baby');
正则表达式中的参数
/表达式/[switch]
switch(也称为修饰符)按照什么样的模式来匹配,有三种值: