相信但凡作为一个前端工程师,都被面试到过这个面试题目,HR考察的就是对oop思想的理解。

  作为一个从后端转过来的怂逼,oop一直是心中的永远的痛啊。

这几天一直在通读js高级程序设计,重复理解js创建对象的几种方式,以及原型链和constructor等关键点。

  谈到创建对象,我们要从最原始的方式说起,也是最简单的方式,就是直接创建一个Object实例,然后添加属性和方法。

1、简单方式

var o=new Object();
o.name='Lucy';
o.age="20";
o.job = "doctor";
o.showName=function(){
console.log(this.name);
}

  简单方式不仅有这种Object构造函数形式,还有对象字面量

    var o = {
name:"Lucy",
age:20,
job:"doctor",
sayName: function () {
console.log(this.name);
}
}

这种写法看上去没啥问题,但是在创建多个p,就需要重复的代码,给p添加属性和方法,所以这种写法终究还是不算通用。所以后面就干脆把创建对象的过程抽象出来了,就有了工厂模式。

2、工厂模式

  function createPerson(name,age,job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.showName = function(){
console.log(this.name);
}
return o;
}
var p = createPerson('wly','23','前端工程师');
p.showName();
  alert(p.constructor == createPerson); //false
  alert(p instanceof createPerson); //false

  

现在可以通过调用这个函数,无数次创建对象了,但是却并不能确切地知道对象的类型。因为ECMAScript的构造函数可用来创建特定类型的对象,所以构造函数模式就出现了。

3、构造函数模式

    function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayInfo= function(){
console.log(this.name +"," + this.age + "," + this.job);
}
}
var p1 = new Person('lily','23','前端工程师');
var p2 = new Person('lucy','24','前端工程师');
alert(p1.constructor == Person); //true
alert(p2.constructor == Person); //true
alert(p1 instanceof Person); //true
alert(p2 instanceof Person); //true
alert(p1 instanceof Object); //true
alert(p2 instanceof Object); //true
alert(p1.sayInfo == p2.sayInfo); //false

构造函数模式最大的问题:同一构造函数的不同实例的相同方法是不一样的。  

p1,p2都有个constructor属性,该属性指向的就是person。而对象的constructor属性本来就是用来标识对象类型的。不过检测对象类型,还是用instanceof比较好些。至于其中的_prototo__,constructor以后另做详解。

那构造函数又有什么缺点呢,p1和p2都有sayInfo方法,但是是不同实例的同名函数,所以是不相等的( alert(p1.sayInfo == p2.sayInfo) 是false),也就是说构造函数的每个方法事实上是在每个实例中重新重建了一遍,所以难免有点浪费内存。

后面就干脆把sayInfo拎出来,成为下面这个样子。

    function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayInfo= sayInfo;
}
function sayInfo(){
console.log(this.name +"," + this.age + "," + this.job);
}
var p1 = new Person('lily','23','前端工程师');
var p2 = new Person('lucy','24','前端工程师');
alert(p1.sayInfo == p2.sayInfo); //true

  

这儿其实就是p1和p2共享了在全局作用域的sayInfo函数。但是如果我们定义这个全局函数只是为了给某个对象调用,是不是有点奇怪。假设这个Person对象有多个方法,那岂不是要定义多个全局函数。

  

4、原型模式

    function Person(){}
Person.prototype.name = "lily";
Person.prototype.age = 12;
Person.prototype.job = "doctor";
Person.prototype.friends = ["Tom","Lucy"];
Person.prototype.sayName = function(){
console.log(this.name);
};
var a = new Person();
var b = new Person();
a.friends.push("Jack");
console.log(a.friends); //"Tom","Lucy","Jack"
console.log(b.friends); //"Tom","Lucy","Jack"
console.log(a.friends == b.friends) //true

我们的初衷是像这样在所有实例共享属性和方法,我们无话可说,但是一般很少会这样用,因为实例应该拥有自己的全部的属性,这也是为啥很少有人用原型模式的原因。

5、构造模式和原型模式组合使用

创建对象最常见的方式,就是组合使用构造函数模式和原型模式。构造函数用来定义实例属性,原型模式用来定义方法和共享属性。每个实例都会有自己的一份实例属性的副本,但同时又可以共享对方付的引用。

    function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Tom","Lucy"];
} Person.prototype = {
constructor : Person,
sayName:function(){
alert(this.name);
}
}
var a = new Person("lily",12,"doctor");
var b = new Person("lucy",23,"teacher");
a.friends.push("Jack");
console.log(a.friends); //"Tom","Lucy","Jack"
console.log(b.friends); //"Tom","Lucy"
console.log(a.friends == b.friends) //false
console.log(a.sayName == b.sayName) //true

独立的friends属性,共享的sayName,这是定义引用类型的一种默认模式。

还有两种方式:寄生构造函数模式 、稳妥构造函数模式,我认为有需要可以去了解下,感觉这两种模式只是在特定情况才会去使用,一般是很少会用到的,着重点应该前面5个的演变历程。

JS创建对象的方式有几种的更多相关文章

  1. js创建对象的方式 三种

    1. 使用直接量创建1个对象: var aobj = { x : 10, y : function(){ console.log("aobj--> "+this.x); } ...

  2. JS创建对象的方式

    1.采用直接量创建方式:系统会使用new方式自动创建对象 var o = {x:1,y:2,z:2}; 2.采用new关键字创建对象:采用构造函数创建对象 var o = new Object();/ ...

  3. javascript(js)创建对象的模式与继承的几种方式

    1.js创建对象的几种方式 工厂模式 为什么会产生工厂模式,原因是使用同一个接口创建很多对象,会产生大量的重复代码,为了解决这个问题,产生了工厂模式. function createPerson(na ...

  4. JS高级---三种创建对象的方式

    JS高级---三种创建对象的方式 字面量的方式 (实例对象) 调用系统的构造函数 自定义构造函数方式 //创建对象---->实例化一个对象,的同时对属性进行初始化 var per=new Per ...

  5. JS创建对象的几种方式整理

    javascript是一种“基于prototype的面向对象语言“,与java有非常大的区别,无法通过类来创建对象.那么,既然是面象对象的,如何来创建对象呢? 一:通过“字面量”方式创建对象 方法:将 ...

  6. js几种创建对象的方式

    javascript是一种“基于prototype的面向对象语言“,与java有非常大的区别,无法通过类来创建对象.那么,既然是面象对象的,如何来创建对象呢? 一.通过”字面量“方式创建. 方法:将成 ...

  7. 对JS关于对象创建的几种方式的整理

    最近一直在看JS高级程序设计这本书,有空来梳理一下几种创建对象的方式.话不多说,直接步入正题. 第一种:Object构造函数创建 var Person = new Object();Person.na ...

  8. js创建对象的多种方式及优缺点

    在js中,如果你想输入一个的信息,例如姓名,性别,年龄等,如果你用值类型来存储的话,那么你就必须要声明很多个变量才行,变量声明的多了的话,就会造成变量污染.所以最好的方式就是存储到对象中.下面能我就给 ...

  9. JS继承以及继承的几种实现方式总结

    传统面向对象语言:继承是类与类之间的关系. 而在js中由于es6之前没有类的概念,所以继承是对象与对象之间的关系. 在js中,继承就是指使一个对象有权去访问另一个对象的能力. 比如:比如对象a能够访问 ...

随机推荐

  1. Centos安装后的一些必要处理工作

    1永久关闭selinux,修改成permissive或者disabled(建议),修改完需重启 2配置network 3.禁止ping(可选,一般不需要禁止)(默认为0位启用ICMP协议,1为禁止), ...

  2. java值转递?引用传递?

    值传递是传递的是原值的副本,引用传递传递的是原值. 在Java中,如果是基本数据类型,传递的是该参数字面量值的拷贝.如果是引用数据类型,传递的是该参数所引用对象在堆中地址的拷贝. swap(int a ...

  3. 湘潭邀请赛 2018 I Longest Increasing Subsequence

    题意: 给出一个长度为n的序列,序列中包含0.定义f(i)为把所有0变成i之后的Lis长度,求∑ni=1i⋅f(i). 题解: 设不考虑0的Lis长度为L,那么对于每个f(i),值为L或L+1. 预处 ...

  4. 【CF Edu 28 B. Math Show】

    time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...

  5. HDU 1159 最长公共子序列(n*m)

    Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  6. 牛客小白月赛4——I—合唱队形

    链接:https://www.nowcoder.com/acm/contest/134/I来源:牛客网 题目描述 铁子的班级在毕业晚会有一个合唱节目,到了毕业晚会的时候,他们必须排成一排一起合唱&qu ...

  7. 网络嗅探器Wireshark

    http://www.wireshark.org/   About Wireshark Wireshark is the world's foremost network protocol analy ...

  8. Angular1 基础知识 浅析(含锚点)

    1.angular:前端js框架  https://angularjs.org ① SPA单页应用程序 通过ajax从后台获取数据,动态渲染页面,不出现白屏,提高效率,节省流量 (1)锚点值 锚点:是 ...

  9. AngularJS中获取ng-repeat动态生成的ng-model值

    需求:通过ng-repeat动态生成的CheckBox,实现勾选控制对应的批次号.如图: html: <div class="clearfix"> <div cl ...

  10. 结构型设计模式之组合模式(Composite)

    结构 意图 将对象组合成树形结构以表示“部分-整体”的层次结构.C o m p o s i t e 使得用户对单个对象和组合对象的使用具有一致性. 适用性 你想表示对象的部分-整体层次结构. 你希望用 ...