javascript创建对象方法的总结。

对象是什么?

  js中对象是“无序属性的集合,其属性可以包含基本值,对象或者函数”,简单来说,它就是一个名值对,有key和value,value可以是数据和函数。

怎样创建对象?

创建对象的方法有很多种,它们都有优缺点,下面从简单的开始介绍。

一、使用Object构造函数或者对象字面量方法创建实例对象

使用这种方法创建单个对象,如果创建多个对象会有很多重复代码。另外,和使用Object构造函数相比,字面量方法更直观,建议创建单个对象时都使用对象字面量方法

var object1 = new Object();
object1.name = "nameTest1";
object1.sayName = function(){console.log(this.name);
}
var object2 = {name:"nameTest2",sayName: new Function("console.log(this.name);")
};
object1.sayName();//nameTest1
object2.sayName();//nameTest2

二、工厂模式

抽象创建对象的过程,因为ES5中没有类的概念,所以使用函数来封装以特定接口创建对象的细节。

function createPerson(name){return {name: name,sayName: function(){console.log(this.name)}}
}
var person = createPerson("nameTest");
person.sayName();//nameTest

优点:可以创建多个对象

缺点:不能对象识别

三、构造函数模式

介绍构造函数前要知道new操作符。使用new操作符调用构造函数会经历4个步骤:

  1. 创建一个新的对象
  2. 将构造函数的作用域赋值给新的对象,则this对象指向新的对象。
  3. 执行构造函数中的代码,为新对象添加属性。
  4. 返回新对象

例如:

function Person(name){//2.将构造函数的作用域赋值给personCopy,this指向personCopythis.name = name;//3.执行构造函数中的代码,personCopy.name = name;this.sayName = new Function("console.log(this.name)")//3.执行构造函数中的代码
}
var person = new Person("testName");//1.创建新的对象,personCopy//4.返回personCopy给person
person.sayName();//testName

了解了new操作符,下面介绍创建对象的构造函数模式。

有原生构造函数(Object Array)和自定义构造函数的概念。原生构造函数不做介绍。

下面是一个自定义的构造函数(构造函数名一般首字母大写

function Person(name){this.name = name;this.sayName = new Function("console.log(this.name)")
}

和工厂模式比较,有一些不同

  • 没有显式的创建对象,即没有var o = new Object()
  • 直接把属性赋值给了this对象
  • 没有return 语句

下面通过上面的构造函数创建2个对象

function Person(name){this.name = name;this.sayName = new Function("console.log(this.name)")
}
var person1 = new Person("testName1");
var person2 = new Person("testName2");
console.log(person1 instanceof Object);//true 对象类型检测
console.log(person2 instanceof Object);//true 对象类型检测
console.log(person1 instanceof Person);//true 对象类型检测
console.log(person2 instanceof Person);//true 对象类型检测
console.log(person1.sayName === person2.sayName);//false 不同对象的同一方法不同
//通过实例对象可以访问构造函数的原型对象中的constructor属性,这个属性指向构造函数
console.log(person1.constructor === Person);//true
console.log(person1.hasOwnProperty("constructor"));//false 可以说明实例对象本身没有constructor属性

通过上面的代码可以知道:

  • instanceof可以用来判断元素是否是数组和对象
  • 实例对象本身中没有constructor属性,它存在于原型对象中
  • constructor属性指向构造函数

如上这个构造函数,其中的方法对于不同的实例对象是不同的,原因是每实例一个对象。都会新建一个function,可以通过移除function定义到构造函数外面解决

function Person(name){this.name = name;this.sayName = fn;
}
function fn(){console.log(this.name);
}
var person1 = new Person("testName1");
var person2 = new Person("testName2");
person1.sayName();
person2.sayName();
console.log(person1.sayName === person2.sayName);//true
//通过这种方法使得构造函数中的方法只创建了一次,那么不同的实例对象的同一方法也就相同了
//但如上这种做法有问题,如果构造函数中有很多方法,都定义在全局作用域中没有封装,并且浪费(毕竟定义在全局作用域中的函数只给一个函数调用)

构造函数的问题在于其对方法的处理有不足。

如果方法定义在构造函数里面,不同的实例对象就会重复新建方法,使得同一方法对于不同的实例对象是不同的

如果定义在构造函数外面(也就是全局作用域中),多个全局方法只被一个函数(这个构造函数)使用,造成浪费,并且没有封装性

可以使用原型模式来解决这个问题

四、原型模型

要理解原型模式,首先要理解什么是原型对象

理解原型对象

新建一个函数时,就会根据一组特定的规则为该函数创建一个prototype属性(也叫作原型属性),该属性的值是一个指针,这个指针指向了函数的原型对象。

默认情况下,原型对象都会获取一个constructor属性(也叫作构造函数属性),该属性的值是一个指针,这个指针指向了prototype属性所在的函数。

function Person(name){this.name = name;
}
Person.prototype.age = 15;
Person.prototype.sayName = function(){console.log(this.name)};
console.log(Person.prototype.constructor === Person);//true 原型对象的构造函数属性指向构造函数

理解原型模式

原型模式指的是把需要的属性都添加在原型对象上

这里需要指出的是,当使用new操作符实例一个对象时,实例对象内部会包含一个属性[[prototype]],这个属性是一个指针,它指向构造函数的原型对象。

要注意的是,这个连接存在与实例对象与原型对象之间,不是存在于实例对象与构造函数之间。

这样的话就可以将需要的属性全都定义在原型对象上。并且原型对象只有一个,不会因为new操作符新建原型对象(新建函数时就会默认新建原型对象),所以所有实例对象都可以共享原型对象上的属性和方法。

这就解决了构造函数模式中方法的不足的问题,原型模式即不会出现不同实例同一构造函数但方法不同的问题,也不会出现将方法放在全局作用域中没有封装性的问题,并且不浪费内存。

function Person(){}
Person.prototype.name = "nameTest1";
Person.prototype.sayName = function(){console.log(this.name)};
console.log(Person.prototype.constructor === Person);//true 原型对象的构造函数属性指向构造函数
var person1 = new Person();
var person2 = new Person();
//Object.getPrototypeOf(value)取得value的原型对象,这个方法返回[[prototype]]的值(不能直接访问[[prototype]]属性)
console.log(Object.getPrototypeOf(person1) === Person.prototype);//true
console.log(person1.hasOwnProperty("name"));//false
console.log(person1.hasOwnProperty("sayName"));//false
console.log(person1.sayName === person2.sayName);//true 同一方法在不同实例对象上是相同的
person1.sayName();//nameTest1
person2.sayName();//nameTest1

上面的code通过把属性和方法添加在原型对象上实现了创建新的实例对象,可以看到:

  • 实例对象本身并不存在属性和方法
  • 实例对象可以访问属性和方法,这是因为原型对象中存在该属性和方法,这其中有一个查找对象属性的过程。
  • 不同实例共享了原型对象,使得不同实例对象的同一方法是相同的

下面说一下查找对象属性的过程。

每次访问实例对象的属性和方法时,都会执行一次搜索,目标是具有给定名字的属性。

  1. 实例对象本身进行寻找
  2. 实例对象内部属性指向的原型对象本身进行寻找
  3. 原型对象自动获取的constructor属性指向的构造函数中进行寻找

同名属性前面的属性会屏蔽后面的属性

function Person(){this.job = "coder"
}
Person.prototype.name = "nameTest1";
Person.prototype.sayName = function(){console.log(this.name)};
var person1 = new Person();
person1.name = "nameTest2";//前面的属性会屏蔽后面的属性,可以用来设置不同的实例对象
console.log(person1.hasOwnProperty("name"));//true 搜索属性的过程到达:实例对象本身
console.log(person1.hasOwnProperty("sayName"));//false 搜索属性的过程到达:原型对象本身
console.log(person1.job);//coder 搜索属性的过程到达:构造函数
person1.sayName();//nameTest2 前面的属性会屏蔽后面的属性
person1.name = null;
person1.sayName();//null 设置为null不会恢复与原型对象的连接
delete person1.name;
console.log(person1.hasOwnProperty("name"));//false
person1.sayName();//nameTest1 delete操作符可以恢复与原型对象的连接

重写原型对象的问题

使用原型模式常见的方式是使用对象字面量法来重写原型对象

正确的方式是在实例对象前面使用对象字面量法来重写原型对象,并且需要把constructor属性指向构造函数

function Person(){}
var person1 = new Person();
Person.prototype = {constructor: Person,//如果没有这一步的话Person.prototype的constructor属性将指向Object构造函数name: "nameTest1",sayName: function(){console.log(this.name)}
}
var person2 = new Person();
console.log("name" in person1);//false 如果在实例对象后重写原型对象,实例对象与新的原型对象是不能建立连接的
console.log("name" in person2);//true 如果在实例对象前重写原型对象,是能够建立新的连接的

原型模式的问题

  1. 单独使用原型模式,将所有的属性和方法定义在原型对象上,省略了构造函数传递参数初始化的过程,使得所有实例对象默认情况下都取得了相同的值,但往往我们想要不同的实例对象用一些不同的属性,但这个问题可以通过在实例对象上添加同名属性屏蔽原型对象上的属性来解决,就是麻烦了点。
  2. 原型模式共享原型对象的本质导致如果通过一个实例对象修改原型对象的属性,那么另外一个实例对象的同名属性也会被修改。对引用类型值特别明显。
function Person(){}
Person.prototype = {constructor: Person,name: "nameTest1",job: ["coder","ITer"],sayName: function(){console.log(this.name)},sayJob: function(){console.log(this.job)},
}
var person1 = new Person();
var person2 = new Person();
person1.name = "newName";
person1.sayName();//newName 对非引用类型的值在实例对象上修改会屏蔽原型对象上的同名属性
person2.sayName();//nameTest1
person1.job.push("LOLer"); //对引用类型的值在实例对象上修改会修改原型对象中的同名属性
person1.sayJob();//coder, ITer, LOLer
person2.sayJob();//coder, ITer, LOLer 因为共享的本质,使得其他实例对象对原型对象的修改也会反映在该实例对象上

五、组合使用构造函数模式和原型模式

目前ES5环境下最好的创建对象的方法是组合使用构造函数模式和原型模式

构造函数模式用于定义实例属性(也就是每个实例都不一样的属性),原型模式用来定义方法和共享的属性(每个实例都一样的属性)。

function Person(name){this.name = name;this.job = ["coder","ITer"];
}//对象字面量重写原型对象
Person.prototype = {constructor: Person,sayName: function(){console.log(this.name)},sayJob: function(){console.log(this.job)},
}
var person1 = new Person("name1");
var person2 = new Person("name2");
person1.name = "newName";
person1.sayName();//newName
person2.sayName();//name2
person1.job.push("LOLer");
person1.sayJob();//coder, ITer, LOLer
person2.sayJob();//coder, ITer

六、动态原型模式

上面提到的最好的方法将构造函数与原型对象分开了,动态原型模式把所有信息封装在了构造函数中,并且通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型对象的优点。

也就是说动态原型模式也使用到了原型,只不过是在构造函数中使用的。

function Person(name){this.name = name;this.job = ["coder","ITer"];//只有在sayName方法不存在的情况下,才给原型对象添加属性,也就是说下面这段代码只会在第一次调用构造函数时才会执行//再次调用构造函数实例对象时,sayName属性已经存在于原型对象中,不会再重复创建,并且只要判断一个就可以了if(typeof this.sayName != "function") {console.log("这个log只会在第一个调用构造函数时出现一次,再次调用时不会出现");Person.prototype.sayName = function(){console.log(this.name)};Person.prototype.sayJob = function(){console.log(this.job)};//不能在已经创建实例的情况下使用对象字面量法重写原型对象,会切断实例与新原型之间的联系// Person.prototype = {//     constructor: Person,//     sayName: function(){//         console.log(this.name)//     },//     sayJob: function(){//         console.log(this.job)//     }// }
    };
}
var person1 = new Person("name1");
var person2 = new Person("name2");
person1.name = "newName";
person1.sayName();//newName
person2.sayName();//name2
person1.job.push("LOLer");
person1.sayJob();//coder, ITer, LOLer
person2.sayJob();//coder, ITer

余下两种创建对象的方式到现在也没找到使用场景,这里就不做记录了。

我的微信:t230124

欢迎讨论学习,打LOL

转载于:https://www.cnblogs.com/FireCamp/p/7884026.html

javascript创建对象方法总结相关推荐

  1. Javascript 创建对象方法的总结

    1. 使用Object构造函数来创建一个对象,下面代码创建了一个person对象,并用两种方式打印出了Name的属性值. var person = new Object();person.name=& ...

  2. Javascript创建对象几种方法解析

    Javascript创建对象几种方法解析 Javascript面向对象编程一直是面试中的重点,将自己的理解整理如下,主要参考<Javascript高级程序设计 第三版>,欢迎批评指正. 通 ...

  3. JavaScript创建对象的4种方法

    JavaScript 创建对象的4种方法 所谓对象就是用来帮助你完成一些事情是,对象是有特征和行为的,是具体特指的某一个事物.使用对象可以使程序更加整洁 通过Object()方法来创建 Object( ...

  4. JavaScript创建对象的6种方式

    JavaScript创建对象简单的说,无非就是使用内置对象(Object)或各种自定义对象,当然还可以用JSON,但写法有很多种,也能混合使用. 1.对象字面量的方式 person = {name : ...

  5. JavaScript创建对象的7大模式

    在JavaScript中,创建对象有7大模式,分别是工厂模式.构造函数模式.原型模式.组合使用构造函数模式和原型模式.动态原型模式.寄生构造函数模式.稳妥构造函数模式.下面针对这7种模式展开讲解. 工 ...

  6. JavaScript的方法和技巧

    摘自http://www.cnblogs.com/Jamedy/archive/2007/02/14/650079.html 有些时候你精通一门语言,但是会发现你其实整天在和其它语言打交道,也许你以为 ...

  7. js方式调用php_javascript调用PHP和PHP调用javascript的方法

    javascript调用PHP和PHP调用javascript的方法 发布时间:2020-06-22 17:03:14 来源:亿速云 阅读:262 作者:Leah 这篇文章将为大家详细讲解有关java ...

  8. 异步与延迟加载JavaScript的方法

    默认情况JavaScript是同步加载的,也就是JavaScript的加载是阻塞的,后面的元素要等待JavaScript加载完毕后才能进行再加载,有多种无阻赛下载JavaScript的方法. (1)d ...

  9. 前端必须学会的5个原生JavaScript对象方法

    前端必须学会的5个原生JavaScript对象方法 JavaScript 随着node.js和基于JavaScript的各种框架的诞生,JavaScript在当今的互联网越来越受到人们的重视,今天我们 ...

最新文章

  1. Sass学习笔记 -- 初步了解函数、运算、条件判断及循环
  2. 沟通CTBS助六和集团实现财务集中管理
  3. Android之如何使用快速联系徽章
  4. pytorch和python有什么区别_PyTorch到底好用在哪里?
  5. Ubuntu/Centos 等linux终端忽略大小写提示
  6. 剑指offer面试题18. 删除链表的节点(双指针)(链表)
  7. mac git配置 idea
  8. 最详细的手机资料名词术语解释
  9. 用gpg加密软件加密文件
  10. Unity 3D学习(一)Unity 3D介绍与安装
  11. VMware Workstation中的虚拟共享存储
  12. 小程序——添加动画,让图标原地旋转
  13. 感觉所有的方法都有人做了,NLPer怎么找创新点?
  14. python----XML
  15. 英特尔 超核芯显卡 620mac_十代i9+3080显卡,男孩们的攒机快乐,还得拿出来显摆显摆!...
  16. 对训练样本分布不均的思考
  17. ubuntu进行apt-get时候出现Package xxx is not available, but is referred to by another package 错误
  18. SAP 使用BDC的一些心得
  19. 现控计控中基于留数法Z变换与Z反变换的MATLAB实现
  20. Aria2 RPC接口协议和Java的本地调用实现

热门文章

  1. 【博客496】k8s dns解析与服务发现原理
  2. apicloud打包成apk
  3. Linux组播编程 组播发送和组播接收
  4. android adb 抓取log
  5. MySQL索引优化是什么意思?底层原理是什么?
  6. Winform自定义MessageBox
  7. 【深度学习】非常详细 | 用 Pytorch 理解卷积网络
  8. Android超简单时间轴的实现
  9. 深拷贝与浅拷贝是什么?如何实现浅拷贝和深拷贝?
  10. linux /sys目录下的各个子目录说明