JavaScript 面向对象 原型(prototype) 继承
1.对象的概念:无需属性的集合,属性可以为数值,对象或函数,ECMAscript中没有类的概念,这点是javascript与其他面向对象(OO)语言不同的地方。
//创建一个自定义对象
var person=new Object();
person.name="Tom";
person.age=;
person.job="web前端工程师";
person.sayName=function(){
alert(person.name);
}
person.sayName();
//用对象字面量语法来创建自定义对象
var person={
name:"Tom",
age:,
job:"web前端工程师",
sayName:function(){
alert(this.name);
}
}
person.sayName();
2.属性类型
(1)为了描述对象属性(property)的各种特征,ECMAscript引入特性(attribute)的概念,同时为了表示特性是内部值,所以将特性放在[[]]中。
(2)ECMAscript有俩中属性:数据属性和访问器属性
数据属性的特性:[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,默认为true。
[[Enumerable]]:表示能否通过for-in循环来返回属性。默认为true。
[[Writable]]:表示能否修改属性的值。默认为true。
[[Value]]:包含这个属性的值。默认为undefined。
如果想修改数据属性的特性可以调用defineProperty(属性所在对象,"属性名",{描述符对象})。
var person={};
Object.defineProperty(person,"name",{
writable:false,
value:"Tom"
});
alert(person.name);
delete person.name;
alert(person.name);
注意:调用defineProperty()时,没有指定Configurable,writable,enumerable特性时,默认为false。
访问器属性:[[Configurable]]同上。
[[Enumerable]]同上。
[[Get]]:在读取属性是调用,默认为undefined
[[Set]]:在写入属性时调用,默认为undefined
Object.defineProperties()可以通过描述符一次定义多个属性
Object.getOwnPropertyDescriptor(book,"_year");读取属性的特性,返回的是对象。
-----------------------------------------------------------------分割线---------------------------------------------------------------------------------------------------
创建对象的方式:
1.工厂模式
function createPerson(name,age,job)
{
var o=new Object();
o.name=name;
o.age=age;
o.job=job;
o.sayName=function(){
alert(this.name);//this指的是o
}
return o;
}
var person1=createPerson("Tom",,"web前端工程师");
person1.sayName();
工厂模式虽然解决多次创建相似对象的重复性问题,但是并没有解决对象识别问题,也就是typeof之后他都显示object,具体的对象是什么并没有显示(ps传送门对象都有哪些http://blog.sina.com.cn/s/blog_70a3539f0101eww3.html),所以构造函数模式出现了。
2.构造函数模式
function Person(name,age,job)
{
this.name=name;
this.age=age;
this.job=job;
this.sayName=function(){
alert(this.name);//this是Person
}
}
var person1=new Person("Tom",,"web前端工程师");
person1.sayName();
构造函数模式和工厂模式的区别
1.没有显式的创建对象。
2.将属性和方法赋给了this对象。
3.没有return语句。
4.函数名第一个字母大写。
构造函数模式优于工厂模式的原因就是,构造函数模式中的对象实例(person1)通过constructor属性或instanceof操作符可以验证person1既是Object的实例,也是Person的实例,同时也证明所有对象均来自于Object。
但是构造函数也有缺点,对象是引用类型,对象实例化不是指针的改变,而是简单的复制,复制对象的方法和属性,假设一个对象有上千个实例,它就会复制上千个功能相同的方法,这显然是不可取的,我们看下面这个例子:
function Person(name,age,job)
{
this.name=name;
this.age=age;
this.job=job;
this.sayName=sayName;
}
function sayName(){
alert(this.name)
}
var person1=new Person("Tom",,"web前端工程师");
person1.sayName();
我们也可以把sayName()函数的定义战役到构造函数的外部,这样我们就将sayName属性设置成等于全局的sayName函数,这样实例化对象就共享全局作用域中的同一个sayName(),解决了构造函数对象方法的多次创建问题。但是全局作用域定义的sayName()函数只能被某个对象调用谈什么全局作用域,而且如果构造函数对象的方法有很多,就需要定义很多全局函数,封装性又从何谈起,于是原型模式应运而生。
3.原型模式
我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,这个对象中包含着所有对象实例的属性和方法,这个对象就是原型对象。通俗的说,原型对象中的方法和属性可以被所有对象的实例所共享,对象实例就不用多次创建相同的方法和属性,我们看下面这个例子:
function Person(){
};
Person.prototype={
name:"Tom",
age:,
job:"web前端工程师",
sayName:function(){
alert(this.name);
}
}
var person1=new Person();
person1.sayName();

虽然可以通过对象实例访问保存在原型对象中的值,但却不能通过对象实例重写原型的值。其实对象实例获取某一属性的值是从本身开始寻找,然后是原型对象,最后是构造函数对象,所以重写对象实例的属性值(这个值可以通过delete操作符删除)仅仅是阻断了获取原型属性值的途径,但是没有改变其中的值,我们看下面这个例子:
function Person(){
};
Person.prototype.name="Tom";
Person.prototype.age=23;
Person.prototype.job="web前端工程师";
Person.prototype.sayName=function(){
alert(this.name);
}
var person1=new Person();
var person2=new Person();
person1.name="Mike";
alert(person1.name);
alert(person2.name);
alert(person1.name);
alert(person2.name);
用对象字面量语法表示的时候,原型对象的constructor属性不在指向Person,因为每创建一个函数,同时会创建它的prototype对象,用对象字面量语法本质上相当于重写了prototype对象,constructor属性也会变成新对象的constructor属性(这里指向Object),我们看下面这个例子:
function Person(){
};
Person.prototype={
constructor:Person,
name:"Tom",
age:,
job:"web前端工程师",
sayName:function(){
alert(this.name);
}
}
var person1=new Person();
var person2=new Person();
person1.name="Mike";
alert(person1.name);
alert(person2.name);
原型模式的缺点:因为所以对象实例共享原型对象的方法和属性,但是往往实例都有他自己私有的属性,这时候原型模式就不适用了,所以我们可以组合使用构造函数模式和原型模式。
4.组合使用构造函数模式和原型模式
组合使用构造函数模式和原型模式结合了构造函数和原型模式的优点,构造函数定义实例的私有属性,原型模式定义共享属性和方法,下面我们看一个例子:
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
};
Person.prototype={
constructor:Person,
sayName:function(){
alert(this.name);
}
}
var person1=new Person("Tom");
var person2=new Person("Mike");
alert(person1.name);
alert(person2.name);
---------------------------------------------------------------分割线------------------------------------------------------------------------------------------------------
继承
许多OO语言支持俩中继承方式:接口继承(继承方法的签名)和实现继承(继承实际的方法),因为函数没有签名,所以ECMAscript只有实现继承,而实现继承主要由原型链来实现。
1.原型链
简单地说,原型链就是让子对象的原型等于父对象的实例,层层递进,实现实例和原型的链条。下面看一个例子:
function SuperType(){
this.property=true;
}
SuperType.prototype.getSuperValue=function(){
return this.property;
}
function SubType(){
this.subproperty=false;
}
SubType.prototype=new SuperType();
SubType.prototype.getSubValue=function(){
return this.subproperty;
}
var instance=new SubType();
alert(instance.getSuperValue());//true

这里需要注意SubType.prototype对象的constructor属性已经不指向SubType,而是指向SuperType.
原型链的问题:
1.原型链也会遇到原型模式的问题,这里就不多说了。
2.创建子对象的实例时,没有办法在不影响所有对象实例的情况下,给父对象的构造函数传递参数。
2.借用构造函数
function SuperType(){
this.colors=["red","blue","green"];
}
function SubType(){
SuperType.call(this)//或者apply()
}
var instance1=new SubType();
instance1.colors.push("black");
alert(instance1.colors);
var instance2=new SubType();
alert(instance2.colors);
借用构造函数也可以通过子对象向父对象传递参数
function SuperType(name){
this.name=name
}
function SubType(){
SuperType.call(this,"Tom")//或者apply()
}
var instance1=new SubType();
alert(instance1.name);
虽然借用构造函数解决了实例共享问题和无法传递参数的问题,但是他做的并不完美,因为所有方法都在构造函数中定义,函数的复用性从何谈起,而且父原型对象中定义的方法,对子对象是不可见的,结果所有类型都只能使用构造函数模式,于是组合继承出现了。
3.组合继承
function SuperType(name,colors)
{
this.name=name;
this.colors=colors;
};
SuperType.prototype.sayName=function()
{
alert(this.name);
};
function SubType(age,name,colors)
{
SuperType.call(this,name,colors);
this.age=age;
};
SubType.prototype=new SuperType();
SubType.prototype.sayAge=function()
{
alert(this.age);
};
var person1=new SubType(,"Tom",["blue","red","green"]);
document.writeln(person1.colors);//来自父对象构造函数
document.writeln(person1.name);//来自父对象构造函数
person1.sayName();//来自父原型对象
document.writeln(person1.age);//来自子对象构造函数
person1.sayAge();//来自子原型对象
这里再强调一下,构造函数创建的属性是实例私有的,原型创建的属性和方法是实例共享的。
4.原型式继承
这种方法并没有使用严格意义的构造函数,而是借助原型可以基于已有的对象创建新对象,同时还不用创建自定义类型来达到这个目的。
以下代码是封装在object函数当中的,在使用的时候直接使用object()
function object (o)//这个o相当于父对象实例
{
function F(){}//这个F相当子对象
F.prototype=o;//继承
return new F();//实例化传出
}
但是ECMAscript5定义了Object.create()方法,可以直接使用,他有俩个参数,下面来一个例子:
var person={
name:"Tom",
age:,
job:"web前端工程师"
};
var anotherPerson=Object.create(person,{
name:{
value:"Mike"
}
});
alert(anotherPerson.name);
在上面这个例子中,create的第二参数是一个对象,其中的属性如果和person重名,则会覆盖person的属性。
5.寄生式继承
function object (o)//这个o相当于父对象实例
{
function F(){}//这个F相当子对象
F.prototype=o;//继承
return new F();//实例化传出
}
function createAnother(o)
{
var clone=object(o);
clone.sayName=function()
{
alert(this.name)
};
return clone;
}
var person={
name:"Tom",
age:
}
var anotherPerson=createAnother(person);
alert(anotherPerson.name);
寄生式继承的缺点:不能做到函数复用而降低效率。
6.寄生组合式继承
组合继承虽然是javascript最常用的继承模式,但是他也不是完美的,这种继承的问题是不管怎么样我么都会调用俩次父对象构造函数,大家可以看之前的例子,下面这个是寄生组合式继承的例子,是最完美的继承:
function object (o)//这个o相当于父对象实例
{
function F(){}//这个F相当子对象
F.prototype=o;//继承
return new F();//实例化传出
}
function inheritPrototype(subType,superType)
{
var prototype=object(superType.prototype);//创建对象
prototype.construct=subType;//增强对象
subType.prototype=prototype;//指定对象
}
function SuperType(name)
{
this.name=name;
}
SuperType.prototype.sayName=function()
{
alert(this.name);
}
function SubType(name,age)
{
SuperType.call(this,name);
this.age=age;
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge=function(){
alert(this.age);
}
var person1=new SubType("Tom",);
person1.sayName();
----------------------------------------------------------分割线---------------------------------------------------------------------------------------------------
以上就是javascript对象,原型和继承总结的所有知识,如果有任何错误请大家指正。
JavaScript 面向对象 原型(prototype) 继承的更多相关文章
- 【面试必备】javascript的原型和继承
原型.闭包.作用域等知识可以说是js中面试必考的东西,通过你理解的深度也就能衡量出你基本功是否扎实.今天来复习一下javascript的原型和继承,虽说是老生常谈的话题,但对于这些知识,自己亲手写一遍 ...
- JavaScript面向对象中的继承
1.1继承的基本概念 使用一个子类,继承另一个父类,那么子类可以自动拥有父类中的所有属性和方法,这个过程叫做继承. >>>继承的两方,发生在两个类之间. 实现继承的三种方式: 扩展O ...
- js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法。
js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法. function ClassA(sColor) { this.color = sColor; } Class ...
- js一种继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法。
js一种继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法. function ClassA(sColor) { this.color = sColor; } ClassA ...
- JavaScript的原型链继承__propt__、prototype、constructor的理解、以及他们之间相互的关系。
回想自己已经工作了有一段时间了,但是自己对JavaScript的原型链.和继承的理解能力没有到位,最近他们彻底的整理并且复习了一遍. 本案例中部分文案来自网络和书籍,如有侵权请联系我,我只是把我的理解 ...
- JavaScript 随笔2 面向对象 原型链 继承
第六章 面向对象的程序设计 1.创建对象的几种方式 A)工厂模式 function CreatObj(name,sex,age){ this.name=name; this.sex=sex; this ...
- Javascript面向对象(封装、继承)
Javascript 面向对象编程(一):封装 作者:阮一峰 Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程( ...
- javascript的原型和继承(1)
原型与继承是javascript中基础,重要而相对比较晦涩难解的内容.在图灵的网上看到一篇翻译过的文章,有参考了一些知名博客.我自己总结了几篇.通过这次的总结,感觉自己对原型和继承的认识又增加了很多, ...
- 深入浅出JavaScript之原型链&继承
Javascript语言的继承机制,它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instanc ...
随机推荐
- xcode7--iOS开发---将app打包发布至app store
时隔3个月再次接触应用打包,又是一顿折腾 说说这次的感受吧: 变得是打包时间减少到4小时(其中大部分时间还是xcode7或者是iOS9的原因),不变的是还是一如既往的坑!! 好了,废话不多说,下面讲讲 ...
- [USACO5.2]蜗牛的旅行Snail Trails(有条件的dfs)
题目描述 萨丽·斯内尔(Sally Snail,蜗牛)喜欢在N x N 的棋盘上闲逛(1 < n <= 120). 她总是从棋盘的左上角出发.棋盘上有空的格子(用“.”来表示)和B 个路障 ...
- hdu 3966 Aragorn's Story : 树链剖分 O(nlogn)建树 O((logn)²)修改与查询
/** problem: http://acm.hdu.edu.cn/showproblem.php?pid=3966 裸板 **/ #include<stdio.h> #include& ...
- 【c学习-8】
/*继承结构体*/ #include // 定义子结构体 struct date{ int year; int month; int day; }; //定义父结构体 struct student{ ...
- php中 include 、include_once、require、require_once4个语言结构的含义和区别
对于不同页面中的相同代码部分,可以将其分离为单个文件 ,通过include引入文件. 可以提高代码的复用率 include 和include_once都有引入文件的作用 使用的语法是 :include ...
- MongoDB学习(1)--安装,基本curd操作
知识点: 1-MongoDB 安装,启动和卸载 2-基本概念 3-基本的增删改查操作(CURD) 来回顾总结一把学习的mongodb,如果有javascript基础,学习"芒果DB" ...
- QP之QEP原理
1.QP简介: 量子平台(Quantum Platform, 简称QP)是一个用于实时嵌入式系统的软件框架,QP是轻量级的.开源的.基于层次式状态机的.事件驱动的平台. QP包括事件处理器(QEP). ...
- css常用样式属性详细介绍
对于初学css的来说,肯定会觉得这么多样式不好记,而且记住了也容易忘,其实刚开始我们不用去记这么多的样式,确实是记了也会忘,刚开始只需记住一些常用的就可以了,然后在慢慢的使用过程当中接触并学习一些高级 ...
- 017---Django的中间件解决跨域
跨域 跨域是什么? 浏览器从一个域名的网页去请求另一个域名的资源的时候,如果不同源.请求的响应结果就会被浏览器的同源策略所拦截 同源策略是什么? 同源:协议 + 域名 + 端口 特点:阻止ajax请求 ...
- Oozie 配合 sqoop hive 实现数据分析输出到 mysql
文件/RDBMS -> flume/sqoop -> HDFS -> Hive -> HDFS -> Sqoop -> RDBMS 其中,本文实现了 使用 sqoo ...