每天一篇javascript学习小结面向对象编程

1、面向对象的工厂方法

rush:xhtml;"> 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; }

var person1 = createPerson("Nicholas",29,"Software Engineer");
var person2 = createPerson("Greg",27,"Doctor");

person1.sayName(); //"Nicholas"
person2.sayName(); //"Greg"

工厂模型的方法的缺点是会产生大量重复代码

2、构造函数模式创建对象

rush:js;"> function Person(name,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; }

var person1 = new Person("Nicholas","Software Engineer");
var person2 = new Person("Greg","Doctor");

person1.sayName(); //"Nicholas"
person2.sayName(); //"Greg"

alert(person1 instanceof Object); //true
alert(person1 instanceof Person); //true
alert(person2 instanceof Object); //true
alert(person2 instanceof Person); //true

alert(person1.constructor == Person); //true
alert(person2.constructor == Person); //true

alert(person1.sayName == person2.sayName); //false

使用new关键字创建对象会经历以下四个过程

  • 1、创建一个新对象
  • 2、将构造函数的作用域赋给一个新对象(因此this就指向了这个新对象)
  • 3、执行构造函数方法(为这个新对象赋值)
  • 4、返回新对象

3、将构造函数函数

rush:js;"> function Person(name,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; }

var person = new Person("Nicholas","Software Engineer");
person.sayName(); //"Nicholas"

Person("Greg","Doctor"); //adds to window
window.sayName(); //"Greg"

var o = new Object();
Person.call(o,"Kristen",25,"Nurse");
o.sayName(); //"Kristen"

构造函数当做函数使用就和普通的函数没有任何不同,它属于window对象下面添加方法而已。由于构造函数创建的对象实际上是创建一个新对象,因此在本质上两者还是不一样的,还是分离的,他们的方法还是不一样的!

4、将共有的方法方法全局解决不一致的问题

rush:js;"> function Person(name,job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; }

function sayName(){
alert(this.name);
}

var person1 = new Person("Nicholas","Doctor");

person1.sayName(); //"Nicholas"
person2.sayName(); //"Greg"

alert(person1 instanceof Object); //true
alert(person1 instanceof Person); //true
alert(person2 instanceof Object); //true
alert(person2 instanceof Person); //true

alert(person1.constructor == Person); //true
alert(person2.constructor == Person); //true

alert(person1.sayName == person2.sayName); //true

虽然上面的方法解决了一致的问题,但是定义的全局的方法本身属于window,那么局部和全局就没有分开!所以这个方法使用的并不多见!也不建议使用。

5、原型模式

我们创建的任何的一个函数都有一个原型对象,这个属性一个指针,它指向一个对象,而这个对象的作用是可以有特定的类型的所有的实例共享的方法

rush:js;"> function Person(){ }

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};

var person1 = new Person();
person1.sayName(); //"Nicholas"

var person2 = new Person();
person2.sayName(); //"Nicholas"

alert(person1.sayName == person2.sayName); //true

alert(Person.prototype.isPrototypeOf(person1)); //true
alert(Person.prototype.isPrototypeOf(person2)); //true

//only works if Object.getPrototypeOf() is available
if (Object.getPrototypeOf){
alert(Object.getPrototypeOf(person1) == Person.prototype); //true
alert(Object.getPrototypeOf(person1).name); //"Nicholas"
}

无论什么时候只要是创建了一个函数,就会创建一个原型属性,这个属性指向函数的原型对象。在认的情况下,原型对象都会包含一个constructor(构造函数属性),这个属性包含一个指向prototype属性所在函数的指针!

属性读取的顺序

每当代码读取某个对象的属性时候,都会执行一次搜索,目标是具有给定名字的属性搜索从对象的实例本身开始查找,如有则返回,没有则继续搜索该对象的原型链,直至搜索到原型链的最外层!

rush:js;"> function Person(){ }

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};

var person1 = new Person();
var person2 = new Person();

person1.name = "Greg";
alert(person1.name); //"Greg" 来自实例
alert(person2.name); //"Nicholas" 来自原型

如果删除了这个元素的实例属性

rush:js;"> function Person(){ }

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};

var person1 = new Person();
var person2 = new Person();

person1.name = "Greg";
alert(person1.name); //"Greg" ?from instance
alert(person2.name); //"Nicholas" ?from prototype

delete person1.name;
alert(person1.name); //"Nicholas" - from the prototype

6、hasOwnProperty方法

这个方法可以检测一个属性是否存在于实例中,还是存在于原型中!hasOwnProperty是从Object继承来的,只要给定属性存在于对象实例中,才会返回true.

rush:vb;"> function Person(){ }
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
  alert(this.name);
};

var person1 = new Person();
var person2 = new Person();

alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true

person1.name = "Greg";
alert(person1.name);  //"Greg" ?from instance
alert(person1.hasOwnProperty("name")); //true
alert("name" in person1); //true

alert(person2.name);  //"Nicholas" ?from prototype
alert(person2.hasOwnProperty("name")); //false
alert("name" in person2); //true

delete person1.name;
alert(person1.name);  //"Nicholas" - from the prototype
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true

7、Object.keys() 可枚举属性方法

这个方法接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组

rush:js;"> function Person(){ }
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
  alert(this.name);
};

var keys = Object.keys(Person.prototype);
alert(keys);  //"name,job,sayName"

如果想得到所有实例的属性,无论它是否可以枚举都可以使用这个方法获取
function Person(){
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
  alert(this.name);
};

var keys = Object.g<a href="https://www.jb51.cc/tag/eto/" target="_blank" class="keywords">eto</a>wnPropertyNames(Person.prototype);
alert(keys);  //"constructor,name,sayName"

方法高版本浏览器才支持

8、简单的原型写法

rush:js;"> function Person(){ }
Person.prototype = {
  name : "Nicholas",age : 29,job: "Software Engineer",sayName : function () {
    alert(this.name);
  }
};

var friend = new Person();

alert(friend instanceof Object); //true
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
alert(friend.constructor == Object); //true

重写了原型就等于将认的原型方法覆盖,那么同样的构造方法也会被重写,重写的构造方法指向了Object对象!而不是原来的对象Person

如果还是想指向之前的构造方法,可以显示的指定

rush:js;"> function Person(){ }
Person.prototype = {
  constructor : Person,name : "Nicholas",sayName : function () {
    alert(this.name);
  }
};

var friend = new Person();

alert(friend instanceof Object); //true
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //true
alert(friend.constructor == Object); //false

9、原型方法的动态添加

rush:js;"> function Person(){ }
Person.prototype = {
  constructor: Person,job : "Software Engineer",sayName : function () {
    alert(this.name);
  }
};

var friend = new Person();

Person.prototype.sayHi = function(){
  alert("hi");
};

friend.sayHi();  //"hi" ?works!

10、原生对象的原型方法

rush:js;"> alert(typeof Array.prototype.sort); //"function" alert(typeof String.prototype.substring); //"function"
String.prototype.startsWith = function (text) {//<a href="https://www.jb51.cc/tag/xiugai/" target="_blank" class="keywords">修改</a>原生对象的原型<a href="https://www.jb51.cc/tag/fangfa/" target="_blank" class="keywords">方法</a>
  return this.indexOf(text) == 0;
};

var msg = "<a href="https://www.jb51.cc/tag/HelloWorld/" target="_blank" class="keywords">Hello World!</a>";
alert(msg.startsWith("Hello"));  //true

11、组合使用构造函数和原型模式创建对象

rush:js;"> //构造函数模式 function Person(name,job){ this.name = name; this.age = age; this.job = job; this.friends = ["Shelby","Court"]; } //原型模式 Person.prototype = { constructor: Person,sayName : function () { alert(this.name); } };
var person1 = new Person("Nicholas","Software Engineer");
var person2 = new Person("Greg","Doctor");

person1.friends.push("Van");

alert(person1.friends);  //"Shelby,Court,Van"
alert(person2.friends);  //"Shelby,Court"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true

12、动态原型模式

rush:js;"> function Person(name,job){
  //properties
  this.name = name;
  this.age = age;
  this.job = job;

  //methods
  if (typeof this.sayName != "function"){

    Person.prototype.sayName = function(){
      alert(this.name);
    };

  }
}

var friend = new Person("Nicholas","Software Engineer");
friend.sayName();

13、寄生构造函数模式

rush:js;"> function Person(name,job){ var o = new Object();//依赖全局对象初始化一个对象,然后再返回这个对象 o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; }

var friend = new Person("Nicholas","Software Engineer");
friend.sayName(); //"Nicholas"

function SpecialArray(){

//create the array
var values = new Array();

//add the values
values.push.apply(values,arguments);

//assign the method
values.toPipedString = function(){
return this.join("|");
};

//return it
return values;
}

var colors = new SpecialArray("red","blue","green");
alert(colors.toPipedString()); //"red|blue|green"

alert(colors instanceof SpecialArray);

上诉方法有一点说明下,由于它是依赖外层对象来创建一个新对象,因此不能依赖 instanceof方法来确定属性方法的来源!它实际上和构造函数的没有关系!

14、稳妥构造函数模式

rush:js;"> function Person(name,job){ var o = new Object(); o.sayName = function(){ alert(name); }; return o; }
var friend = Person("Nicholas","Software Engineer");
friend.sayName(); //"Nicholas"

方法不依赖任何new this 关键符!如果要访问对象的方法属性,只能通过对象已经定义好的方法获取

15、继承

javascript实现继承是通过原型链来实现的

rush:js;"> function SuperType(){ this.property = true;//定义一个属性 }
SuperType.prototype.getSuperValue = function(){//定义的原型<a href="https://www.jb51.cc/tag/fangfa/" target="_blank" class="keywords">方法</a>
  return this.property;
};

function SubType(){
  this.subproperty = false;
}

//inherit from SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function (){
  return this.subproperty;
};

var instance = new SubType();
alert(instance.getSuperValue());  //true

alert(instance instanceof Object);   //true
alert(instance instanceof SuperType);  //true
alert(instance instanceof SubType);   //true

alert(Object.prototype.isPrototypeOf(instance));  //true
alert(SuperType.prototype.isPrototypeOf(instance)); //true
alert(SubType.prototype.isPrototypeOf(instance));  //true

SubType继承SuperType的方法属性,因此当instance可以直接调用SuperType的方法
function SuperType(){
this.property = true;
}

SuperType.prototype.getSuperValue = function(){
  return this.property;
};

function SubType(){
  this.subproperty = false;
}

//inherit from SuperType
SubType.prototype = new SuperType();

//new method
SubType.prototype.getSubValue = function (){
  return this.subproperty;
};

//override existing method
SubType.prototype.getSuperValue = function (){
  return false;
};

var instance = new SubType();
alert(instance.getSuperValue());  //false

上面的例子说明,重写的原型会覆盖之前继承的原型,最后返回的往往不是预期的效果

rush:js;"> function SuperType(){ this.property = true; }
SuperType.prototype.getSuperValue = function(){
  return this.property;
};

function SubType(){
  this.subproperty = false;
}

//inherit from SuperType
SubType.prototype = new SuperType();

//使用字面量<a href="https://www.jb51.cc/tag/tianjia/" target="_blank" class="keywords">添加</a>的<a href="https://www.jb51.cc/tag/fangfa/" target="_blank" class="keywords">方法</a>导致上面的<a href="https://www.jb51.cc/tag/fangfa/" target="_blank" class="keywords">方法</a>失效了
SubType.prototype = {
  getSubValue : function (){
    return this.subproperty;
  },someOtherMethod : function (){
    return false;
  }
}; 

var instance = new SubType();
console.log(instance);
alert(instance.getSuperValue());  //error!

下面的例子也说明重写原型带来的风险

rush:js;"> function SuperType(){ this.colors = ["red","green"]; }
function SubType(){      
}

//inherit from SuperType
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);  //"red,blue,green,black"

var instance2 = new SubType();
alert(instance2.colors);  //"red,black"

原型共享导致两个不同的对象调用的同一个数据

16、借用构造函数来实现继承

rush:js;"> function SuperType(){ this.colors = ["red","green"]; }
function SubType(){ 
  //inherit from SuperType
  SuperType.call(this);
}

var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);  //"red,green"

传递参数

rush:js;"> function SuperType(name){ this.name = name; }
function SubType(){ 
  //inherit from SuperType passing in an argument
  SuperType.call(this,"Nicholas");

  //instance property
  this.age = 29;
}

var instance = new SubType();
alert(instance.name);  //"Nicholas";
alert(instance.age);   //29

17、组合继承方式

rush:js;"> function SuperType(name){ this.name = name; this.colors = ["red","green"]; }
SuperType.prototype.sayName = function(){
  alert(this.name);
};

function SubType(name,age){ 
  SuperType.call(this,name);

  this.age = age;
}

18、原型继承

rush:js;"> function object(o){ function F(){} F.prototype = o; return new F(); }
var person = {
  name: "Nicholas",friends: ["Shelby","Court","Van"]
};

var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

19、寄生组合式继承

rush:js;"> function object(o){ function F(){} F.prototype = o; return new F(); }
function inheritPrototype(subType,superType){
  var prototype = object(superType.prototype);  //create object
  prototype.constructor = subType;        //augment object
  subType.prototype = prototype;         //assign object
}

function SuperType(name){
  this.name = name;
  this.colors = ["red",name);

  this.age = age;
}

inheritPrototype(SubType,SuperType);

SubType.prototype.sayAge = function(){
  alert(this.age);
};

var instance1 = new SubType("Nicholas",29);
instance1.colors.push("black");
alert(instance1.colors); //"red,black"
instance1.sayName();   //"Nicholas";
instance1.sayAge();    //29


var instance2 = new SubType("Greg",27);
alert(instance2.colors); //"red,green"
instance2.sayName();   //"Greg";
instance2.sayAge();    //27

以上就是今天的javascript学习小结,之后每天还会继续更新,希望大家继续关注。

相关文章

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