老生常谈javascript的面向对象思想

面向对象的三大基本特性

封装(把相关的信息(无论数据或方法)存储在对象中的能力)

继承(由另一个类(或多个类)得来类的属性方法的能力)

多态(一个对象在不同情况下的多种形态)

定义类或对象

第一种:基于Object对象

rush:xhtml;"> var person = new Object(); person.name = "Rose"; person.age = 18; person.getName = function () { return this.name; }; console.log(person.name);//Rose console.log(person.getName);//function () {return this.name;} console.log(person.getName());//Rose

缺点:不能创建多个对象。

第二种:基于字面量方式

rush:xhtml;"> var person = { name : "Rose",age : 18,getName : function () { return this.name; } }; console.log(person.name);//Rose console.log(person.getName);//function () {return this.name;} console.log(person.getName());//Rose

优点:比较清楚的查找对象包含的属性方法

缺点:不能创建多个对象。

第三种:工厂模式

方式一:

rush:xhtml;"> function createPerson(name,age) { var object = new Object(); object.name = name; object.age = age; object.getName = function () { return this.name; }; return object; } var person1 = createPerson("Rose",18); var person2 = createPerson("Jack",20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName === person2.getName);//false//重复生成函数,为每个对象都创建独立的函数版本

优点:可以创建多个对象;

缺点:重复生成函数getName(),为每个对象都创建独立的函数版本。

方式二:

rush:xhtml;"> function createPerson(name,age) { var object = new Object(); object.name = name; object.age = age; object.getName = getName; return object; } function getName() { return this.name; } var person1 = createPerson("Rose",20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName === person2.getName);//true//共享同一个函数

优点:可以创建多个对象;

缺点:从语义上讲,函数getName()不太像是Person对象的方法,辨识度不高。

第四种:构造函数方式

方式一:

rush:xhtml;"> function Person(name,age) { this.name = name; this.age = age; this.getName = function () { return this.name; } } var person1 = new Person("Rose",18); var person2 = new Person("Jack",20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName === person2.getName); //false//重复生成函数,为每个对象都创建独立的函数版本

优点:可以创建多个对象;

缺点:重复生成函数getName(),为每个对象都创建独立的函数版本。

方式二:

rush:xhtml;"> function Person(name,age) { this.name = name; this.age = age; this.getName = getName ; } function getName() { return this.name; } var person1 = new Person("Rose",20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName === person2.getName); //true//共享同一个函数

优点:可以创建多个对象;

缺点:从语义上讲,函数getName()不太像是Person对象的方法,辨识度不高。

第五种:原型方式

rush:xhtml;"> function Person() { } Person.prototype.name = 'Rose'; Person.prototype.age = 18; Person.prototype.getName = function () { return this.name; }; var person1 = new Person(); var person2 = new Person(); console.log(person1.name);//Rose console.log(person2.name);//Rose//共享同一个属性 console.log(person1.getName === person2.getName);//true//共享同一个函数

缺点:它省略了为构造函数传递初始化参数,这在一定程序带来不便;另外,最主要是当对象的属性是引用类型时,它的值是不变的,总是引用同一个外部对象,所有实例对该对象的操作都会影响其它实例:

rush:xhtml;"> function Person() { } Person.prototype.name = 'Rose'; Person.prototype.age = 18; Person.prototype.lessons = ["语文","数学"]; Person.prototype.getName = function () { return this.name; }; var person1 = new Person(); person1.lessons.push("英语"); var person2 = new Person(); console.log(person1.lessons);//["语文","数学","英语"] console.log(person2.lessons);//["语文","英语"]//person1修改影响了person2

第六种:构造函数+原型方式(推荐)

rush:xhtml;"> function Person(name,age) { this.name = name; this.age = age; } Person.prototype.getName = function () { return this.name; }; var person1 = new Person('Rose',18); var person2 = new Person('Jack',20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName === person2.getName);//true//共享原型中定义的方法

缺点:属性定义在构造函数内,方法定义在构造函数外,与面向对象的封装思想不符。

第七种:构造函数+动态原型方式(推荐)

方式一:

rush:xhtml;"> function Person(name,age) { this.name = name; this.age = age; if (typeof Person._getName === "undefined"){ Person.prototype.getName = function () { return this.name; }; Person._getName = true; } } var person1 = new Person('Rose',20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName === person2.getName);//true//共享原型中定义的方法

方式二:

rush:xhtml;"> function Person(name,age) { this.name = name; this.age = age; if (typeof this.getName !== "function"){ Person.prototype.getName = function () { return this.name; }; } } var person1 = new Person('Rose',20); console.log(person1.name);//Rose console.log(person2.name);//Jack console.log(person1.getName === person2.getName);//true//共享原型中定义的方法

对象属性的扩展及删除

Javascript的对象可以使用 '.' 操作符动态的扩展其属性,可以使用 'delete' 关键字或将属性的值设置为 'undefined' 来删除属性

rush:xhtml;"> function Person(name,age) { this.name = name; this.age = age; if (typeof Person._getName === "undefined"){ Person.prototype.getName = function () { return this.name; }; Person._getName = true; } } var person = new Person("Rose",18); person.job = 'Engineer';//添加属性 console.log(person.job);//Engineer delete person.job;//删除属性 console.log(person.job);//undefined//删除属性后值为undefined person.age = undefined;//删除属性 console.log(person.age);//undefined//删除属性后值为undefined

对象属性类型

数据属性

特性:

[configurable]:表示能否使用delete操作符删除从而重新定义,或能否修改为访问器属性认为true;

[enumberable]:表示是否可通过for-in循环返回属性认true;

[writable]:表示是否可修改属性的值。认true;

[value]:包含该属性的数据值。读取/写入都是该值。认为undefined;如上面实例对象person中定义了name属性,其值为'My name',对该值的修改都反正在这个位置

rush:xhtml;"> function Person(name,18); Object.defineProperty(person,"name",{configurable:false,writable:false}); person.name = "Jack"; console.log(person.name);//Rose//重新赋值无效 delete person.name; console.log(person.name);//Rose//删除无效

注意:

一旦将configurable设置为false,则无法再使用defineProperty将其修改为true(执行会报错:cannot redefine property : propertyName)

rush:xhtml;"> function Person(name,writable:false}); person.name = "Jack"; console.log(person.name);//Rose//重新赋值无效 delete person.name; console.log(person.name);//Rose//删除无效 Object.defineProperty(person,{configurable:true,writable:true});//Cannot redefine property: name

访问器属性

特性:

[configurable]:是否可通过delete操作符删除重新定义属性

[numberable]:是否可通过for-in循环查找该属性

[get]:读取属性调用认:undefined;

[set]:写入属性调用认:undefined;

访问器属性不能直接定义,必须使用defineproperty()或defineProperties来定义:如下

rush:xhtml;"> function Person(name,age) { this.name = name; this._age = age; if (typeof Person._getName === "undefined"){ Person.prototype.getName = function () { return this.name; }; Person._getName = true; } } var person = new Person("Rose","age",{ get:function () { return this._age; },set:function (age) { this._age = age; }}); person.age = 20; console.log(person.age);//20//person.age=20是使用set方法将20赋值给_age,person.age是使用get方法将_age的读取出来 console.log(person._age);//20

获取所有的属性属性的特性

使用Object.getownPropertyNames(object)方法可以获取所有的属性

使用Object.getownPropertyDescriptor(object,property)方法可以取得给定属性的特性;

rush:xhtml;"> function Person(name,set:function (age) { this._age = age; }}); console.log(Object.getownPropertyNames(person));//["name","_age","age"] console.log(Object.getownPropertyDescriptor(person,"age"));//{enumerable: false,configurable: false,get: function,set: function}

对于数据属性,可以取得:configurable,enumberable,writable和value;

对于访问器属性,可以取得:configurable,get和set;

继承机制实现

对象冒充

rush:xhtml;"> function Father(name) { this.name = name ; this.getName = function () { return this.name; } } function Son(name,age) { this._newMethod = Father; this._newMethod(name); delete this._newMethod;

this.age = age;
this.getAge = function () {
return this.age;
}
}
var father = new Father("Tom");
var son = new Son("Jack",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//继承父类getName()方法
console.log(son.getAge());//18

多继承(利用对象冒充可以实现多继承)

rush:xhtml;"> function FatherA(name) { this.name = name ; this.getName = function () { return this.name; } } function FatherB(job) { this.job = job; this.getJob = function () { return this.job; } } function Son(name,job,age) { this._newMethod = FatherA; this._newMethod(name); delete this._newMethod; this._newMethod = FatherB; this._newMethod(job); delete this._newMethod;

this.age = age;
this.getAge = function () {
return this.age;
}
}
var fatherA = new FatherA("Tom");
var fatherB = new FatherB("Engineer");
var son = new Son("Jack","Programmer",18);
console.log(fatherA.getName());//Tom
console.log(fatherB.getJob());//Engineer
console.log(son.getName());//Jack//继承父类FatherA的getName()方法
console.log(son.getJob());//Programmer//继承父类FatherB的getJob()方法
console.log(son.getAge());//18

call()方法

rush:xhtml;"> function Father(name) { this.name = name ; this.getName = function () { return this.name; } } function Son(name,age) { Father.call(this,name);

this.age = age;
this.getAge = function () {
return this.age;
}
}
var father = new Father("Tom");
var son = new Son("Jack",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//继承父类getName()方法
console.log(son.getAge());//18

多继承(利用call()方法实现多继承)

rush:xhtml;"> function FatherA(name) { this.name = name ; this.getName = function () { return this.name; } } function FatherB(job) { this.job = job; this.getJob = function () { return this.job; } } function Son(name,age) { FatherA.call(this,name); FatherB.call(this,job);

this.age = age;
this.getAge = function () {
return this.age;
}
}
var fatherA = new FatherA("Tom");
var fatherB = new FatherB("Engineer");
var son = new Son("Jack",18);
console.log(fatherA.getName());//Tom
console.log(fatherB.getJob());//Engineer
console.log(son.getName());//Jack//继承父类FatherA的getName()方法
console.log(son.getJob());//Programmer//继承父类FatherB的getJob()方法
console.log(son.getAge());//18

apply()方法

rush:xhtml;"> function Father(name) { this.name = name ; this.getName = function () { return this.name; } } function Son(name,age) { Father.apply(this,new Array(name));

this.age = age;
this.getAge = function () {
return this.age;
}
}
var father = new Father("Tom");
var son = new Son("Jack",18);
console.log(father.getName());//Tom
console.log(son.getName());//Jack//继承父类getName()方法
console.log(son.getAge());//18

多继承(利用apply()方法实现多继承)

rush:xhtml;"> function FatherA(name) { this.name = name ; this.getName = function () { return this.name; } } function FatherB(job) { this.job = job; this.getJob = function () { return this.job; } } function Son(name,age) { FatherA.apply(this,new Array(name)); FatherB.apply(this,new Array(job));

this.age = age;
this.getAge = function () {
return this.age;
}
}
var fatherA = new FatherA("Tom");
var fatherB = new FatherB("Engineer");
var son = new Son("Jack",18);
console.log(fatherA.getName());//Tom
console.log(fatherB.getJob());//Engineer
console.log(son.getName());//Jack//继承父类FatherA的getName()方法
console.log(son.getJob());//Programmer//继承父类FatherB的getJob()方法
console.log(son.getAge());//18

原型链方法

rush:xhtml;"> function Father() { } Father.prototype.name = "Tom"; Father.prototype.getName = function () { return this.name; }; function Son() { } Son.prototype = new Father(); Son.prototype.age = 18; Son.prototype.getAge = function () { return this.age; }; var father = new Father(); var son = new Son(); console.log(father.getName());//Tom console.log(son.getName());//Tom//继承父类FatherA的getName()方法 console.log(son.getAge());//18

混合方式(call()+原型链)

rush:xhtml;"> function Father(name) { this.name = name; } Father.prototype.getName = function () { return this.name; }; function Son(name,name); this.age = age; } Son.prototype = new Father(); Son.prototype.getAge = function () { return this.age; }; var father = new Father("Tom"); var son = new Son("Jack",18); console.log(father.getName());//Tom console.log(son.getName());//Jack//继承父类Father的getName()方法 console.log(son.getAge());//18

多态机制实现

rush:xhtml;"> function Person(name) { this.name = name; if (typeof this.getName !== "function"){ Person.prototype.getName = function () { return this.name; } } if (typeof this.toEat !== "function"){ Person.prototype.toEat = function (animal) { console.log( this.getName() + "说去吃饭:"); animal.eat(); } } } function Animal(name) { this.name = name; if (typeof this.getName !== "function"){ Animal.prototype.getName = function () { return this.name; } } } function Cat(name) { Animal.call(this,name); if (typeof this.eat !== "function"){ Cat.prototype.eat = function () { console.log(this.getName() + "吃鱼"); } } } Cat.prototype = new Animal(); function Dog(name) { Animal.call(this,name); if (typeof this.eat !== "function"){ Dog.prototype.eat = function () { console.log(this.getName() + "啃骨头"); } } } Dog.prototype = new Animal();

var person = new Person("Tom");
person.toEat(new Cat("cat"));//Tom说去吃饭:cat吃鱼
person.toEat(new Dog("dog"));//Tom说去吃饭:dog啃骨头

以上这篇老生常谈javascript的面向对象思想就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持编程之家。

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...