JavaScript创建对象方法总结精彩博文
javascript继承讲解精彩博文
于江水 继承讲解
JavaScript创建对象方式总结
- object构造函数、对象字面量
//object构造函数
// 优点:简单方便
// 缺点:批量创建对象很麻烦,不能使用instanceof来确定对象类型
var person = new Object();
person.name = "masike";
person.age=19;
person.job="student";
person.sayName=function(){
console.log(this.name);
};
//字面量
var person = {
name:"masike",
age:22,
job:"student",
sayName:function(){
console.log(this.name);
}
}```
- 工厂模式:简单的函数创建对象,为对象添加属性和方法,然后返回对象,这个模式后来被构造函数所取代。
```JavaScript
//工厂模式
// 优点:减少了代码量
// 缺点:未能解决对象识别问题
function createPerson(name,age,job){
var o=new Object();
o.name=name;
o.age=19;
o.job="student";
o.sayName=function(){
console.log(this.name);
}
return o;
}
var person1=createPerson("masike",19,"student");
var person2=createPerson("withershins",20,"worker");```
- 构造函数模式:自定义引用类型,像创建对象实例一样使用new操作符,缺点是每个成员无法得到复用,包括函数。
//构造函数模式
//优点:在工厂模式的基础下解决了对象识别问题
//缺点:每个实例的方法都是独立的,多数情况下同个对象的实例方法都是一样的
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.sayName=function(){
console.log(this.name);
}
}
var person1=new Person("masike",19,"student");
var person2=new Person("withershins",19,"worker");
//偏方
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.sayName=sayName;
}
function sayName(){
console.log(this.name);
}
var person1=new Person("masike",19,"student");
var person2=new Person("withershins",19,"worker");```
- 原型模式:使用prototype属性共享属性和方法。
//原型模式
//优点:公用原型减少了赘余
//缺点:在原型的改变会影响到所有的实例,于是实例没有了独立性
function Person(){
}
Person.prototype.name="masike";
Person.prototype.age=19;
Person.prototype.job="student";
Person.prototype.sayName=function(){
console.log(this.name);
}
var person1=new Person();
person1.sayName();
var person2=new Person();
person2.sayName();
console.log(person1.sayName==person2.sayName);```
- 组合使用构造函数模式和原型模式:构造函数定义实例属性,原型定义共享的属性和方法。
//组合使用构造函数和原型模式
//优点:结合了构造函数和原型模式的优点,并解决了缺点
//缺点:代码没有被很好地封装起来
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=student;
this.friends=["num1","num2"];
}
Person.prototype={
constructor:Person,
sayName:function(){
console.log(this.name);
}
}
var person1=new Person("masike",19,"student");
var person2=new Person("withershins",19,"worker");
person1.friends.push("vash");
console.log(person1.friends);
console.log(person2.friends);
console.log(person1.friends===person2.friends);
console.log(person1.sayName===person2.sayName);```
JavaScript继承方式总结
继承:超类构造函数中有属性有方法,超类原型中有属性有方法,子类想要继承超类的构造函数,超类原型中的部分属性和方法,于是便有了继承。
- 原型链继承:讲一个类型的实例赋值给另一个构造函数的原型,子类型就能够访问超类型所有的属性和方法
//原型链的继承
//缺点:对象实例共享所有的属性和方法,因此不适合单独使用。
function Parent(){
this.name="mike";
}
function Child(){
this.age=19;
}
Child.prototype=new Parent();//子类原型等于父类实例
var test =new Child();
console.log(test.age);
console.log(test.name);
function Brother(){
this.weight=60;
}
Brother.prototype=new Child();
var brother=new Brother();
console.log(brother.name);
console.log(brother.age);```
- 借用构造函数模式
//借用构造函数/类式继承call()/apply()
//可以传递参数,但是方法无法共享
function Parent(age){
this.name=['mike','jack','smith'];
this.age=age;
}
function Child(age){
Parent.call(this,age);
}
var test=new Child(21);
console.log(test.age);//21
console.log(test.name);//mike,jack,smith
test.name.push('bill');
console.log(test.name);//mike,jack,smith,bill
//call()和apply()用法区别
The difference is that apply lets you invoke the function with arguments as an array;
call requires the parameters be listed explicitly.
A useful mnemonic is "A for array and C for comma(逗号)."```
- 组合式继承:原型链和构造函数结合的方法,原型链继承共享的属性和方法,构造函数继承实例属性。
//组合式继承
//组合构造函数和原型链
//原型链继承原型属性和方法,构造函数实现实例属性的继承
function Parent(name){
this.name=name;
this.arr=['aaa','bbb','ccc'];
}
Parent.prototype.run=function(){
return this.name;
};
function Child(name,age){
Parent.call(this,age);//第二次调用
this.age=age;
}
Child.prototype=new Parent();//第一次调用```
- 原型式继承:不必预先定义构造函数的情况下实现继承,本质是执行给定对象的浅复制,而复制的副本还可以得到进一步的改造。
//借助于原型并基于已有的对象创建新对象,同时还不用创建自定义类型
function obj(o){
function F(){}
F.prototype=o;
return new F();
}
var box={
name:"masike",
arr:['baba','mama','didi']
};
var b1=obj(box);
console.log(b1.name);//masike
b1.name='mike';
console.log(b1,name);//mike
console.log(b1,arr);//baba,mama,didi
b1.arr.push("parents");
console.log(b1.arr);//baba,mama,didi,parents
var b2=obj(box);
console.log(b2.name);//masike
console.log(b2.arr);//baba,mama.didi,parents
- 寄生式继承:基于某个对象后某些信息创建一个对象,然后增强对象,最后返回对象。
function create(o){
var f=obj(o);
f.run=function(){
return this.arr;
}
return f;
}```
- 寄生组合式继承:集寄生式继承和组合是继承优点于一身,是实现基于类型继承的最有效的方式。解决组合继承模式由于多次调用父类构造函数而导致低效率问题。
//寄生组合式类型
//解决了父类构造函数两次调用问题
function obj(o){ //(原型式)
function F(){}
F.prototype=o;
return new F();
}
function create(parent,test){
var f=obj(parent.prototype);//创建对象
f.constructor=test;//增强对象
}
function Parent(name){
this.name=name;
this.arr=['brother','sister','parents'];
}
Parent.prototype.run=function(){
return this.name;
}
function Child(name,age){
Parent.call(this,name);
this.age=age;
}
Child.prototype = obj(Parent.prototype);//实现继承
var test=new Child("masike",19);
test.arr.push("withershins");
console.log(test.arr);
console.log(test.run());//只共享了方法
var test2=new Child("jack",22);
console.log(test2.arr);//引用问题解决```
未完待续......
>继承最推荐的解决方案:
if(!Object.create){//object.create()是ES5新增方法
Object.create= (function(){
function F(){} //创建中介函数(bridge)
return function(obj) {
if(arguments.length !== 1) {
throw new Error("仅支持一个参数");
}
F.prototype = obj; //原形绑定
return new F(); //返回实例
}
})()
//最终返回的结果,既是F的实例属性,享有F构造函数中的所有属性和方法(因为F构造函数为空,所以完全不用担心会有多余不想要的属性方法存在),[[prototype]]又指向F.prototype,返回的结果是一个对象!!!
}
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.walk = function() {//写到了prototype中,walk一定是想要共享的方法
console.log("走路....");
}
function Child(name, age, address) {
Person.call(this, name, age);//这里继承了person构造函数中想要传递的一些属性
this.address = address;
}
Child.prototype = Object.create(Person.prototype);//不要再使用new了!
Child.prototype.talk = function() {
console.log("说话ing.....")
}
//不用new的原因是因为你不想要Child继承Person构造函数中的所有属性和方法,而是想让他单独继承Person.prototype中共享的属性和方法。```