点击通往->黑马pink讲js高级.
点击通往->尚硅谷ES6视频.
目录:
js高级:
第一部分、构造函数、原型和继承
1、构造函数原型prototype
①构造函数通过原型分配的函数是所有对象所共享的
②每一个构造函数都有一个prototype属性,指向另一个对象。这个prototype就是一个对象,这个对象的所有属性和方法都会被构造函数所拥有的
③我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例都可以共享这些方法
例如Star.prototype.sing = function (){}
2、对象原型__proto__
对象都会有一个属性__proto__指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为有对象__proto__原型存在
3、constructor构造对象
对象原型(proto)和构造函数原型对象(prototype)里面都有一个属性constructor属性,constructor我们称为构造函数,因为它指回构造函数本身
constructor主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数
很多情况我们需要手动利用constructor这个属性指回 原来的构造函数,例如多个方法写在一个对象里面的时候,constructor属性被覆盖了,就要手动添加:
4、构造函数、实例、原型对象三者关系
5、原型链
js的成员查找机制(规则):
- 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
- 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)
- 如果还没有就查找原型对象的原型(Object原型对象)
- 依次类推一直找到Object为止(null)
- __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
6、原型对象this指向
①在构造函数中,里面的this指向的是对象实例
②原型对象里面的this指向的是实例对象
7、继承
ES6之前是没有给我们提供extends继承。可以通过构造函数+原型对象模拟实现继承,称为组合继承。
(1)call()
调用这个函数,并且修改函数运行时的this指向
fun.call(thisArg,arg1,arg2,...)
thisArg:当前调用函数this的指向对象
arg1,arg2:传递其他参数
作用:
- 可以调用函数
- 可以改变函数的this指向
(2)继承父构造函数属性
(3)借用构造函数继承父类型方法
Son.prototype = new Father();
Son.prototype.constructor = Son;
第二部分、函数进阶
一、函数的定义和调用
1、函数的定义方式
- function声明方式(命名函数)
- 匿名表达式(匿名函数)
- (了解)new Function(‘参数1’,‘参数2’,‘函数体’) 里面的参数都是字符串
所有函数都是Function的实例对象
函数也是对象
2、函数的调用方式
- 普通函数
fn();
fn.call();
- 对象的方法
object.ff();
- 构造函数
new Star();
- 绑定事件函数
btn.onclick = function(){
}//点击了按钮就可以调用
- 定时器函数
srtInterval(function(){
},1000);//这个函数定时器自动1秒钟执行一次
- 立即执行函数
(function(){
})();//立即执行函数是自动调用
二、this
1、函数内this的指向
这些this的指向,是当我们调用函数的时候确定的。调用方式的不同决定了this的指向不同
一般指向我们的调用者
原型对象里面的this也是指向实例对象
2、改变函数内部this指向
- call方法
该方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的this指向
fun.call(thisArg,arg1,arg2,...)
call 可以实现继承
- apply方法
apply()方法调用一个函数。简单的理解为调用函数的方式,但是它可以改变函数的this指向
fun.apply(thisArg,[argsArray])
//thisArg:在fun函数运行时指定的this值
//argsArray:传递的值,必须包含在数组里面
//返回值就是函数的返回值,因为它就是调用函数
apply 主要应用:借助于数学内置对象求最大值最小值
var arr=[1,34,56,32,4];
var max = Math.max.apply(Math,arr);
- bind方法
bind()方法不会调用函数,但能改变函数内部的this指向
fun.bind(thisArg,arg1,arg2,...)
//thisArg:在fun函数运行时指定的this值
//arg1,arg2:传递的其他参数
//返回值:返回由指定的this值和初始化参数改造的原函数拷贝(一个新函数)
如果有的函数不需要立即调用,但是又想改变着函数内部的this指向,此时用bind
例如:
//我们有一个按钮,当我们点击之后,就禁用这个按钮,3秒后再开启这个按钮
var btn = document.querySelector('button');
btn.onclick = function(){
this.disabled = true;//这个this指向的就是btn这个按钮
setTimeout(function(){
this.disabled = false; //如果下面没用bind,这样写就不行,定时器里面的this指向window
}.bind(this),3000)//这个this指向的是btn这个对象
}
三、严格模式
1、严格模式对正常的javascript语义做了一些修改
- 消除了js语法的一些不合理、不严谨之处,减少了一些怪异行为
- 消除代码运行的一些不安全之处,保证代码运行正常
- 提高编译器效率,增加运行速度
- 禁用了ECMAScript的未来版本中可能会定义的一些语义,为未来新版本的js做好铺垫。比如一些保留字:class、enum、export、extends、super、import等不能作为变量名
2、开启严格模式
严格模式可以应用到整个脚本或个别函数中。
- 整个脚本:
开头写上:
'use strict';
//下面的js就会按照严格模式执行代码
防止变量污染,可以写成立即执行函数:
(function(){
'use strict'
})();
- 为某个函数开启:
function fn(){
'use strice'
}
3、严格模式中的变化
-
变量规定
①变量必须先声明再使用
②不能随意删除声明好的变量 -
严格模式下this指向问题
①以前全局作用域函数中的this指向window对象,严格模式下则是undefined
②严格模式下,如果构造函数不加new调用,this会报错;new实例化的构造函数指向创建的对象实例
③定时器this还是指向window,事件、对象还是指向调用者 -
函数变化
①函数不能有重名的参数
②函数必须声明在顶层,新版本的js会引入“块级作用域”,为与新版本接轨,不允许在非函数的代码块内声明函数
四、高阶函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出
函数也是一种数据类型,同样也可以作为参数,传递给另一个参数使用。最典型的就是作为回调函数
五、闭包
1、变量作用域
变量根据作用域的不同分为两种:全局变量和局部变量
(1)函数内部可以使用全局变量
(2)函数外部不可以使用局部变量
(3)当函数执行完毕,本作用域内的局部变量会销毁
2、什么是闭包
闭包(closure)指有权访问另一个函数作用域中变量的函数。-----JavaScript高级程序设计
闭包就是一个函数
简单理解就是,一个作用域可以访问另外一个函数内部的局部变量
3、闭包的主要作用:延伸了变量的作用范围
function fn(){
var num = 10;
return function(){
console.log(num);
}
}
var f=fn();
f();
4、案例:
(1)立即执行函数(小闭包)
(function(i){
lis[i].onclick = function(){
console.log(i);
}
})(i)
//立即执行函数里面的任何一个函数都可以使用它的变量i
六、递归
1、如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
2、浅拷贝和深拷贝
- 浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用
- 深拷贝拷贝多层,每一级别的数据都会拷贝
- Object.assign(target,sources) rs6新增方法可以浅拷贝
封装深拷贝函数:
function deepCopy(newobj,oldobj){
for(var k in oldobj){
//获取属性
var item = oldobj[k];
//判断属性属于哪种数据类型
if(item instanceof Array){
newobj[k]=[];
deepCopy(newobj[k],item);
}else if(item instanceof Object){
newobj[k]={
};
deepCopy(newobj[k],item);
}else{
newobj[k]=item;
}
}
}
第三部分、正则表达式
一、正则表达式概述
1、什么是正则表达式
正则表达式是用于匹配字符串中字符组合的模式。在js中正则表达式也是对象。
2、作用:
通常被用来检索、替换那些符合某个模式(规则)的文本。例如:
- 匹配:用户名表单只能输入英文字母、数字或下划线,昵称输入框可以输入中文
- 替换:用于过滤掉页面内容中的一些敏感词
- 提取:从字符串中获取我们想要的特定部分
3、特点
- 灵活性、逻辑性和功能性非常强
- 可以迅速地用极简单的方式达到字符串的复杂控制
二、正则表达式在javascript中的使用
1、创建正则表达式
在js中可以通过两种方式创建一个正则表达式
- 通过RegExp对象来创建
var 变量名 =new RegExp(/表达式/);
- 利用字面量创建
var 变量名 = /表达式/;
2、测试正则表达式 test
test()正则对象方法,用于检测字符串是否符合该规则,该对象会返回true或false,其参数时测试字符串
regexObj.test(str)
例如:
var rg=/123/;
console.log(rg.test(123));//返回true
console.log(rg.test('123'));//返回false
三、正则表达式中特殊的字符
1、正则表达式的组成
一个正则表达式可以由简单的字符构成,比如/abc/,也可以时简单和特殊字符的组合,比如/ab*/。其中特殊字符也被称为元字符,在正则表达式中具有特殊意义的专有符号,如^、\、$等
2、特殊字符
字符 | 含义 |
---|---|
^ | 边界符,匹配输入的开始。例如,/^A/ 并不会匹配 “an A” 中的 ‘A’,但是会匹配 “An E” 中的 ‘A’。 |
$ | 边界符,匹配输入的结束。例如,/t$/ 并不会匹配 “eater” 中的 ‘t’,但是会匹配 “eat” 中的 ‘t’。 如果^和$一起使用就是精确匹配,例如 /^abc$/ |
[abc] | 字符类,表示一系列字符(这里abc三个字符)可供选择,只要匹配其中一个就可以了。可以使用破折号(-)来指定一个字符范围。例如,[abcd] 和[a-d]是一样的。他们都匹配"brisket"中的‘b’,也都匹配“city”中的‘c’。 |
[^xyz] | 一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符。你可以使用破折号(-)来指定一个字符范围。任何普通字符在这里都是起作用的。例如,[^abc] 和 [^a-c] 是一样的。他们匹配"brisket"中的‘r’,也匹配“chop”中的‘h’。 |
* | 量词符, 匹配前一个表达式 0 次或多次。等价于 {0,}。例如,/bo*/ 会匹配 “A ghost boooooed” 中的 ‘booooo’ 和 “A bird warbled” 中的 ‘b’,但是在 “A goat grunted” 中不会匹配任何内容。 |
+ | 量词符, 匹配前面一个表达式 1 次或者多次。等价于 {1,}。例如,/a+/ 会匹配 “candy” 中的 ‘a’ 和 “caaaaaaandy” 中所有的 ‘a’,但是在 “cndy” 中不会匹配任何内容。 |
? | 量词符, 匹配前面一个表达式 0 次或者 1 次。等价于 {0,1}。例如,/e?le?/ 匹配 “angel” 中的 ‘el’、“angle” 中的 ‘le’ 以及 "oslo’ 中的 ‘l’。如果紧跟在任何量词 *、 +、? 或 {} 的后面,将会使量词变为非贪婪(匹配尽量少的字符),和缺省使用的贪婪模式(匹配尽可能多的字符)正好相反。例如,对 “123abc” 使用 /\d+/ 将会匹配 “123”,而使用 /\d+?/ 则只会匹配到 “1”。 |
{n} | 量词符, n 是一个正整数,匹配了前面一个字符刚好出现了 n 次。比如, /a{2}/ 不会匹配“candy”中的’a’,但是会匹配“caandy”中所有的 a,以及“caaandy”中的前两个’a’。 |
{n,} | 量词符,n是一个正整数,匹配前一个字符至少出现了n次。例如, /a{2,}/ 匹配 “aa”, “aaaa” 和 “aaaaa” 但是不匹配 “a”。 |
{n,m} | 量词符,n 和 m 都是整数。匹配前面的字符至少n次,最多m次。如果 n 或者 m 的值是0, 这个值被忽略。例如,/a{1, 3}/ 并不匹配“cndy”中的任意字符,匹配“candy”中的a,匹配“caandy”中的前两个a,也匹配“caaaaaaandy”中的前三个a。注意,当匹配”caaaaaaandy“时,匹配的值是“aaa”,即使原始的字符串中有更多的a。 |
\d | 预定义类,匹配一个数字。等价于[0-9]。例如, /\d/ 或者 /[0-9]/ 匹配"B2 is the suite number."中的’2’。 |
\D | 预定义类,匹配一个非数字字符。等价于[^0-9]。例如, /\D/ 或者 /[^0-9]/ 匹配"B2 is the suite number."中的’B’ 。 |
\w | 预定义类,匹配一个单字字符(字母、数字或者下划线)。等价于 [A-Za-z0-9_]。例如, /\w/ 匹配 “apple,” 中的 ‘a’,"$5.28,"中的 ‘5’ 和 “3D.” 中的 ‘3’。 |
\W | 预定义类,匹配一个非单字字符。等价于 [^A-Za-z0-9_]。例如, /\W/ 或者 /[^A-Za-z0-9_]/ 匹配 “50%.” 中的 ‘%’。 |
\s | 预定义类,匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。例如, /\s\w*/ 匹配"foo bar."中的’ bar’。 |
\S | 预定义类,匹配一个非空白字符。等价于 [^ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。例如,/\S\w*/ 匹配"foo bar."中的’foo’。 |
四、正则表达式中的替换
1、replace替换
replace()方法可以实现替换字符串操作,用来替换的参数可以时一个字符串或是一个正则表达式
stringObj.replace(regexp/substr,replacement)
第一个参数:被替换的字符串 或者 正则表达式
第二个参数:替换为的字符串
返回值是一个替换完毕的新字符串
2、正则表达式参数
/表达式/[switch]
switch(也称为修饰符)按照什么的模式来匹配,有三种值:
- g:全局匹配
- i:忽略大小写
- gi:全局匹配+忽略大小写
ES6:
p3 let变量声明及声明特性
1、变量声明
let a;
let b,c,d;
let e=100;
let f=342,g='fgsddgf',h=[];
2、声明特性
- 变量不能重复声明,下面代码就会报错
let star='df';
let star='ff';
- 块级作用域(只在{}里面有效)、全局、函数、evel
- 不存在变量提升
//下面就不会报错
console.log(song);
var song='wer';
//下面就会报错
console.log(song);
let song='wer';
p5 const常量
1、声明常量
const SCHOOL='sgg';
2、特点
- 一定要赋初值
- 一般常量使用大写命名(潜规则)
- 常量的值不能修改
- 块级作用域,块级外无效
- 对于数组和对象的元素修改,不算做对常量的修改,不会报错
const T=['UE','TX','NG'];
T.push('DF');
//只要T所指的地址没有改变,就不会报错
p6 变量解构的赋值
es6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值
1、数组的解构
const F4=['xsy','ln','zs','sxb'];
let [x,l,z,s]=F4;
//这样就相当于x='xsy',l='ln',z='zs',s='sxb'
2、对象的解构
p7 模板字符串
1、声明(反引号)
let str = `我也是字符串`;
2、内容中可以直接出现换行符
let str =`<ul>
<li>sdgsdg</li>
<li>sdgsdg</li>
<li>sdgsdg</li>
<li>sdgsdg</li>
</ul>
3、变量拼接
let lovest ='dfsd';
let out = `${
lovest}dgdgdgs`;
//out就为dfsddgdgdgs
p8对象简化写法
es6允许在大括号里面直接写入变量和函数,作为对象的属性和方法
p9~p10 箭头函数
es6中允许使用【箭头(=>)】定义函数
1、声明函数
//之前
var fn = function(a,b){
xxx
}
//es6
let fun=(a,b)=>{
xxx
}
2、调用函数
let result = fn(1,2);
3、箭头函数的特性
- 箭头函数的this是静态的,this始终指向函数声明时所在作用域下的this的值
function getName() {
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
}
//设置window对象name属性
window.name = 'gfd';
const school = {
name: "fssfd"
}
//直接调用
// getName();//输出gfd
// getName2();//输出gfd
getName.call(school);//输出fssfd
getName2.call(school);//还是输出gfd,所以箭头函数的this是静态的,始终指向声明时所在作用域下的那个this值
- 不能作为构造函数实例化对象
以下代码就会报错:
let Person = (name,age)=>{
this.name = name;
this.age = age;
}
let me=new Person('Xiao'