原型对象与原型链
构造对象的缺点
之前我们自定义对象时,以构造函数为模板;
对象的属性和方法,可以定义在构造函数内部。
prototype属性
JavaScript的每个对象都继承另一个对象,父级对象称为“原型”(prototype)对象。
只有nul1除外,它没有自己的原型对象。
而原型对象上的所有属性和方法,都能被派生对象共享
通过构造函数生成实例对象时,会自动为实例对象分配原型对象。
每一个构造函数都有一个prototype属性,这个属性就是实例对象的原型对象。
总结一下,原型对象的作用,就是定义所有实例对象共享的属性和方法。
这也是它被称为原型对象的原因,而实例对象可以视作从原型对象行生出来的子对象。
由于JavaScript的所有对象都有构造函数(只有nul1除外),而所有构造函数都有prototype属性(其实是所有函数都有prototype属性),所以所有对象都有自己的原型对象。
原型链
对象的属性和方法,有可能是定义在自身内,也有可能是定义在它的原型对象上。
由于原型本身也是对象,又有自己的原型,所以形成了一条原型链(prototype chain).
比如,a对象是b对象的原型,b对象是c对象的原型,以此类推。如果一层层地上湖,所有对象的原型最终都可以上湖到Object;那么,Object对象有没有它的原型呢?
有的,就是没有任何属性和方法的nul1对象,而nul1对象没有自己的原型。
对象.proto(两边都是两个下划线):获取对象的原型对象
原型链的作用是,读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。
如果直到景顶层的Object.prototype还是找不到,则返回undefined.
如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖(overriding)
需要注意的是,一级级向上,在原型链导找某个属性,对性能是有影响的。
如果寻找某个不存在的属性,将会遗历整个原型链。
注意:
在实际项目开发中,我们通常会使用第三方框架(一个类),但是当我们发现这个类中并不存在我们想要属性或方法时,不能直接修改源代码,
原形操作
constructor操作
设置获取原型对象
Object.getPrototypeOf()方法返回一个对象的原型对象。
这是获取原型对象的标准方法。
Object.setPrototypeOf()为现有对象设置原型对象
第一个是现有对象,第二个是要设置成为原型对象的对象这是设置原型对象的标准方法。
闭包
闭包的概念
JavaScript有两种作用域:全局作用域和函数作用域。函数内部可以直接读取全局变量。
函数f1可以读取全局变量n但是,在函数外部无法读取函数内部声明的变量。
垃圾回收与闭包
当我们在函数内部引入一个变量或函数时,系统都会开辟一块内存空间;
还会将这块内存的引用计数器进行初始化,初始化值为0如果外部有全局变量或程序引用了这块空间,则引用计数器会自动进行+1操作当函数执行完毕后,变量计数器重新归零,系统会运行垃圾回收机制,将函数运行产生的数据销毁;如计数器不是0,则不会清楚数据:
这个过程就称之为”JS的垃圾回收机制”:
但是,如果将以上代码,改为闭包形式:
运行代码发现,函数调用一次,其变量n变化一次;
因函数f1被调用时,返回的结果是f2函数体,也就是说,f2函数被当作值返回给f1的调用者,但是f2函数并没有在此时被调用执行,所以整个f1函数体,无法判断子函数f2会对其产生何种影响,无法判断 变量n是否会被使用:即使f1函数被调用结束,整个f1函数始终保留在内存中,不会被垃圾回收机制回收闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在;
注意,外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。
因此不能滥用闭包,否则会造成网页的性能问题。
call或apply方法
call
函数名称.call(obj,argl,arg2….argN);参数说明:obj:函数内this要指向的对象argl,arg2…argN:参数列表,参数与参数之间使用一个逗号隔开
apply
函数名称.apply(obj,[arg1,arg2…,argN])
参数说明:obj:this要指向的对象[arg1,arg2..argN]:参数列表,但是要求格式为数组
私有属性
在PHP类中我们使用private声明私有属性;
public:公有的
protected:受保护的
private:私有
但是在JS中,只有两种属性,公有属性与私有属性,在构造函数内部通过this声明的属性就是公有属性,通过var声明的就是私有属性。
对象的继承
在PHP中,我们可以使用extends关键字来实现类的继承;但是,JS中并没有类似extends的关键字提供继承的功能;而我们知道,所谓的继承,其实就是为子类提供父类中的方法和属相,是子类能够使用父类中的属性及方法;
- 通过原型实现继承;
- 通过call 或 apply方法继承;
定时器
JavaScript提供定时执行代码的功能,叫做定时器:
setTimeout()
用来指定某个函数或某段代码,在多少毫秒之后执行,
setinterval()
指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。
setTimeout(),setInterval()的第一个参数都是指定要执行的函数名称或者代码段,第二个参数时时间;
clearTimeout(),clearlnterval()
setTimeout和 setInterval函数,都返回一个表示计数器编号的整数值,将该整数传入clearTimeout和clearlnterval函数,就可以取消对应的定时器。