第184天:js创建对象的几种方式总结

面向对象编程(OOP)的特点

抽象:抓住核心问题

封装:只能通过对象来访问方法

继承:从已有的对象下继承出新的对象

多态:多对象的不同形态

一、创建对象的几种方式

javascript 创建对象简单的来说,无非就是使用内置对象或各种自定义对象,当然还可以使用JSON,但写法有很多,也能混合使用。

1、工厂方式创建对象:面向对象中的封装函数(内置对象)

 1 function createPerson(name){
 2    //1、原料
 3     var obj=new Object();
 4    //2、加工
 5     obj.name=name;
 6     obj.showName=function(){
 7        alert(this.name);
 8     }     
 9     //3、出场
10      return obj; 
11 } 
12 var p1=createPerson('小米');
13 p1.showName();

与系统对象的区别:

 var arr=new Array();//生成一个系统数组对象

    1、系统对象是直接用 new 在外面生成,而工厂定义的是在函数内部生成

    2、工厂定义的函数名称第一个是小写开头,而系统定义的是大写开头

工厂模式的优缺点:虽然解决了创建相似对象的问题,但是却没有解决对象识别问题(即怎样知道一个对象的类型)。

2、构造函数创建对象

  当new去调用一个函数,这个时候函数中的this就是创建出来的对象,而且函数的返回值就是this(隐式返回)

  new后面的函数叫做构造函数

  <1>有参数的构造函数

1 function CreatePerson(name){
2   this.name=name;
3   this.showName=function(){
4     alert(this.name);
5   }
6 }
7     var p1=new CreatePerson('小米');

<2>无参数的构造函数

1 function CreatePerson(){}
2     var p1=new CreatePerson();
3     p1.name="小米";
4     p1.showName=function(){
5      alert(p1.name);
6     }
7     p1.showName();

构造函数模式的优缺点:

  1、优点:创建自定义函数意味着将来可以将它的实例标识为一种特定的类型,这是构造函数胜过工厂模式的地方

  2、缺点:每个方法都要在每个实例上重新创建一遍

3、对象字面量方式创建对象

 1 //字面量创建对象
 2    var boy = {
 3       name:'王源'
 4       ,image:'男生头像'
 5       ,age:20
 6       ,sex:'男'
 7       ,technologys:['普通攻击','横扫千军','地狱火','漫天飞雪']
 8    };
 9 
10    //将对象转换成字符串
11    console.log(JSON.stringify(boy));
12 
13    var sboy='{"name":"王源","sex":"男","age":"20"}';//字符串
14    
15    //将字符换转换成json对象
16    var objBoy = JSON.parse(sboy);
17    console.log(objBoy.name);//王源

4、用原型方式 

  1、原型对象:只要创建了一个新函数,就会为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性是一个指向prototype属性所在函数的指针

  2、可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系

1 function Person(){}
2 Person.prototype.name="小米";
3 Person.prototype.showName=function(){
4 alert(this.name);
5 }
6 var p1=new Person();
7 p1.showName();

原型模式的优缺点:

  1、优点:可以让所有的对象实例共享它所包含的属性和方法

  2、缺点:原型中是所有属性都是共享的,但是实例一般都是要有自己的单独属性的。所以一般很少单独使用原型模式。

5.混合模型

  构造函数模式定义实例属性,而原型模式用于定义方法和共享的属性

 1 function CreatePerson(name){
 2   this.name=name;
 3 }
 4   Create.prototype.showName=function(){
 5     alert(this.name);
 6   }
 7     var p1=new CreatePerson('小米');
 8     p1.showName();
 9 
10    var p2=new CreatePerson('小米');
11     p2.showName();
12   alert(p1.showName==p2.showName);//true;原因:都是在原型下面,在内存中只存在一份,地址相同

 总结:

  function 构造函数(){

    this.属性;

  }

  构造函数.原型.方法=function(){};

  var 对象1=new 构造函数();

  对象1.方法();

原型:去改写对象下面公用的的方法或属性,让公用的方法或属性在内存中存在一份(提高性能)

原型:prototype:要写在构造函数的下面

1 var  arr=[];
2 arr.number=10;
3 Array.prototype.number=20;
4 alert(arr.number);//10,
5 //原因:普通定义的要比原型定义的权重大,先会找自身的,自身没有的话再沿着原型链找原型上是否有

属性是否要放在原型下面,就要看该属性是否是可变的,如果不是可变的,就可以放在原型下面,用来公用属性,可变的话放在构造函数下面。

this的指向问题:在事件或者定时器下比较容易出问题

二、包装对象

1、我们把系统自带的对象,叫做系统对象。例如:Array,Date

2、包装对象:基本类型都有自己对应的包装对象:String,Number,Boolean

  var str='hello';//基本类型:字符串类型

  str.charAt(0);//基本类型会找到对应的包装对象类型,然后包装对象把所有的属性和方法给了基本类型,然后包装对象消失。

  str.number=10;//在包装对象下创一个对象,将属性创建在对象下面,然后包装对象就消失了,

  alert(str.number);//会弹出undefined;原因:会在包装对象下重新创建一个对象

三、原型链

  原型链:实例对象与原型之间的连接,叫做原型链  

 _proto_(隐式连接)

Object对象类型是原型链的最外层

  实例对象->先查找自己本身下面的属性和方法->自身没找到会沿着原型链找到该对象的原型,再查看原型上是否有要查找的属性或方法->依次继续查找如果找到的话则返回,否则找到最顶层Object上还没有就真没有了

四、面向对象中的属性和方法 

1、hasOwnProperty():看是否为对象自身下面的属性和方法

  只有对象自己定义的属性和方法则返回true,如果在prototype下定义发属性和方法为公用的,所以返回为false;

2、constructor:查看对象的构造函数

  (可以用来检测函数类型例如检测是否是数组)

  每个原型函数都会自动添加constructor属性(只会生成这一个属性)

  for in的时候有些属性是找不到的(系统自带的属性是for in找不到的,自己定义的可以找到)

  避免修改constructor属性

 1 function Aaa(){}
 2 //Aaa.prototype.name='小米';
 3 //Aaa.prototype.age=6;
 4 //alert(a1.constructor);//Aaa 原因:只是给原型添加了属性,并不是重新赋值了,自动添加的constructor属性还在。
 5 Aaa.prototype={
 6 //  constructor:'Aaa',//需要手动修正指向问题
 7   name:'小米',
 8   age:6
 9 }
10 var a1=new Aaa();
11 alert(a1.constructor);//Object 原因:将原型的prototype重新赋值了,但里面没有constructor

 注意:以这种方式重设constructor属性会使它的[Enumerable]特性被设置为true,默认情况下,原生的constructor属性是不可枚举的。可以通过Object.defineProperty()来修改。

3、instanceof:运算符

  对象与构造函数在原型链上是否有关系,也可以用作类型判断但不是最好的方案,最好的方案是用toString 方法来判断。

4、toString():object上的方法,把对象转化为字符串

1 var arr=[];
2 alert(arr.toString==Object.prototype.toString);//false
3 //原因:系统对象下面都是自带的(例如数组的toString在Array.prototype下),自己写的对象都是通过原型链找到object下面的toString
4 function Aaa(){}
5 var a1=new Aaa();
6 alert(a1.toString==Object.prototype.toString);//true

1>利用toString 进制转化

 Number.toString(进制);

1 var num=255;
2 alert(num.toString(16));//ff---转化为16进制,默认不写转化为十进制

2>利用toString做类型判断:

 1 //跨页面的情况下上面两种情况会失效
 2 
 3  var oF=document.createElement('iframe');
 4 
 5   document.body.appendChild('oF');
 6 
 7   var ifArray=windows.frames[0].Array;//iframe下的Array数组
 8 
 9   var arr=new ifArray();
10 
11   alert(arr.constructor==Array);//false
12 
13   alert(arr instanceof Array);//false
14 
15   alert(Object.prototype.toString.call(arr)=='[object Array]');//true
 1 var arr=[];
 2 alert(Object.prototype.toString.call(arr));//[Object Array] 
 3 var arr={};
 4 alert(Object.prototype.toString.call(arr));//[Object Object] 
 5 var arr=new Date;
 6 alert(Object.prototype.toString.call(arr));//[Object Date] 
 7 var arr=new RegExp;
 8 alert(Object.prototype.toString.call(arr));//[Object RegExp]  
 9 var arr=null;
10 alert(Object.prototype.toString.call(arr));//[Object Null]

五 、继承

1、继承方式:

  1、拷贝继承:通用型  有new无new都可以用

  2、类式继承:new构造函数---利用构造函数(类)继承的方式

  3、原型继承:无new的对象---借助原型来实现对象继承对象

 属性继承:调用父类的构造函数call

 方法继承:用for in的形式 拷贝继承(jq也用拷贝继承)

 1 var a = {
 2             name: '小米'
 3         };
 4         //拷贝继承
 5         function extend(obj1, obj2) {
 6             for (var attr in obj2) {
 7                 obj1[attr] = obj2[attr];
 8             }
 9         }
10         //原型继承
11             var b=cloneObj(a);
12             b.name='小乔';
13             alert(a.name);
14             alert(b.name);
15             function cloneObj(obj) {
16                 var F=function () {};
17                 F.prototype=obj;
18                 return new F();
19             }
20         //类式继承
21         function A() {//父类
22             this.name='小米';
23         }
24         A.prototype.showName=function () {
25             alert(this.name);
26         }
27         function B() {//子类
28             A.call(this);//属性和方法分开继承
29         }
30     //B.prototype=new A();//一句话实现继承,但会有很多问题,比如指向问题,属性会互相影响
31     //类式继承改进:至少由以下四句实现方法的继承,属性需要分开继承
32 
33         var F=function () {};
34         F.prototype=A.prototype;
35         B.prototype=new F();
36         B.prototype.constructor=A;//修正指向问题
37         var b1=new B();
38         b1.name='笑笑';
39         b1.showName();

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏IT派

Java面试中常被问到的几大技术难题

大家在平常面试java的过程中都会遇到哪些难题呢?还有一些即将去面试java的童鞋们,你们想知道技术面试中会涉及到哪些点吗?达妹为你整理Java面试中会被问到的...

1200
来自专栏java一日一条

继承、接口与多态的相关问题

继承:通过继承实现代码复用。Java中所有的类都是通过直接或间接地继程java.lang.Object类得到的。继承而得到的类称为子类,被继承的类称为父类。子类...

852
来自专栏Albert陈凯

scala 隐式详解(implicit关键字)

掌握implicit的用法是阅读Spark源码的基础,也是学习Scala其它的开源框架的关键,implicit 可分为: 隐式参数 隐式转换类型 隐式调用...

3019
来自专栏静晴轩

59分钟学会正则表达式

推荐几个正则表达式编辑器 Debuggex PyRegex Regexper 正则表达式是一种查找以及字符串替换操作。正则表达式在文本编辑器中广泛使用,比如正则...

3845
来自专栏个人随笔

房上的猫:类的无参方法

一.类的无参方法  1.概述:   (1)类是由一组具有相同属性和共同行为的实体抽象而来的   (2)对象执行的操作是通过编写类的方法实现的   (3)类的每一...

37513
来自专栏腾讯IVWEB团队的专栏

讲讲标准的 Promise 长啥样?

不同项目下lib里的promise/deferred往往是差异化最多的,用起来和自己的习惯相比经常是缺胳膊少腿,因此聊聊标准的Promise的啥样的。

1610
来自专栏十月梦想

php内建函数

strpos(变量名,'包含字符')判断变量中字符首次出现的位置,返回值数字,第一位为0

1264
来自专栏Python爱好者

Java基础笔记07

943
来自专栏奔跑的蛙牛技术博客

java基本程序设计

保护对象实例域,提供黑盒的概念保护数据域的安全,体现了面向对象思想。数据>算法的思想

872
来自专栏IT可乐

Java的深拷贝和浅拷贝

  关于Java的深拷贝和浅拷贝,简单来说就是创建一个和已知对象一模一样的对象。可能日常编码过程中用的不多,但是这是一个面试经常会问的问题,而且了解深拷贝和浅拷...

3336

扫码关注云+社区