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 ...
随机推荐
- 史上最简单的 SpringCloud 教程 | 第一篇: 服务的注册与发现Eureka(Finchley版本)
转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f1-eureka/ 本文出自方志朋的博客 一.spring ...
- Controller类的方法上的RequestMapping一定要写在Controller类里吗?
转载请标明出处: https://blog.csdn.net/forezp/article/details/80069961 本文出自方志朋的博客 使用Spring Cloud做项目的同学会使用Fei ...
- spring boot整合mybatis查询数据库返回Map字段为空不返回解决
1.出现问题原因原因1:mybatis的配置即mapper返回映射配置. 原因2:jackson的配置即@ResponseBody序列化配置. 2.解决方式步骤1:解决原因1 mybatis: con ...
- java中泛型的简单使用
泛型是在jdk1.5之后引入的,我们可以在类的声明处增加泛型列表,如:<T,E,V>.此处,字符可以是任何标识符,一般采用这3个字母. 1.泛型类声明 class MyCollection ...
- 怎样在Swift中使用CocoaPods
怎样在Swift中使用CocoaPods 它不是神秘的亚马逊区域的部落人用手捡出来的生可可的豆荚,肯定不是!让CocoaPods website来回答可能是最好的: CocoaPods是Cocoa项目 ...
- 简明 ES6 模块
简明 ES6 模块 1.什么是模块 模块就是一段代码,这段代码可以反复使用,经常单独写成一个文件,一旦加载会立即执行. 2.导出 导出有 2 种方式:命名导出和默认导出,分别用关键字export和ex ...
- Emmet插件使用
目录 Emmet插件使用 1.生成html5文档 2.header部分 3.body部分 Emmet插件使用 标签(空格分隔): php 前端 1.生成html5文档 html5:5 ! 2.head ...
- SP1716 GSS3 - Can you answer these queries III(单点修改,区间最大子段和)
题意翻译 nnn 个数, qqq 次操作 操作0 x y把 AxA_xAx 修改为 yyy 操作1 l r询问区间 [l,r][l, r][l,r] 的最大子段和 题目描述 You are give ...
- JDBC编程:获取数据库连接
JDBC(Java Database Connectivity),即Java数据库连接.通过JDBC编程,可以使Java应用程序和数据库进行交互. JDBC驱动的方式有很多种,我们常用的驱动方式为:本 ...
- vuex重置所有state(可定制)
在正式场景中我们经常遇到一个问题,就是登出页面或其他操作的时候,我们需要重置所有的vuex,让其变为初始状态,那么,就涉及到了多种方法:1.页面刷新: window.location.reload() ...