JS进阶笔记

1.创建类

class Star{
	constructor(uname){		//构造函数
		this.uname = uname;
	}
}

2.继承

语法

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里面,谁调用指向谁

3.实例成员和静态成员

实例成员就是构造函数内部通过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

4.原型对象prototype

构造函数存在浪费内存问题,JS规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。我们可以把那些不变的方法,直接定义在prototype上,这样所有对象的实例就可以共享这些方法。

function Star(uname, age){
	this.uname = uname;
	this.age = age;
}
Star.prototype.sing  = funtion(){
		console.log('我会唱歌');
}

5.对象原型__proto__

对象都会有一个属性__proto__指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在
JS进阶笔记_第1张图片
注意:很多情况下,我们需要手动的利用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('我会演电影');
	}
}

构造函数、实例、原型对象三者之间的关系
JS进阶笔记_第2张图片

6.原型链

Star原型对象里面的__proto__原型指向的是Object.prototype
Object原型对象里面的__proto__原型指向的是null
JS进阶笔记_第3张图片

7.JS的查找机制

①当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
②如果没有就查找他的原型(也就是__proto__指向的prototype原型对象)
③如果还没有就查找原型对象的原型(Object的原型对象)
④以此类推一直找到Object为止(null)
⑤__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线

8.扩展内置对象

可以通过原型对象,对原来的内置对象进行扩展自定义的方法,比如给数组增加自定义求偶数和的功能。

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());

9.继承

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);

JS进阶笔记_第4张图片

10.类的本质

类的本质还是一个函数,可以简单的认为类是构造函数的另一种写法
(1)类有原型对象prototype
(2)类原型对象prototype里面有constructor指向类本身
(3)类可以通过原型对象添加方法
(4)构造函数创建的实例对象有__proto__ 原型指向构造函数的原型对象

11.ES5中的新增方法

数组方法
迭代遍历方法:forEach()、map()、filter()、some()、every();

  1. forEach()

array.forEach(function(currentValue, index, arr))

  • 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);
  1. filter()

array.filter(function(currentValue, index, arr))

  • filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组
  • 注意它直接返回一个新数组
  • currentValue:数组当前项的值
  • index:数组当前项的索引
  • arr:数组对象本身
var arr = [12, 66, 4,88];
var newArr = arr.filter(function(value, index)){
	return value >= 20;
});
console.log(newArr);
  1. some()

array.some(function(currentValue, index, arr))

  • some()方法用于检测数组中的元素制定条件,通俗点查找数组中是否有满足条件的元素
  • 注意它返回是布尔值,如果查找到这个元素,就返回true, 如果查找不到就返回false
  • 如果找到第一个满足条件的元素,则终止循环,不在继续查找
  • 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说明:以对象形式{}书写

  • value:设置属性的值,默认为undefined
  • writable:值是否可以重写。true|false 默认为false
  • enumerable:目标属性是否可以被枚举。true|false 默认为false
  • configurable:目标属性是否可以被删除或是否可以再次修改特性。true|false 默认为false
Object.defineProperty(obj, 'id', {
	writable:false,		//不允许修改这个id属性值,默认也是false
});

12.函数的进阶

1. 函数的定义方式

  1. 自定义函数

function fn() {};

  1. 函数表达式(匿名函数)

var fun = function() {};

  1. 利用new Function(‘参数1’, ‘参数2’, …,‘函数体’);

var f = new Function(‘a’, ‘b’, ‘console.log(a + b)’;
f(1, 2);

所有的函数都是Function的实例对象
JS进阶笔记_第5张图片

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])

  • thisArg: 在fun函数运行时指定的this值
  • 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);
  1. bind方法
    bind方法不会调用函数,但是能改变函数内部this指向

fun.bind(thisArg, arg1, arg2, …)

  • thisArg: 在fun函数运行时指定的this值
  • arg1, arg2:传递的其他参数
  • 返回由指定的this值初始化参数改造的原拷贝函数
var o = {
 	name: 'andy'
}
funtion fn(a, b){
	console.log(this);
};
fn.bind(o);
//会返回一个新函数 
//不想调用又想改变指向就用bind 

13.严格模式

JS进阶笔记_第6张图片
JS进阶笔记_第7张图片
在这里插入图片描述
JS进阶笔记_第8张图片
严格模式中的变化
① 在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法,变量都必须先用var命令声明,然后再使用
②严禁删除已经声明的变量。例如,delete x; 语法是错误的
③严格模式下全局作用域中函数中的this是undefined ,如果给它赋值则会报错
④严格模式下,如果构造函数不加new调用,this会报错
⑤严格模式下,函数参数名不能重复

14.高阶函数

高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。

function fn(callback){
	callback&&callback():
}
fn(function(){alert('hi')}

function fn(){
	return funtcion(){}
}
fn();
//此时fn就是一个高阶函数,最典型的就是作为回调函数

14.闭包

闭包(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();

15.递归

函数内部自己调用自己

//利用递归函数求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);

浅拷贝和深拷贝

  1. 浅拷贝只是拷贝一层,更深层次对象级别的值拷贝引用
var obj = {
	id: 1,
	name: 'andy'
	msg: {
		age: 18
	}
};
var o = {};
for(var k in obj){
	//k是属性名 obj[k]是属性值
	o[k] = obj[k];
}

JS进阶笔记_第9张图片

  1. 深拷贝拷贝多层,每一级别的数据都会拷贝
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);

JS进阶笔记_第10张图片
3. es6新增方法可以浅拷贝

Object.assign(target, …sources)

Object.assign(o, obj);

16.正则表达式

正则表达式(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)

  1. regexObj是写的正则表达式
  2. str是我们要测试的文本
  3. 就是检测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');
  1. 第一个参数:被替换的字符串或者正则表达式
  2. 第二个参数:替换为的字符串
  3. 返回值是一个替换完毕的新字符串

正则表达式中的参数
/表达式/[switch]
switch(也称为修饰符)按照什么样的模式来匹配,有三种值:

  • g:全局匹配
  • i:忽略大小写
  • gi:全局匹配+忽略大小写

你可能感兴趣的:(前端,javascript,html5)