JavaScript深入之创建对象的多种方式以及优缺点,深入之创建对象的多种方式以及优缺点

JavaScript 深刻之创造对象的有余艺术以及优缺点

2017/05/28 · JavaScript
· 对象

原稿出处: 冴羽   

源点《JavaScript高级程序设计》

已离开简书,原因参见
http://www.jianshu.com/p/0f12350a6b66。

写在头里

那篇小说讲解创设对象的各样艺术,以及优缺点。

但是注意:

那篇小说更像是笔记,因为《JavaScript高级程序设计》写得真是太好了!

写在头里

那篇文章讲解创立对象的各个格局,以及优缺点。

只是注意:

那篇小说更像是笔记,因为《JavaScript高级程序设计》写得真是太好了!

  1. 厂子情势

虽卑不足道,但也要有和好的千姿百态。

1. 工厂形式

function createPerson(name) {
  var o = new Object();
  o.name = name;
  o.getName = function () {
    console.log(this.name);
  };

  return o;
}

var person1 = createPerson('kevin');

缺点:对象不能够甄别,因为有着的实例都对准叁个原型

一. 工厂情势

function createPerson(name) { var o = new Object(); o.name = name;
o.getName = function () { console.log(this.name); }; return o; } var
person1 = createPerson(‘kevin’);

1
2
3
4
5
6
7
8
9
10
11
function createPerson(name) {
    var o = new Object();
    o.name = name;
    o.getName = function () {
        console.log(this.name);
    };
 
    return o;
}
 
var person1 = createPerson(‘kevin’);

症结:对象不能甄别,因为具备的实例都对准2个原型

function createPerson(name) {

文章能够在自家的 Github
https://github.com/mqyqingfeng/Blog
查看

二. 构造函数方式

function Person(name) {
  this.name = name;
  this.getName = function () {
    console.log(this.name);
  };
}

var person1 = new Person('kevin');

可取:实例能够分辨为贰个一定的种类

症结:每一趟创设实例时,每一种方法都要被成立1回

二. 构造函数格局

function Person(name) { this.name = name; this.getName = function () {
console.log(this.name); }; } var person1 = new Person(‘kevin’);

1
2
3
4
5
6
7
8
function Person(name) {
    this.name = name;
    this.getName = function () {
        console.log(this.name);
    };
}
 
var person1 = new Person(‘kevin’);

可取:实例能够分辨为1个特定的档次

症结:每趟创造实例时,各个方法都要被创立2次

    var o = new Object();

二.一 构造函数形式优化

function Person(name) {
  this.name = name;
  this.getName = getName;
}

function getName() {
  console.log(this.name);
}

var person1 = new Person('kevin');

可取:消除了各种方法都要被重新创建的题材

症结:那叫什么封装……

2.1 构造函数方式优化

function Person(name) { this.name = name; this.getName = getName; }
function getName() { console.log(this.name); } var person1 = new
Person(‘kevin’);

1
2
3
4
5
6
7
8
9
10
function Person(name) {
    this.name = name;
    this.getName = getName;
}
 
function getName() {
    console.log(this.name);
}
 
var person1 = new Person(‘kevin’);

可取:消除了各类方法都要被再一次成立的难点

症结:那叫什么封装……

    o.name = name;

JavaScript深入之创建对象的多种方式以及优缺点,深入之创建对象的多种方式以及优缺点。三. 原型情势

function Person(name) {

}

Person.prototype.name = 'keivn';
Person.prototype.getName = function () {
  console.log(this.name);
};

var person1 = new Person();

优点:方法不会重复创立

缺点:1. 有所的性质和办法都共享 二. 不能开端化参数

三. 原型方式

function Person(name) { } Person.prototype.name = ‘keivn’;
Person.prototype.getName = function () { console.log(this.name); }; var
person1 = new Person();

1
2
3
4
5
6
7
8
9
10
function Person(name) {
 
}
 
Person.prototype.name = ‘keivn’;
Person.prototype.getName = function () {
    console.log(this.name);
};
 
var person1 = new Person();

亮点:方法不会另行创造

症结:1. 具有的质量和措施都共享 二. 不可能起初化参数

    o.getName = function () {

三.壹 原型方式优化

function Person(name) {

}

Person.prototype = {
  name: 'kevin',
  getName: function () {
    console.log(this.name);
  }
};

var person1 = new Person();

亮点:封装性好了1些

缺陷:重写了原型,丢失了constructor属性

3.一 原型格局优化

function Person(name) { } Person.prototype = { name: ‘kevin’, getName:
function () { console.log(this.name); } }; var person1 = new Person();

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name) {
 
}
 
Person.prototype = {
    name: ‘kevin’,
    getName: function () {
        console.log(this.name);
    }
};
 
var person1 = new Person();

可取:封装性好了几许

缺陷:重写了原型,丢失了constructor属性

        console.log(this.name);

三.二 原型格局优化

function Person(name) {

}

Person.prototype = {
  constructor: Person,
  name: 'kevin',
  getName: function () {
    console.log(this.name);
  }
};

var person1 = new Person();

亮点:实例可以因此constructor属性找到所属构造函数

缺陷:原型方式该有的通病照旧有

3.2 原型情势优化

function Person(name) { } Person.prototype = { constructor: Person,
name: ‘kevin’, getName: function () { console.log(this.name); } }; var
person1 = new Person();

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(name) {
 
}
 
Person.prototype = {
    constructor: Person,
    name: ‘kevin’,
    getName: function () {
        console.log(this.name);
    }
};
 
var person1 = new Person();

优点:实例能够透过constructor属性找到所属构造函数

症结:原型方式该有的缺点仍旧有

    };

四. 构成情势

构造函数形式与原型方式双剑合璧。

function Person(name) {
  this.name = name;
}

Person.prototype = {
  constructor: Person,
  getName: function () {
    console.log(this.name);
  }
};

var person1 = new Person();

优点:该共享的共享,该民用的私人住房,使用最广大的措施

缺陷:有的人正是梦想全体都写在共同,即越来越好的封装性

四. 结合情势

构造函数情势与原型形式双剑合璧。

function Person(name) { this.name = name; } Person.prototype = {
constructor: Person, getName: function () { console.log(this.name); } };
var person1 = new Person();

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name) {
    this.name = name;
}
 
Person.prototype = {
    constructor: Person,
    getName: function () {
        console.log(this.name);
    }
};
 
var person1 = new Person();

可取:该共享的共享,该民用的私家,使用最普遍的不②诀窍

缺陷:有的人正是指望任何都写在一块儿,即越来越好的封装性

    return o;

四.1 动态原型格局

function Person(name) {
  this.name = name;
  if (typeof this.getName != "function") {
    Person.prototype.getName = function () {
      console.log(this.name);
    }
  }
}

var person1 = new Person();

留意:使用动态原型方式时,不能够用对象字面量重写原型

分解下为何:

function Person(name) {
  this.name = name;
  if (typeof this.getName != "function") {
    Person.prototype = {
      constructor: Person,
      getName: function () {
        console.log(this.name);
      }
    }
  }
}

var person1 = new Person('kevin');
var person2 = new Person('daisy');

// 报错 并没有该方法
person1.getName();

// 注释掉上面的代码,这句是可以执行的。
person2.getName();

为了诠释那一个难题,倘使开首执行var person1 = new Person('kevin')

如若对 new 和 apply
的最底层执行进程不是很掌握,能够翻阅后面部分相关链接中的作品。

咱俩想起下 new 的落实步骤:

  1. 率先新建叁个指标
  2. 然后将指标的原型指向 Person.prototype
  3. 然后 Person.apply(obj)
  4. 归来这么些指标

留神那年,回看下 apply 的兑现步骤,会执行 obj.Person
方法,今年就会实施 if 语句里的始末,注意构造函数的 prototype
属性指向了实例的原型,使用字面量格局平昔覆盖
Person.prototype,并不会转移实例的原型的值,person①依然是指向了原先的原型,而不是 Person.prototype。而在此之前的原型是尚未
getName 方法的,所以就报错了!

设若您不怕想用字面量方式写代码,能够品尝下那种:

function Person(name) {
  this.name = name;
  if (typeof this.getName != "function") {
    Person.prototype = {
      constructor: Person,
      getName: function () {
        console.log(this.name);
      }
    }

    return new Person(name);
  }
}

var person1 = new Person('kevin');
var person2 = new Person('daisy');

person1.getName(); // kevin
person2.getName();  // daisy

4.一 动态原型形式

function Person(name) { this.name = name; if (typeof this.getName !=
“function”) { Person.prototype.getName = function () {
console.log(this.name); } } } var person1 = new Person();

1
2
3
4
5
6
7
8
9
10
function Person(name) {
    this.name = name;
    if (typeof this.getName != "function") {
        Person.prototype.getName = function () {
            console.log(this.name);
        }
    }
}
 
var person1 = new Person();

留意:使用动态原型格局时,不可能用对象字面量重写原型

分解下怎么:

function Person(name) { this.name = name; if (typeof this.getName !=
“function”) { Person.prototype = { constructor: Person, getName:
function () { console.log(this.name); } } } } var person一 = new
Person(‘kevin’); var person二 = new Person(‘daisy’); // 报错 并不曾该方法
person一.getName(); // 注释掉上面包车型大巴代码,那句是能够执行的。
person二.getName();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Person(name) {
    this.name = name;
    if (typeof this.getName != "function") {
        Person.prototype = {
            constructor: Person,
            getName: function () {
                console.log(this.name);
            }
        }
    }
}
 
var person1 = new Person(‘kevin’);
var person2 = new Person(‘daisy’);
 
// 报错 并没有该方法
person1.getName();
 
// 注释掉上面的代码,这句是可以执行的。
person2.getName();

为了表明这么些难题,假使早先进行var person1 = new Person('kevin')

1经对 new 和 apply
的最底层执行进程不是很理解,可以翻阅尾巴部分相关链接中的小说。

笔者们回顾下 new 的落到实处步骤:

  1. 率先新建一个目的
  2. 然后将目的的原型指向 Person.prototype
  3. 然后 Person.apply(obj)
  4. 回来这一个目的

只顾那年,回看下 apply 的完结步骤,会进行 obj.Person
方法,这一年就会履行 if 语句里的内容,注意构造函数的 prototype
属性指向了实例的原型,使用字面量格局一贯覆盖
Person.prototype,并不会改变实例的原型的值,person1还是是指向了原先的原型,而不是 Person.prototype。而以前的原型是向来不
getName 方法的,所以就报错了!

即便您不怕想用字面量格局写代码,能够品尝下那种:

function Person(name) { this.name = name; if (typeof this.getName !=
“function”) { Person.prototype = { constructor: Person, getName:
function () { console.log(this.name); } } return new Person(name); } }
var person1 = new Person(‘kevin’); var person2 = new Person(‘daisy’);
person1.getName(); // kevin person2.getName(); // daisy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Person(name) {
    this.name = name;
    if (typeof this.getName != "function") {
        Person.prototype = {
            constructor: Person,
            getName: function () {
                console.log(this.name);
            }
        }
 
        return new Person(name);
    }
}
 
var person1 = new Person(‘kevin’);
var person2 = new Person(‘daisy’);
 
person1.getName(); // kevin
person2.getName();  // daisy

}

五.一 寄生构造函数形式

function Person(name) {

  var o = new Object();
  o.name = name;
  o.getName = function () {
    console.log(this.name);
  };

  return o;

}

var person1 = new Person('kevin');
console.log(person1 instanceof Person) // false
console.log(person1 instanceof Object)  // true

寄生构造函数方式,作者个人觉得应该如此读:

寄生-构造函数-情势,也正是说寄生在构造函数的1种办法。

也正是说打着构造函数的牌子挂羊头卖狗肉,你看创设的实例使用 instanceof
都心有余而力不足指向构造函数!

这么方法可以在非正规处境下行使。比如大家想创建贰个持有额外措施的非凡规数组,不过又不想间接修改Array构造函数,我们得以如此写:

function SpecialArray() {
  var values = new Array();

  for (var i = 0, len = arguments.length; i < len; i++) {
    values.push(arguments[i]);
  }

  values.toPipedString = function () {
    return this.join("|");
  };
  return values;
}

var colors = new SpecialArray('red', 'blue', 'green');
var colors2 = SpecialArray('red2', 'blue2', 'green2');


console.log(colors);
console.log(colors.toPipedString()); // red|blue|green

console.log(colors2);
console.log(colors2.toPipedString()); // red2|blue2|green2

您会发现,其实所谓的寄生构造函数形式正是比厂子方式在创设对象的时候,多利用了3个new,实际上两者的结果是相同的。

可是笔者可能是愿意能像使用普通 Array 1样使用 SpecialArray,尽管把
SpecialArray 当成函数也一如既往能用,不过这并不是小编的本心,也变得不美观。

在能够动用任何情势的图景下,不要使用那种方式。

不过值得1提的是,上面例子中的循环:

for (var i = 0, len = arguments.length; i < len; i++) {
  values.push(arguments[i]);
}

能够替换到:

values.push.apply(values, arguments);

5.一 寄生构造函数情势

function Person(name) { var o = new Object(); o.name = name; o.getName =
function () { console.log(this.name); }; return o; } var person1 = new
Person(‘kevin’); console.log(person1 instanceof Person) // false
console.log(person1 instanceof Object) // true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(name) {
 
    var o = new Object();
    o.name = name;
    o.getName = function () {
        console.log(this.name);
    };
 
    return o;
 
}
 
var person1 = new Person(‘kevin’);
console.log(person1 instanceof Person) // false
console.log(person1 instanceof Object)  // true

寄生构造函数形式,小编个人认为应该如此读:

寄生-构造函数-方式,也即是说寄生在构造函数的①种办法。

也正是说打着构造函数的招牌挂羊头卖狗肉,你看成立的实例使用 instanceof
都爱莫能助指向构造函数!

这么方法可以在尤其情况下行使。比如大家想创设贰个持有额外措施的奇异数组,不过又不想一贯修改Array构造函数,大家得以如此写:

function SpecialArray() { var values = new Array(); for (var i = 0, len
= arguments.length; i len; i++) { values.push(arguments[i]); }
values.toPipedString = function () { return this.join(“|”); }; return
values; } var colors = new SpecialArray(‘red’, ‘blue’, ‘green’); var
colors2 = SpecialArray(‘red2’, ‘blue2’, ‘green2’); console.log(colors);
console.log(colors.toPipedString()); // red|blue|green
console.log(colors2); console.log(colors2.toPipedString()); //
red2|blue2|green2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function SpecialArray() {
    var values = new Array();
 
    for (var i = 0, len = arguments.length; i  len; i++) {
        values.push(arguments[i]);
    }
 
    values.toPipedString = function () {
        return this.join("|");
    };
    return values;
}
 
var colors = new SpecialArray(‘red’, ‘blue’, ‘green’);
var colors2 = SpecialArray(‘red2’, ‘blue2’, ‘green2’);
 
 
console.log(colors);
console.log(colors.toPipedString()); // red|blue|green
 
console.log(colors2);
console.log(colors2.toPipedString()); // red2|blue2|green2

你会发现,其实所谓的寄生构造函数格局就是比厂子形式在成立对象的时候,多应用了三个new,实际上两者的结果是同样的。

但是小编只怕是愿意能像使用普通 Array 一样使用 SpecialArray,就算把
SpecialArray 当成函数也同等能用,然则这并不是作者的本心,也变得不优雅。

在能够行使其余格局的事态下,不要选拔那种形式。

然而值得一提的是,下边例子中的循环:

for (var i = 0, len = arguments.length; i len; i++) {
values.push(arguments[i]); }

1
2
3
for (var i = 0, len = arguments.length; i  len; i++) {
    values.push(arguments[i]);
}

能够替换来:

values.push.apply(values, arguments);

1
values.push.apply(values, arguments);

var person1 = createPerson(‘kevin’);

伍.2 稳妥构造函数形式

function person(name){
  var o = new Object();
  o.sayName = function(){
    console.log(name);
  };
  return o;
}

var person1 = person('kevin');

person1.sayName(); // kevin

person1.name = "daisy";

person1.sayName(); // kevin

console.log(person1.name); // daisy

所谓妥帖对象,指的是未曾国有属性,而且其方式也不引用 this 的靶子。

与寄生构造函数格局有两点区别:

  1. 新创造的实例方法不引用 this
  2. 不选用 new 操作符调用构造函数

得当对象最符合在部分平安的条件中。

妥帖构造函数情势也跟工厂情势一样,不可能辨识对象所属类型。

原文:

伍.二 稳当构造函数方式

function person(name){ var o = new Object(); o.sayName = function(){
console.log(name); }; return o; } var person1 = person(‘kevin’);
person1.sayName(); // kevin person1.name = “daisy”; person1.sayName();
// kevin console.log(person1.name); // daisy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function person(name){
    var o = new Object();
    o.sayName = function(){
        console.log(name);
    };
    return o;
}
 
var person1 = person(‘kevin’);
 
person1.sayName(); // kevin
 
person1.name = "daisy";
 
person1.sayName(); // kevin
 
console.log(person1.name); // daisy

所谓妥贴对象,指的是绝非国有属性,而且其格局也不引用 this 的对象。

与寄生构造函数形式有两点不一样:

  1. 新创建的实例方法不引用 this
  2. 不应用 new 操作符调用构造函数

伏贴对象最适合在一部分安然无恙的条件中。

妥当构造函数格局也跟工厂情势一样,不可能识别对象所属类型。

缺点:对象不能辨别,因为拥有的实例都对准三个原型

深刻种类

JavaScript长远连串目录地址:。

JavaScript深远种类揣摸写10伍篇左右,意在帮大家捋顺JavaScript底层知识,重点教学如原型、成效域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等困难概念。

假如有错误或许不严格的地点,请务必给予指正,10分谢谢。固然喜欢还是具有启发,欢迎star,对作者也是一种鞭策。

  1. JavaScirpt 深切之从原型到原型链
  2. JavaScript
    长远之词法作用域和动态功用域
  3. JavaScript 深刻之推行上下文栈
  4. JavaScript 深切之变量对象
  5. JavaScript 深远之效果域链
  6. JavaScript 深远之从 ECMAScript 规范解读
    this
  7. JavaScript 深刻之推行上下文
  8. JavaScript 浓厚之闭包
  9. JavaScript 深切之参数按值传递
  10. JavaScript
    深远之call和apply的模仿完毕
  11. JavaScript 深远之bind的模拟实现
  12. JavaScript 深入之new的模拟达成
  13. JavaScript 深切之类数组对象与
    arguments

    1 赞 收藏
    评论

图片 1

  1. 构造函数情势

function Person(name) {

    this.name = name;

    this.getName = function () {

        console.log(this.name);

    };

}

var person1 = new Person(‘kevin’);

优点:实例能够辨认为3个一定的项目

症结:每一趟创造实例时,各个方法都要被创立二遍

二.1 构造函数方式优化

function Person(name) {

    this.name = name;

    this.getName = getName;

}

function getName() {

    console.log(this.name);

}

var person1 = new Person(‘kevin’);

可取:消除了每种方法都要被再次创立的难点

症结:那叫什么封装……

  1. 原型情势

function Person(name) {

}

Person.prototype.name = ‘keivn’;

Person.prototype.getName = function () {

    console.log(this.name);

};

var person1 = new Person();

优点:方法不会重复创建

缺点:1. 具备的习性和办法都共享 2. 不能够起首化参数

三.一 原型形式优化

function Person(name) {

}

Person.prototype = {

    name: ‘kevin’,

    getName: function () {

        console.log(this.name);

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图