认识对象
生活角度:
万物皆对象,任何事和物都可以抽象为对象。
对象的特征:静态特征 和 动态特征
程序角度:
对象是一个集合,封装了属性 和 方法。
对象组织数据的方式:key → value
构造函数和对象
构造函数:创建对象的模板 比如系统提供的object
对象 构造函数所创建的实例
对象:
var obj = new object
var obj = {} // 常用对象方法
对象的操作
设置对象的属性或方法
对象.key =value
对象.[‘key’] = value
获取对象的属性或者方法
对象.key
对象[‘key’]
删除对象的属性或者方法
delete 对象.key
若对象中没有某个属性时,访问返回undefined
若对象中没有某个方法,调用时报错
监测对象的属性或者方法
对象.hasOwnProperty(name)
返回布尔值,true有 false没有
面向过程和面向对象
面向过程编程:关注的是 过程 ,过程中的每一个环节,都是亲力亲为
面向对象编程:关注的是 对象,让对象帮你做事,指挥对象左事情
面向对象编程
Object Oriented Programming,简称 OOP,是一种编程开发思想。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。
因此,面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的过程式编程(procedural programming),更适合多人合作的大型软件项目 。
面向对象的特征
封装 继承 多态(一种事物,多种表现形式)
什么是原型
原型也称原型对象,每个构造函数都有其对应的远行对象
获取原型对象的方式:
构造函数名.prototype
获取构造函数的原型对象:构造函数.protorype
原型对象的constructor属性可以获取对应的构造函数
console.log(yx.constructor);
注意:原型对象,也是对象,是对象必然可以存放key→value
原型的作用
原型对象中的键值可以被其对应的构造函数所创建的多有实例共享
一般情况下,原型对象中用来存放方法
方法 存放到原型中,所有的实例对象可以共享一个方法 。减少了内存的使用,提高程序性能。
原型链
在访问一个对象的属性,若该对象中没有,则会通过 __proto__属性找到其原型对象,从原型对象中查找。若原型对象中也没有,则再通过原型对象的__proto__属性找到原型对象的原型对象,依次类推就构成了原型链
为内置对象扩展方法
调用getSum方法
// 通过原型给数组对象扩展求和方法
Array.prototype.getSum = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i]; }
return sum;};
// 创建一个数组对象
var arr = [11,22,33];
// 调用getSum方法
var r = arr.getSum(); console.log(r); // 66
自调用函数的问题
1、如果存在多个自调用函数要用分号分割,否则语法错误
2、当自调用函数前面有函数声明时,不加分号,会报错
bind()可以改变函数内部this的指向,并返回一个新的函数
继承(extend())
生活中继承:子承父业
程序中继承:
子类型继承父类型的成员(把多个子类型的共同成员提取到父类型中)
继承的作用:减少代码量
Extend() 只会拷贝本身没有的
// 拷贝之前的obj1
console.log(obj1); // {name: "张三", age: 18}
// 把obj2中的属性或方法拷贝到obj1中
extend(obj2,obj1);
// 拷贝之后的obj1
console.log(obj1); // {name: "张三", age: 18, sex: "男", sayHi: f}
对象的继承
概念:继承是类型和类型之间的关系,对象的“继承”本质是对象的拷贝,把一个对象的所有成员拷贝给另一个对象。
注意:当设置了构造函数的prototype之后,别忘记设置constructor
问题:原型继承,无法设置构造函数的参数Student.prototype = new Person();只执行一次,无法给属性传值,可以方便的继承父类型的原型中的方法,但是属性的继承无意义
call方法
使用call可以改变函数中的this,并且可以立即调用函数 和bind不同的是,bind会返回一个新函数,而call是直接调用 。
语法:函数名或方法名.call(obj [,params]);
参数:
obj:函数名或方法名对应的函数体中的this的指向。
params, 函数名或方法名调用时需要传入的参数(一个或多个),可选。
组合继承:
就是让原型继承和借用继承一起使用
函数声明和函数表达式的区别
预解析时,函数声明创建的函数整体会提升到所在执行环境【作用域】的顶部。
预解析时,函数表达式创建的函数,仅仅提升变量名到所在执行环境【作用域】的顶部。
函数创建的第三种方式:
语法: var 变量名 = new function('形参1','形参2',....,'程序代码');
代码:
var fn = new function('a','b','alert(a + b);');console.log(fn instanceof function); // trueconsole.log(fn instanceof Object); // truefn(10,20); // 调用函数
this到底指向谁,是有程序在执行的过程中决定的
1、普通函数调用时,this指向window
2、构造函数调用时,this指向当前所创建的对象。
3、对象的方法调用时,this指向方法所属的对象。
4、事件绑定的方法,this 指向事件源
5、定时器函数,this指向window
改变函数的this指向
为什么要改变this ? 例如:我们经常在定时器外部备份 this 引用,然后在定时器函数内部使用外部 this 的引用。
改变this的方式:函数有三个方法可以改变内部的this:call、apply、bind。
call方法:
函数名.call(thisArg[,arg1][,arg2]......)
thisArg:在函数运行时指定的this值,若传null或者undefined.则函数内部this指向window
arg1...:指定的参数列表
apply方法
函数名.apply(thisArg,[argsArray])
thisArg,在 函数运行时指定的 this 值。若传null或undefined,则函数内部this指向window
argsArray,是一个数组,数组中存放函数调用时需要传入的实参
和call方法一样,唯一不同的时,函数或方法被借用时,apply以数组的方式存放实参
bind方法
var 变量 = 函数名.bind(thisArg)
thisArg:在 函数运行时指定的 this 值。若传null或undefined,则函数内部this指向window
和call使用方式一样,不一样的时,使用bind时,借用的函数不会被立即执行,而是返回一个新的函数,若要执行,需要自己调用。
函数的其他成员
arguments实参集合
caller函数的调用者
length形参的个数
name函数的名称
function fn(x, y, z) {
console.log(fn.length) // => 形参的个数
console.log(arguments) // 伪数组实参参数集合
console.log(arguments.callee === fn) // 函数本身
console.log(fn.caller) // 函数的调用者
console.log(fn.name) // => 函数的名字
}
function f() {
fn(10, 20, 30)
}
f()
函数作为函数的形参
当调用一个函数A是,需要向函数A内部传入一个程序时,可以选择将一个函数B当做实参传入给另一个函数A 的形参,并在另一个函数中执行
代码:
/*功能:吃完东西后做事情
参数:
name 食物名称 string
callback 注入一段代码 function */
function eat (foodName,callback) {
console.log('今天吃' + foodName);
// 判断是否传入了一个函数进来
if (callback instanceof function) {
callback(foodName);
}}
// 调用eat('西瓜', function(f) {
console.log(f + '吃起来口感真棒!五星好评!');
});
函数作为函数的返回值
在程序中,有时在调用一个函数时,需要返回一个新的函数来实现功能。比如之前学习的bind方法调用完后返回一个新的函数
如下:
// 如:创建一个函数用来创造一个检测指定数据类型的功能
/*
功能:生成一个能够比较指定类型的功能
参数:type 数据类型
*/
function getFn (type) {
return function (obj) {
return Object.prototype.toString.call(obj).indexOf(type) != -1;
};
}
var isArray = getFn('Array');
console.log(isArray([1,2,3])); // true
console.log(isArray(new Date())); // false
闭包
闭包(Closure):闭包是函数与声明函数的词法环境的组合
闭包就是能够读取/设置其他函数内部变量的函数
闭包就是将函数内部和函数外部连接起来的一座桥梁
闭包的用途
可以在函数外部读取函数内部成员
让函数内成员始终存活在内存中(延展变量的生命周期)
闭包简单来说就是一个函数 内部的变量,可以在外部作用域中操作。
递归
官方概念
程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量 。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
递归的三个阶段
1、递归前进段
2、递归边界条件、
3、递归返回段
如:一组有规律的年龄10 、12、14、16、18、20、22、24......,求第n个人的年龄
代码:function age(n){ if(n==1){ return 10; } else { return getAge(n-1) + 2; }}age(5);
递归的作用
减少代码量。
正则表达式
正则表达式:是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个 规则字符串 ,这个规则字符串 用来表达对字符串的一个过滤逻辑
正则表达式在其他语言中也广泛应用
正则表达式,就是定义好一个字符串规则,然后根据规则实现对象字符串的匹配、提取、替换等等
正则表达式的作用
1、给定的字符串是否符合正则表达式的过滤逻辑(匹配)
2、可以通过正则表达式,从字符串中获取我们想要的特定部分(提取)
3、强大的字符串替换能力(替换)
正则表达式的特点
1、灵活性、逻辑性和功能性非常的强
2、可以迅速的用极其简单的方式达到字符串的复杂控制
3、对于刚接触的人来说,比较不好懂
正则表达式由: 普通字符abc...z 123.... 和特殊字符(元字符、限定符、中括号) 组成
元字符
元字符就是,在正则表达式中具有特殊含义的字符
元字符 |
说明 |
\d |
匹配数字 |
\D |
匹配非数字 |
\w |
匹配字母或数字或下划线_ |
\W |
匹配非字母、数字、下划线_ |
\s |
匹配空白符(空格) |
\S |
匹配非空白符 |
. |
匹配任意除了换行符之外的单个字符 |
限定符
控制字符出现的次数。
限定符 |
说明 |
n* |
匹配任何包含零个或多个 n 的字符串。{0,} |
n+ |
匹配任何包含至少一个 n 的字符串。{1,} |
n? |
匹配任何包含零个或一个 n 的字符串。{0,1} |
n{x} |
匹配包含 x 个 n 的序列的字符串 |
n{x,} |
匹配包含至少 x 个 n 的序列的字符串。 |
n{x,y} |
匹配包含 至少x个 至多 y 个 n 的序列的字符串。 |
n$ |
匹配任何结尾为 n 的字符串 |
^n |
匹配任何开头为 n 的字符串 |
注意:^正则表达式$ 使用时,会对字符串整体校验,完全符合才能够匹配。否则,不匹配。
中括号
一个中括号就代表一个字符,中括号的目的就是控制了一个字符的范围。
中括号 |
说明 |
[abc] |
查找一个方括号之间的任何字符。 |
[^abc] |
查找一个任何不在方括号之间的字符。^在中括号中有取反的意思 |
[0-9] |
查找一个任何从 0 至 9 的数字。 |
[a-z] |
查找一个任何从小写 a 到小写 z 的字符。 |
[A-Z] |
查找一个任何从大写 A 到大写 Z 的字符。 |
[A-z] |
查找一个字母(包含大小写) |
[\u4e00-\u9fa5] |
查找一个汉字 |
或模式
特殊符号:正则1|正则2, 或者。 符合或两边其中一个就可以匹配。
如:google,baidu,bing; // 匹配三种其中一种字符串
正则:^google|baidu|bing$
分组模式
特殊符号:(正则);
组指的是一个小集体,分组就是将一个大集体可以分成几个小集体。
如:控制你的名字连续出现的次数,最少1次,最多3次
正则:^(bruce){1,3}$
贪婪模式和非贪婪模式
贪婪模式,尽可能多的匹配非贪婪模式,仅仅匹配一次
如:字符串 '<title>网页的标题</title>'
贪婪模式:<.+>
非贪婪模式:<.+?>
修饰符
→ g g,全称global,有 全局 的意思,表示全局匹配。 如: var reg = /hello/g;→ i i,全称ignore,有 忽视、忽略 的意思,表示匹配字母时,可以忽略字母的大小写。 如: var reg = /hello/i;
→ gi gi,全局匹配和忽略大小写一起使用。 如: var reg = /hello/gi;
正则转义符
(.)在正则中表示特殊符号。去除(.)的特殊意义,需要转义: \.
正则表达式对象
创建正则表达式对象
方式1:
语法:var 变量 = new RegExp(“规则”,”修饰符”);
代码:
var reg = new RegExp('\\d','g');
方式2:
语法:var 变量 = /正则表达式/;
代码:
var reg = /\d/g;
正则表达式在线测试 _ 菜鸟工具.html正则测试工具
验证邮箱
^\w{2,}@[0-9A-z]{2,}\.[A-z]{2,3}$
验证身份证号
^\d{17}[0-9Xx]$
验证手机号
^1[538][0-9]\d{8}$
检测匹配 和 提取
正则对象.test(字符串) ; 用于检测字符串是否匹配某个规则。返回true和false。
正则对象.exec(字符串) ;用于获取所匹配的子字符串。调用一次exec方法则返回单个匹配项并且以数组包装,调用第二次则从第二个匹配项返回,若没有则返回null;
字符串对象方法相关正则使用
字符串.match(正则对象); 重点 获取匹配正则的子字符串,返回一个数组。
字符串.replace(正则对象,替换后的内容); 重点 替换所匹配正则的子字符串。返回替换后的字符串。
字符串.split(正则对象); 按照正则规则拆分字符串,返回一个数组。
字符串.search(正则对象); 获取第一个匹配正则的子字符串的位置。
hind 借用的函数不会被立即执行,而是返回一个新的数组,若要执行,需要自己调用
apply 传入的是一个数组
call 传入的是一个一个的形参
闭包:
闭包是一个函数,被 包养 在函数内部的【变量】,可以被函数之外的程序访问到。
变量的生命周期:变量在内存中生命时候被释放;
局部变量的生命周期(一般情况下):局部变量会在函数调用完之后被释放。
局部变量的生命周期(特殊情况):产生闭包的时候,局部变量不会在函数调用完之后被释放。
全局变量的生命周期:在当前页面被关闭的时候,才回从内存中释放。
垃圾数据:没有用的数据
有用的数据:被变量一直引用的数据
null空的对象:若一个变量被赋值为null,那么这个变量就会变为没用的数据。
闭包的用途:①可以在函数外部读取函数内部的成员②让函数内成员始终存活在内存中(延展变量的使用范围)
到底有没有闭包看俩点:
①内部函数是否操作了外部函数的局部变量
②内部函数是否被返回