创建对象的模式对比
/**
* 工厂模式
* 工厂模式虽然解决了创建多个相似对象的问题
* 但却没有解决对象识别的问题
*(即怎样知道一个对象的类型)。
*/
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
let person1 = createPerson('1',21,'test');
/**
* 构造函数模式
* 构造函数模式解决了上面工厂模式的问题【instanceof可以判断变量属于哪种类型】
* 但是对于其中的function却是多次重复的,并不会重用,
* 这样会造成性能与空间的浪费
*/
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
let person2 = new Person('1',21,'test');
/**
* 原型模式
* 原型模式可以做到function重用
*/
function PersonX(name,age,job){
this.name = name;
this.age = age;
this.job = job;
}
PersonX.prototype.sayName = function(){
alert(this.name);
};
let person3 = new PersonX('1222',21,'test');
person3.sayName(); //"1222"
原型对象的理解
- 只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个 prototype属性,这个属性指向函数的原型对象。
- 在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。
- Example:Person.prototype.constructor 指向 Person。( function 也是一个对象 )。
- 使用
Object.getPrototypeOf()
可以方便地取得一个对象的原型。( ES5的特性 ) - 实例中的同名属性会覆盖对实例原型中的值的访问。当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性;换句话说,添加这
个属性只会阻止我们访问原型中的那个属性,但不会修改那个属性。 使用
hasOwnProperty()
方法可以检测一个属性是存在于实例中,还是存在于原型中。遍历一个对象的所有可枚举属性可用
Object.keys()
;- 遍历一个对象的所有实例属性可用
Object.getOwnPropertyNames()
; __Proto__
指向的是父类对象的原型,new(或者说是实例化)出来的对象没有prototype这个属性,但是function是有的。- 通过给原生对象,可以添加新的自定义方法。
- 通过 call 以及apply 的方法改变this的作用域,使子类能成功独立拥有父类的属性,而不会导致属性的共用。
// 测试代码
function Pers(age){ this.age = age; } let ttt = new Pers(21);
Object.keys(ttt);
// > ["age"]
Object.keys(ttt.__proto__);
// > []
Object.keys(Pers.prototype);
// > []
Pers.prototype.say = function(){ console.log(`hello, my age is ${this.age}`); }
ttt.say()
// > hello, my age is 21
Object.keys(ttt.__proto__);
// > ["say"]
Object.keys(Pers.prototype);
// > ["say"]
ttt.say = () => { console.log('come on baby~');}
ttt.say();
// > come on baby~
let uuu = new Pers(32);
uuu.say()
// > hello, my age is 32
// 组合继承的参考代码
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
SuperType.call(this, name); //继承属性
this.age = age;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
};
let instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
let instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27
JS间歇调用与延时调用
- 间歇调用:
let id_1 = setInterval(()=>console.log(1),1000);
间歇执行 - 延时调用:
let id_2 = setTimeout(()=>console.log(1),1000);
只延时执行一次 - 使用
clearInterval(id)
来清除定时执行的任务
事件
- 事件就是用户或浏览器自身执行的某种动作。
- 事件流描述的是从页面中接收事件的顺序。事件流有2种,一种是冒泡,一种是捕获。
- 冒泡:事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。
- 捕获:是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。
- 对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。