详解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实现在数组中查找不同顺序排列的字符串
Sep 26 Javascript
JavaScript通过字典进行字符串翻译转换的方法
Mar 19 Javascript
js 动态给元素添加、移除事件的实现方法
Jul 19 Javascript
关于JSON与JSONP简单总结
Aug 16 Javascript
KnockoutJS 3.X API 第四章之表单textInput、hasFocus、checked绑定
Oct 11 Javascript
在微信小程序中渲染HTML内容的方法示例
Sep 28 Javascript
vue框架下部署上线后刷新报404问题的解决方案(推荐)
Apr 03 Javascript
js实现列表向上无限滚动
Jan 13 Javascript
js+canvas实现简单扫雷小游戏
Jan 22 Javascript
vue-drag-chart 拖动/缩放图表组件的实例代码
Apr 10 Javascript
微信小程序使用前置摄像头拍照
Oct 22 Javascript
canvas 中如何实现物体的框选
Aug 05 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
详解PHP中的mb_detect_encoding函数使用方法
2015/08/18 PHP
ThinkPHP模板Volist标签嵌套循环输出多维数组的方法
2016/03/23 PHP
PHP读取、解析eml文件及生成网页的方法示例
2017/09/04 PHP
PHP设计模式之简单工厂和工厂模式实例分析
2019/03/25 PHP
用JSON做数据传输格式中的一些问题总结
2011/12/21 Javascript
js jquery验证银行卡号信息正则学习
2013/01/21 Javascript
不使用jquery实现js打字效果示例分享
2014/01/19 Javascript
JavaSript中变量的作用域闭包的深入理解
2014/05/12 Javascript
点击button获取text内容并改变样式的js实现
2014/09/09 Javascript
jquery中表单 多选框的一种巧妙写法
2015/09/06 Javascript
使用javascript插入样式
2016/03/14 Javascript
JS 动态加载js文件和css文件 同步/异步的两种简单方式
2016/09/23 Javascript
CSS+jQuery实现简单的折叠菜单
2016/12/20 Javascript
利用JQuery操作iframe父页面、子页面的元素和方法汇总
2017/09/10 jQuery
nodejs中art-template模板语法的引入及冲突解决方案
2017/11/07 NodeJs
Vue集成Iframe页面的方法示例
2017/12/12 Javascript
浅谈vue的几种绑定变量的值 防止其改变的方法
2018/03/01 Javascript
JavaScript对象的特性与实践应用深入详解
2018/12/30 Javascript
vue-cli设置css不生效的解决方法
2020/02/07 Javascript
JavaScript利用键盘码控制div移动
2020/03/19 Javascript
微信小程序 flexbox layout快速实现基本布局的解决方案
2020/03/24 Javascript
VUE项目axios请求头更改Content-Type操作
2020/07/24 Javascript
[53:21]2014 DOTA2国际邀请赛中国区预选赛5.21 DT VS LGD-CDEC
2014/05/22 DOTA
[01:08:44]NB vs VP 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
对python程序内存泄漏调试的记录
2018/06/11 Python
Python Socket编程之多线程聊天室
2018/07/28 Python
Python 合并多个TXT文件并统计词频的实现
2019/08/23 Python
python获取网络图片方法及整理过程详解
2019/12/20 Python
Python参数传递及收集机制原理解析
2020/06/05 Python
英国领先的高街书籍专家:Waterstones
2018/02/01 全球购物
凯普林包包西班牙官网:Kipling西班牙
2019/04/12 全球购物
银行求职信
2014/05/31 职场文书
小学语文业务学习材料
2014/06/02 职场文书
2014小学二年级班主任工作总结
2014/12/05 职场文书
MySQL sql_mode的使用详解
2021/05/08 MySQL
Python数据可视化之Seaborn的安装及使用
2022/04/19 Python