资讯专栏INFORMATION COLUMN

《javascript高级程序设计》笔记:创建对象

姘存按 / 1848人阅读

摘要:简单方式创建对象字面量方式创建对象方式创建对象虽然构造函数或对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点使用同一个接口创建很多对象,会产生大量的重复代码,如上面的代码,每创建一个类似的对象,就会重复上面的写法,代码较为冗余为了

1. 简单方式创建对象
  // 字面量方式创建对象
  var person1 = {
    name: "xyc",
    age: 23,
    sayHi: function() {
      console.log(name);
    }
  };
  
  // Object方式创建对象
  var person2 = new Object();
  person2.name = "lxy";
  person2.age = 18;
  person2.sayHi = function() {
    console.log(person2.name);
  }

虽然Object构造函数或对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码,如上面的代码,每创建一个类似的person对象,就会重复上面的写法,代码较为冗余

为了解决这个问题(代码重复),下面引入工厂模式 ==>

2. 工厂模式创建对象
  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 o; 
  }
  var person1 = createPerson("Nicholas", 29, "Software Engineer");
  var person2 = createPerson("Greg", 27, "Doctor");

通俗的解释:工厂模式就是利用了函数的封装调用,类比工厂材料==>成品的过程,完成入口参数==>对象的过程,函数可以无数次的生成,因此能够避免上面产生大量重复代码的情况。工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)

为解决这个问题(对象识别),下面引入构造函数模式

3. 构造函数创建对象 3.1 构造函数与普通函数的区别

命名规则:构造函数一般是首字母大写,普通函数遵照小驼峰式命名法

函数调用
构造函数:
(1)new fn( )
(2)构造函数内部会创建一个新的对象,即f的实例
(3)函数内部的this指向 新创建的f的实例
(4)默认的返回值是f的实例
普通函数:
(1)fn( )
(2)在调用函数的内部不会创建新的对象
(3)函数内部的this指向调用函数的对象(如果没有对象调用,默认是window)
(4)返回值由return语句决定

构造函数的返回值
有一个默认的返回值,新创建的对象(实例),当手动添加返回值后(return语句):
(1)返回值是基本数据类型-->真正的返回值还是那个新创建的对象(实例)
(2)返回值是复杂数据类型(对象)-->真正的返回值是这个对象

function foo() {
  var f2 = new foo2();
  console.log(f2);    // {a: 3}
  console.log(this);  // window
  return true;
}
function foo2() {
  console.log(this);  // foo2类型的对象 不是foo2函数
  return {a: 3};
}
var f1 = foo();
console.log(f1);      // true

3.2 new 操作符作用

使用new操作符调用构造函数会经历下面几个步骤:
(1)创建一个以这个函数为原型的空对象.
(2)将函数的 prototype 赋值给对象的 proto 属性
(3)将对象作为函数的 this 传进去。如果有 return 出来东西是对象的话就直接返回 return 的内容,没有的话就返回创建的这个对象

function NewFunc(func){
  var ret = {};
  if (func.prototype !== null) {
    ret.__proto__ = func.prototype;
  }
  var ret1 = func.apply(ret, Array.prototype.slice.call(arguments, 1));
  if ((typeof ret1 === "object" || typeof ret1 === "function") && ret1 !== null) {
    return ret1;
  }
  return ret;
}

普通函数的作用主要是封装作用,能够在作用域内多处调用而已

3.3 构造函数解决对象识别

创建自定义的构造函数意味着可以通过 instanceof 将它的实例标识为一种特定的类型

  function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.sayHi = function(){
      console.log(this.name);
    }
  }
  
  var person1 = new Person("xyc", 23);
  var person2 = new Person("lxy", 22);
  
  console.log(person1 instanceof Person); //true
  console.log(person2 instanceof Person); //true
  console.log(person1 instanceof Object); //true 因为Person继承自Object,所以这里一样成立.
3.4 缺陷

构造函数创建对象的方式解决了代码重复对象识别的问题,但是创建的对象中含有方法时,每实例化一个Person,就会产生一个方法,也就是一个对象,每个对象分别占据内存。因此,构造函数创建对象的方式存在内存大量占用的风险

利用原型共享的特性,下面引入原型模式

4. 原型创建对象
  function Person(){}
  Person.prototype = {
    constructor: Person,
    name : "Nicholas",
    age : 29,
    job : "Software Engineer",
    friends : ["Shelby", "Court"],
    sayName : function () {
      alert(this.name);
    } 
  };
  
  var person1 = new Person();
  var person2 = new Person();
  
  person1.sayName();    //"Nicholas"
  person2.sayName();    //"Nicholas"
  
  person1.friends.push("Van");
  alert(person1.friends);    //"Shelby,Court,Van"
  alert(person2.friends);    //"Shelby,Court,Van"
  alert(person1.friends === person2.friends);  //true

原型创建对象的方式将属性和方法都存在与原型中,也就是说,只要通过这种形式创建的对象都会共享这些属性和对象,相对于方法共享这是我们乐于看到的,但是属性共享让每个实例缺失了“个性”;另外对于引用类型的属性共享时,如上面的例子,多个实例对引用类型的操作会被篡改

实例一般都要有属于自己的全部属性,这也决定了原型创建方式的局限性。下面引入非常经典的对象创建方式

5. 构造函数+原型创建对象(重点)

组合构造函数模式与原型模式:构造函数模式用于定义实力属性,而原型模式用于定义方法和共享的属性

  function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby", "Court"];
  }
  
  Person.prototype = {
    constructor : Person,
    sayName : function(){
      alert(this.name);
    }
  }
  
  var person1 = new Person("Nicholas", 29, "Software Engineer");
  var person2 = new Person("Greg", 27, "Doctor");
  
  person1.friends.push("Van");
  alert(person1.friends);    //"Shelby,Count,Van"
  alert(person2.friends);    //"Shelby,Count"
  alert(person1.friends === person2.friends); //false
  alert(person1.sayName === person2.sayName); //true

这种方式创建的实例对象,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存;另外,这种方式还支持相构造函数传递参数,解决了上面的各种问题

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89476.html

相关文章

  • javascript高级程序设计笔记:内存与执行环境

    摘要:因此,所有在方法中定义的变量都是放在栈内存中的当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用因为对象的创建成本通常较大,这个运行时数据区就是堆内存。 上一篇:《javascript高级程序设计》笔记:继承近几篇博客都会围绕着图中的知识点展开 showImg(https://segmentfault.com/img/bVY0C4?w=1330&h=618);...

    fuyi501 评论0 收藏0
  • 《你不知道的javascript笔记_对象&原型

    摘要:上一篇你不知道的笔记写在前面这是年第一篇博客,回顾去年年初列的学习清单,发现仅有部分完成了。当然,这并不影响年是向上的一年在新的城市稳定连续坚持健身三个月早睡早起游戏时间大大缩减,学会生活。 上一篇:《你不知道的javascript》笔记_this 写在前面 这是2019年第一篇博客,回顾去年年初列的学习清单,发现仅有部分完成了。当然,这并不影响2018年是向上的一年:在新的城市稳定、...

    seasonley 评论0 收藏0
  • javascript高级程序设计笔记:继承

    摘要:继承和前面两篇文章中的知识非常相关,如果对函数创建原理和原型链不熟悉,请猛戳高级程序设计笔记创建对象高级程序设计笔记原型图解继承,通俗的说,就是将自身不存在的属性或方法,通过某种方式为自己所用文章分别介绍原型链继承继承借用构造函数继承组合继 继承和前面两篇文章中的知识非常相关,如果对函数创建原理和原型链不熟悉,请猛戳:《javascript高级程序设计》笔记:创建对象《javascri...

    JerryC 评论0 收藏0
  • JavaScript高级程序设计-摘要笔记-3

    摘要:如果重设构造函数的原型对象,那么,会切断新的原型对象和任何之前已经存在的构造函数实例之间的联系,它们引用的仍然是最初的原型。说明返回的对象与构造函数或者与构造函数的原型属性没有关系。 说明: 此摘要笔记系列是我最近看《JavaScript高级程序设计(第3版)》随手所记。里面分条列举了一些我认为重要的、需要记下的、对我有帮助的点,是按照我看的顺序来的。摘要笔记本身没有系统性,没有全面性...

    AndroidTraveler 评论0 收藏0
  • 笔记JavaScript高级篇——面向对象、原型、继承

    摘要:继承传统的面向对象语言,继承是类与类之间的关系。原型继承原型定义原型就是指构造函数的属性所引用的对象。创建构造函数创建的实例对象张三李四就是对象的原型也是的原型在原型上创建一个属性运行和,并对比是否为同一个方法。 原文链接:http://www.hansmkiii.com/2018/07/06/javascript-node-1/ 面向对象、原型、继承 1、面向对象 1.1 什么...

    OBKoro1 评论0 收藏0
  • javascript高级程序设计笔记:变量对象与预解析

    摘要:检查当前上下文中的参数,建立该对象下的属性与属性值。检查当前上下文的函数声明,也就是使用关键字声明的函数。如果该变量名的属性已经存在,为了防止同名的函数被修改为,则会直接跳过,原属性值不会被修改。 上一篇:《javascript高级程序设计》笔记:内存与执行环境showImg(https://segmentfault.com/img/bVY4xr?w=1146&h=374); 上篇文章...

    tyheist 评论0 收藏0

发表评论

0条评论

姘存按

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<