详解js创建对象的几种方法及继承


Posted in Javascript onApril 12, 2019

创建对象

通过Object构造函数或对象字面量创建单个对象
这些方式有明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码。为了解决这个问题,出现了工厂模式。

工厂模式

考虑在ES中无法创建类(ES6前),开发人员发明了一种函数,用函数来封装以特定接口创建对象的细节。(实现起来是在一个函数内创建好对象,然后把对象返回)。

function createPerson(name,age,job){
  var o=new Object();
  o.name=name;
  o.age=age;
  o.job=job;
  o.sayName=function(){
    alert(this.name);
  };
  return 0;
}

var person1=createPerson("Nicholas",29,"Software Engineer");
var person2=createPerson("Greg",27,"Doctor");

构造函数模式

像Object和Array这样的原生构造函数,在运行时会自动出现在执行环境。此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。

function Person(name,age,job){
  this.name=name;
  this.age=age;
  this.job=job;
  this.sayName=function(){
    alert(this.name);
  };
}

var person1=new Person(...);
var person2=new Person(...);

与工厂模式相比,具有以下特点:

  1. 没有显式创建对象;
  2. 直接将属性和方法赋给了this对象;
  3. 没有return语句;
  4. 要创建新实例,必须使用new操作符;(否则属性和方法将会被添加到window对象)
  5. 可以使用instanceof操作符检测对象类型

构造函数的问题:

构造函数内部的方法会被重复创建,不同实例内的同名函数是不相等的。可通过将方法移到构造函数外部解决这一问题,但面临新问题:封装性不好。

原型模式

我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。(prototype就是通过调用构造函数而创建的那个对象实例的原型对象)。
使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。

function Person(){
}

Person.prototype.name="Nicholas";
Person.prototype.age=29;
Person.prototype.job="...";
Person.prototype.sayName=function(){
  ...
};

var person1=new Person();
person1.sayName();//"Nicholas"

更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象,并重设constructor属性。

function Person(){
}

Person.prototype={
  name:"...",
  age:29,
  job:"...",
  sayName:function(){
    ...
  }
};

Object.defineProperty(Person.prototype,"constructor",{
  enumerable:false,
  value:Person,
});

原型对象的问题:

他省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值,虽然这会在一定程度带来一定的不便,但不是最大的问题,最大的问题是由其共享的本性所决定的。
对于包含基本值的属性可以通过在实例上添加一个同名属性隐藏原型中的属性。然后,对于包含引用数据类型的值来说,会导致问题。

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

这是创建自定义类型的最常见的方式。
构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。所以每个实例都会有自己的一份实例属性的副本,但同时共享着对方法的引用,最大限度的节省了内存。同时支持向构造函数传递参数。

function Person(name,age,job){
  this.name=name;
  this.age=age;
  this.job=job;
  this.friends=["S","C"];
}

Person.prototype={
  constructor:Person,
  sayName:function(){
    alert(this.name);
  }
};

var person1=new Person(...);

动态原型模式

function Person(name,age,job){
  this.name=name;
  this.age=age;
  this.job=job;

  if(typeof this.sayName!="function"){
    Person.prototype.sayName=function(){
      alert(this.name);
    };
  }
}

这里只有sayName()不存在的情况下,才会将它添加到原型中,这段代码只会在初次调用构造函数时才执行。这里对原型所做的修改,能够立刻在所有实例中得到反映。

Object.create()

ES5定义了一个名为Object.create()的方法,它创建一个新对象,其中第一个参数是这个对象的原型,第二个参数对对象的属性进行进一步描述。

Object.create()介绍

Object.create(null) 创建的对象是一个空对象,在该对象上没有继承 Object.prototype 原型链上的属性或者方法,例如:toString(), hasOwnProperty()等方法

Object.create()方法接受两个参数:Object.create(obj,propertiesObject) ;

obj:一个对象,应该是新创建的对象的原型。

propertiesObject:可选。该参数对象是一组属性与值,该对象的属性名称将是新创建的对象的属性名称,值是属性描述符(这些属性描述符的结构与Object.defineProperties()的第二个参数一样)。注意:该参数对象不能是 undefined,另外只有该对象中自身拥有的可枚举的属性才有效,也就是说该对象的原型链上属性是无效的。

var o = Object.create(Object.prototype, {
 // foo会成为所创建对象的数据属性
 foo: { 
  writable:true,
  configurable:true,
  value: "hello" 
 },
 // bar会成为所创建对象的访问器属性
 bar: {
  configurable: false,
  get: function() { return 10 },
  set: function(value) {
   console.log("Setting `o.bar` to", value);
  }
 }
});
console.log(o);//{foo:'hello'}
var test1 = Object.create(null) ;
console.log(test1);// {} No Properties 
因为在bar中设置了configurable 使用set,get方法默认都是不起作用,所以bar值无法赋值或者获取
这里的o对象继承了 Object.prototype Object上的原型方法
我们可以 对象的 __proto__属性,来获取对象原型链上的方法 如:
console.log(o.__proto__);//{__defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, __lookupSetter__: ƒ, …}
console.log(test1.__proto__);//undefined

通过打印发现, 将{}点开,显示的是 No Properties ,也就是在对象本身不存在属性跟方法,原型链上也不存在属性和方法,

new object()

var test1 = {x:1};

var test2 = new Object(test1);

var test3 = Object.create(test1);
console.log(test3);//{} 
//test3等价于test5
var test4 = function(){
  
}
test4.prototype = test1;
var test5 = new test4();
console.log(test5);
console.log(test5.__proto__ === test3.__proto__);//true
console.log(test2);//{x:1}
var test1 = {};
var test2 = new Object();
var test3 = Object.create(Object.prototype);
var test4 = Object.create(null);//console.log(test4.__proto__)=>undefined 没有继承原型属性和方法
console.log(test1.__proto__ === test2.__proto__);//true
console.log(test1.__proto__ === test3.__proto__);//true
console.log(test2.__proto__ === test3.__proto__);//true
console.log(test1.__proto__ === test4.__proto__);//false
console.log(test2.__proto__ === test4.__proto__);//false
console.log(test3.__proto__ === test4.__proto__);//false

总结:使用Object.create()是将对象继承到__proto__属性上

var test = Object.create({x:123,y:345});
console.log(test);//{}
console.log(test.x);//123
console.log(test.__proto__.x);//3
console.log(test.__proto__.x === test.x);//true

var test1 = new Object({x:123,y:345});
console.log(test1);//{x:123,y:345}
console.log(test1.x);//123
console.log(test1.__proto__.x);//undefined
console.log(test1.__proto__.x === test1.x);//false

var test2 = {x:123,y:345};
console.log(test2);//{x:123,y:345};
console.log(test2.x);//123
console.log(test2.__proto__.x);//undefined
console.log(test2.__proto__.x === test2.x);//false

继承

我这里就介绍一种吧,剩下的可以去权威指南里看去

原型链

ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原 型让一个引用类型继承另一个引用类型的属性和方法。简单回顾一下构造函数、原型和实例的关系:每 个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型 对象的内部指针。那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然,此时的 原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数 的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实 例与原型的链条。这就是所谓原型链的基本概念。

实现原型链有一种基本模式,其代码大致如下。

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
  return this.property;
};
function SubType(){
  this.subproperty = false;
}
//继承了 SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
  return this.subproperty;
  };
  var instance = new SubType();
alert(instance.getSuperValue());
//true

以上代码定义了两个类型:SuperType 和 SubType。每个类型分别有一个属性和一个方法。它们 的主要区别是 SubType 继承了 SuperType,而继承是通过创建 SuperType 的实例,并将该实例赋给 SubType.prototype 实现的。实现的本质是重写原型对象,代之以一个新类型的实例。换句话说,原 来存在于 SuperType 的实例中的所有属性和方法,现在也存在于 SubType.prototype 中了。在确立了 继承关系之后,我们给 SubType.prototype 添加了一个方法,这样就在继承了 SuperType 的属性和方 法的基础上又添加了一个新方法。这个例子中的实例以及构造函数和原型之间的关系如图 6-4 所示。

详解js创建对象的几种方法及继承

以上所述是小编给大家介绍的js创建对象的几种方法及继承详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
javascript 命名空间以提高代码重用性
Nov 13 Javascript
改善用户体验的五款jQuery插件分享
May 22 Javascript
javascript实现按回车键切换焦点
Feb 09 Javascript
javascript实现任务栏消息提示的简单实例
May 31 Javascript
angular中子控制器向父控制器传值的实例
Oct 08 Javascript
react中使用css的7中方式(最全总结)
Feb 11 Javascript
Vue实现点击显示不同图片的效果
Aug 10 Javascript
js实现指定时间倒计时效果
Aug 26 Javascript
简介JavaScript错误处理机制
Aug 04 Javascript
.netcore+vue 实现压缩文件下载功能
Sep 24 Javascript
浅谈vant组件Picker 选择器选单选问题
Nov 04 Javascript
详解node.js创建一个web服务器(Server)的详细步骤
Jan 15 Javascript
详解JQuery基础动画操作
Apr 12 #jQuery
React中阻止事件冒泡的问题详析
Apr 12 #Javascript
TypeScript中的方法重载详解
Apr 12 #Javascript
vue-cli 3.x配置跨域代理的实现方法
Apr 12 #Javascript
解决微信小程序调用moveToLocation失效问题【超简单】
Apr 12 #Javascript
详解Bootstrap 学习(一)入门
Apr 12 #Javascript
vue组件中iview的modal组件爬坑问题之modal的显示与否应该是使用v-show
Apr 12 #Javascript
You might like
德生PL450的电路分析和低放电路的改进办法
2021/03/02 无线电
采集邮箱的php代码(抓取网页中的邮箱地址)
2012/07/17 PHP
PHP 获取文件路径(灵活应用__FILE__)
2013/02/15 PHP
thinkphp使用literal防止模板标签被解析的方法
2014/11/22 PHP
EarthLiveSharp中cloudinary的CDN图片缓存自动清理python脚本
2017/04/04 PHP
PHP示例演示发送邮件给某个邮箱
2019/04/03 PHP
js 事件小结 表格区别
2007/08/13 Javascript
Javascript之旅 对象的原型链之由来
2010/08/25 Javascript
Jquery数独游戏解析(一)-页面布局
2010/11/05 Javascript
Javascript 八进制转义字符(8进制)
2011/04/08 Javascript
浅析return false的正确使用
2013/11/04 Javascript
利用Bootstrap实现表格复选框checkbox全选
2016/12/21 Javascript
angular $watch 一个变量的变化(实例讲解)
2017/08/02 Javascript
Angular6 正则表达式允许输入部分中文字符
2018/09/10 Javascript
jQuery表单选择器用法详解
2019/08/22 jQuery
JavaScript中变量提升机制示例详解
2019/12/27 Javascript
vue-cli3 取消eslint校验代码的解决办法
2020/01/16 Javascript
jquery将信息遍历到界面上实例代码
2020/01/21 jQuery
[05:04]DOTA2上海特级锦标赛主赛事第二日TOP10
2016/03/04 DOTA
[52:03]Secret vs VG 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
Python中asyncio与aiohttp入门教程
2018/10/16 Python
使用Python-OpenCV向图片添加噪声的实现(高斯噪声、椒盐噪声)
2019/05/28 Python
python实现简易学生信息管理系统
2020/04/05 Python
opencv3/Python 稠密光流calcOpticalFlowFarneback详解
2019/12/11 Python
python怎么提高计算速度
2020/06/11 Python
基于python获取本地时间并转换时间戳和日期格式
2020/10/27 Python
仿CSDN Blog返回页面顶部功能实现原理及代码
2013/06/30 HTML / CSS
关于VPN
2012/06/10 面试题
EJB3.1都有哪些改进
2012/11/17 面试题
新闻专业毕业生英文求职信
2014/03/19 职场文书
食品安全承诺书
2014/05/22 职场文书
西岭雪山导游词
2015/02/06 职场文书
战马观后感
2015/06/08 职场文书
关于国庆节的广播稿
2015/08/19 职场文书
CSS实现章节添加自增序号的方法
2021/06/23 HTML / CSS
基于MySql验证的vsftpd虚拟用户
2021/11/07 MySQL