一.面向对象编程
1.创建对象方法
1.1简单方式
var person = new Object();
person.name = "Bob";
person.age = 18;
person.sayName = function () {
console.log(this.name);
};
person.sayName();
1.2对象字面量化简
var person1 = {
name : "Bob",
age : 18,
sayName : function () {
console.log(this.name);
}
};
var person2 = {
name : "Mike",
age : 20,
sayName : function () {
console.log(this.name);
}
};
person1.sayName();
person2.sayName();
1.3工厂函数
function createPerson(name,age) {
// 添加一个新对象
var person = new Object();
person.name = name;
person.age = age;
person.sayName = function () {
console.log(this.name);
};
// 必须有返回值
return person;
}
// 生成真正的对象
var person1 = createPerson("John",19);
var person2 = createPerson("Mike",18);
person1.sayName();
1.4自定义构造函数
function Person(name,age) {
//1.创建一个新对象
//var instance = new Object();
2.将函数内部的 this 指向了这个新对象
//this = instance;
// 3.执行构造函数内部的代码
this.name = name;
this.age = age;
this.sayName = function() {
conosole.log(this.name);
};
//4.将新对象作为返回值
return instance ;
}
Person.version = "1.0"//定义静态成员
var person1 = new Person("zs",16);
var person2 = new Person("ls",15);
person1.sayName();
new 关键字的用途
1.创建一个新对象
2.将函数内部的 this 指向了这个新对象
3.执行构造函数内部的代码
4.将新对象作为返回值
- 用instanceof判断一个对象的具体对象类型
1.5总结:如果对象不需要生成实例可以直接使用字面量方式封装,不需要使用构造函数封装
2.成员
2.1 静态成员
添加给构造函数自身的成员,只能用构造函数调用,不能使用生成的实例对象调用
//调用自定义构造函数代码
console.log(Person.name)//使用构造函数调用实例成员会出错
console.log(Person.version)//可以正常调用静态成员
2.2实例成员
构造函数内部添加给this的成员,属于实例对象的成员,在创建对象后必须由对象调用
//调用自定义构造函数代码
conosle.log(person1.name)//调用实例成员
conosle.log(person1.version)//undefined
3.构造函数存在的问题
- 内存浪费
解决方案:利用原型对象(prototype)
任何函数都有protype属性,属性值时一个对象。内部可以添加属性和方法,原型对象所有的属性和方法都会被构造的实例对象拥有Person.prototype.type = "human"
console.log(Person.prototype);//指向原型对象
conosle.log(person1.__proto__);//指向原型对象
console.log(Person.prototype.constructor);//指
向构造函数
console.log(person1.constructor)//指向构造函数
所有的对象都有一个 -proto- 的属性,是一个指针,指向的就是生成实例对象的 构造函数的原型对象
4.原型链
任何一个对象都有 proto 属性,指向的就是该对象的 构造函数的原型对象。 当调用一个对象的方法时,如果对象没有该方法就沿原型链向上查找直到null。
4.1实例对象读写原型对象成员
- 通过实例对象添加新成员,会直接添加给自己,会屏蔽掉对原型对象的访问
person1.sex = "male";
person1.sayAge = function () {
console.log(this.age);
};
- 如果通过实例对象更改简单类型原型对象的属性和方法,会直接添加给自己,会屏蔽掉对原型对象的访问
person1.type = "person";
person1.sayName = function () {
console.log(this.name);
}
console.dir(person1);
- 通过实例对象更改原型对象中复杂类型数据中的内容.如果自身有该成员就直接修改,如果没有还是会进行原型链的查找
person1.address.city = "上海";
- 简化书写
为了避免重复书写原型对象和实例对象,可将包含所有属性和方法的对象字面量来重写整个原型对象。但是会丢失constructor成员,需要手动将constructor指向正确的构造函数。
私有成员(一般为非函数成员)设置在构造函数中。
公有成员(函数成员)放置到原型对象中。
重置了protype需要修正constrctor指向。
4.2this关键字
总结:不同函数内部this指向
全局执行上下文中的this指向的是windwo对象;普通函数中this指向window对象;构造函数中this指向生成的实例对象;对象的方法中的this指向对象本身;事件函数中的this指向事件源。
执行上下文分为:全局执行上下文、函数执行上下文、eval执行上下文,所以对应的this也由三种。
通过构造函数方式定义函数
var fun = new Function('var a = "1"; console.log(1)');
fun();
4.3修改this指向的方法
4.3.1 call方法
功能:1.指定函数的this 2.执行函数并传参
参数:1.指定让this指向的对象 第二个及以后参数是函数参数的列表
返回值:函数自己的返回值
fun.call(o,1,2);
call的应用:处理对象时借用其他对象的方法
var o ={
0:10;
1:20
lenght:2
}
//利用数组中的push方法,指定内部的this为对象o,就可以处理类数组对象
Array.prototype.push.call(o,50);
console.log(o);
4.3.2 apply方法
功能:1.指定函数的this 2.执行函数并传参
参数:1.指定让this指向的对象 第二个参数是函数参数的列表
返回值:函数自己的返回值
fun.apply(o,[4,5]);
apply方法的应用:将数组作为参数传入
var arr = [1,2,3,6,8];
//利用apply方法将数组传给了max的第二个参数
Math.max.apply(null,arr);//null指不改变原来的this指向
4.3.3 bind方法
功能:指定函数的this &emsp 2.不能执行函数但可传参
参数:1.传入让this指向的对象,第二个及以后是函数参数的列表
返回值:返回一个新的指定了this的函数
var fn = fun.blid(o,2,3); //传参不执行
fn(5,9); //执行函数时,将绑定函数和执行函数的参数都作为实参传入。将参数拆开传入
bind方法的应用;定时器或事件函数
var o = {
name: "zs";
age : 18;
s: function () {
setInterval (function () {
console.log(this.age);
},500);
}
o.s();//结果是undefinde
//更改定时器中的this
var o = {
name: "zs";
age : 18;
s: function () {
setInterval (function () {
console.log(this.age);
}.bind(this),500);
}
o.s();// 结果输出18
注:通过自调用函数,进行封装。通过window暴露 Food对象
window.Food = Food (function(){})();
4.4 this中的缺陷
4.4.1 嵌套函数中的this不会从外层函数中继承
var myObj = {
name : "zs",
showThis: function(){
console.log(this)
function bar(){console.log(this)}
bar()
}
}
myObj.showThis()
showThis方法里的this指向的是myObj对象,但是bar函数中的this指向的是window对象。
解决方法:方法一:在showThis函数中声明一个that变量保存this (将this体系转换为作用域的体系)
方法二:使用箭头函数
var myObj = {
name : "zs",
showThis: function(){
console.log(this)
var bar = () =>{
this.name = "ls"
console.log(this)}
bar()
}
}
myObj.showThis() //{name: "zs", showThis: ƒ}
console.log(myObj.name) //{name: "ls", showThis: ƒ}
console.log(window.name)//ls
4.4.2 this指向(在调用时确定具体指向)
普通函数:this默认指向window
构造函数:内部this指向将来创建的实例对象
对象中的方法:内部this默认指向调用的对象自己
事件函数:this指向触发事件的事件源 app.onclick = function() {console.log(this)} this指向的是app
定时器和延时器函数:内部this指向window
二、继承
1.call方法 :执行函数的方法
1.在调用函数时可以更改函数的内部指向
2.调用函数执行内部代码
参数:第一个参数指定this指向,第二个参数是传入的实参
//借用构造函数继承
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function (){ //方法也需要继承
console.log("nihao");
}
function Student(name,age,score){
Person.call(this,name,age);
this.score = score;
}
//继承方法的方法1:对象拷贝继承
for(var k in Person .prototype){
//保留constructor不需要继承
if(k==="constructor"){continue;}
Student.prototype[k] = Person.prototype[k];
}
//方法2:原型继承
Student.prototype = new Person();
Student.prototype.constructor = Student ;//保证constructor指向正确
var s1 = new Student("zs","13","75");
s1.sayHi();
2.组合继承 :属性在构造函数内部继承,方法通过原型继承
3.函数中的其他成员
arguments属性是传入所有实参组成的一个类数组对象
argument.callee函数本身,arguments的一个属性
caller 函数的调用者,函数在哪个作用域调用,caller就是谁,全局为null
length指的是形参的个数
name指的是函数的名字
高阶函数:作为参数或返回值的函数
三.正则表达式
在JS中的正则表达式是一种索引类型,也是对象
\s 空白 \d数字
3.1创建正则表达式
1.var reg = /abc/; 2.var reg = newRegExp("abc");
正则表达式字面量在脚本加载后编译,性能更好
3.2字符串方法
- split() 分割字符串为数组
var str = "aa bbb ccd e";
//var arr = str.split(" "); //以空格作为分隔符
console.log(arr); //空字符串也会被分割到数组中
//使用正则表达式可以进行模糊匹配分割
var arr1 = str.split(/\s+/); //以多个空白作为分隔符
console.log(arr); //空字符串会被自动过滤
- search方法:寻找匹配字符串在父字符串中的位置
var str = "abaaacsaaaa";
console.log(str.search("cd")); //输出结果为5
console.log(str.search(/cd/);//输出结果为5
- match()方法:在父字符串中寻找匹配字符串结果输入到数组中
var str = "abaafbfefefebdsljk";
var arr = str.match(/b+/);
console.log(arr); //在匹配到第一个字符串就结束
var arr1 =str.match(/b+/g);//如果有全局修饰符g,会找所有匹配的字符串后结束
console.log(arr1);
- replace方法:替换父字符串中匹配的字符串,返回新的替换后的字符串,原始字符串不受影响
var str = "www.hello.com";
var str1 = str.replace(/hello/,"byebye");
console.log(str); //www.hello.com
console.log(str1); //www.byebye.com
3.3正则表达式方法
- exec 查找匹配的字符串,输出到数组中。不论有没有全局修饰符,都会只找到第一个后停止
var str = "aaaavvvccc";
var reg = /av/;
var arr = reg.exec(str);
console.log(arr); //Array(1)对象
- test方法:匹配字符串是否符合正则表达式(返回值为Boolean类型)
var reg =/abc/;
console.log(reg.test("5661abcdsf")); //true
3.4正则表达式的组成
- 特殊字符
\t 制表符
\n 回车符
\f 换页符
\b 空格
var str = `sdfsfsf
eoffjf`
console.log(/\n/.test(str));
2.字符集:使用[ ]表示的可能字符的集合,吉和内部可以排列多个匹配字符串的可能性,整个字符集需要匹配的是字符串中的一个字符
2.1 简单类:多个可能匹配的字符连续书写在一起,只要其中一个匹配成功即可
var reg = /[abc]/;
console..log(reg.test("efefabc"));//true
2.2 范围类:匹配过多简化操作[a-z]、[0-9]、[A-Z]
2.3 反向类:去反,表示不能匹配括号里的字符.[^a] [^a-q]
2.4 组合类:单一类或者简单类不可匹配所有结果,可以将多个写法连在一起书写[0-9a-z]、0-Z
3.5修饰符
- g 全局查找
var str = "adafdsdfdasfaaa";
var reg = /b+/g;
console.log(str.match(reg));
- i修饰符:字母大小写不敏感 ,a可以匹配A
var str = "adafdsdfdasfBBBaaa";
var reg = /b+/A;
console.log(str.match(reg));
- 边界
^开头 不可跟在中括号后面
/^hello/
结 尾 : 前 面 的 正 则 内 容 匹 配 的 结 果 必 须 出 现 在 字 符 串 结 尾 / a a a 结尾:前面的正则内容匹配的结果必须出现在字符串结尾 /aaa 结尾:前面的正则内容匹配的结果必须出现在字符串结尾/aaa/
3.6 预定义类
. [^\n\r] 除了换行和回车的任意字符
\d [0-9] 数字字符
\D [^0-9] 非数字字符
\s [\t\n\x0B\f\r] 空白字符
\S [^\t\n\x0B\f\r] 非空白字符
\w [a-zA-Z_0-9] 单词字符(所有的字母数字下划线)
\W [^a-zA-Z_0-9] 非单词字符
3.7量词
{n} 硬性量词 对应前面的内容必须在字符串中出现n次连续
{n,m} 弹性量词 对应前面的内容必须在字符串中出现 n~m 次连续
{n,} 弹性量词 对应前面的内容必须在字符串中至少出现n次连续
? 弹性量词 表示前面的内容出现0次或者1次
‘*’ 弹性量词 表示前面的内容出现任意次
‘+’ 弹性量词 表示前面的内容出现至少1次
var reg = /^\d{5}/;
var reg = /^\d{5,7}/;
- 分组
/^(bye){2}/
或操作符|
/a|bcd/
//在正则中过两个规则只能选自一种,不能包含其他的开头结尾,需要去将运算放在分组里
var reg = /^(ad|cd)$/;
分组的反向:使用匹配到的字符作为条件匹配其他字符
- 内部引用 (用\次数表示)
console.log(/^([a-z]{3})\2$/.test("byebyebye"));//true 把满足条件的前三个字母作为条件来匹配剩余字符
console.log(/^([a-z]{3})\2$/.test("byebyebie"));//false
- 外部引用 (用$编号表示)
var str = 123*456.replace(/^(\d{3})\*(\d{3})$/,"$2*$1");
- 中文字符 [\u4e00 - \u9fa5]