深深之创造对象的有余方法以致优瑕玷,JavaScript浓烈之创设对象的多样办法以至优劣势

图片 1
永利402com官方网站

JavaScript 深入之创立对象的有余艺术以致优劣点

2017/05/28 · JavaScript
· 对象

初稿出处: 冴羽   

发源《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’);

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’);

短处:对象不可能辨别,因为全数的实例都对准叁个原型

function createPerson(name) {

2. 布局函数情势

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’);

亮点:实例能够辨别为叁个特定的门类

弱点:每一遍创制实例时,种种方法都要被创设三次

    var o = new Object();

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;

3. 原型格局

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. 具有的性质和章程都分享 2. 不能够起头化参数

    o.getName = function () {

3.1 原型情势优化

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);

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属性找到所属构造函数

症结:原型情势该有的弱点照旧有

    };

4. 结缘形式

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

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;

4.1 动态原型情势

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 person1 = new
Person(‘kevin’卡塔尔国; var person2 = new Person(‘daisy’卡塔尔国; // 报错 并不曾该办法
person1.getName(卡塔尔国; // 注释掉上边的代码,那句是能够施行的。
person2.getName(卡塔尔(英语:State of Qatar);

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')

生龙活虎经对 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

}

5.1 寄生结构函数格局

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’);

5.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

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深入连串测度写十六篇左右,目的在于帮我们捋顺JavaScript底层知识,着重批注如原型、效用域、施行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、世袭等苦衷概念。

只要有错误大概不当心的地点,请必需赋予指正,十一分谢谢。借使心仪依然有所启迪,款待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’);

可取:实例能够辨以为三个特定的项目

缺欠:每一次创造实例时,每一种方法都要被创制一遍

2.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. 无法开头化参数

3.1 原型形式优化

function Person(name) {

}

Person.prototype = {

    name: ‘kevin’,

    getName: function () {

        console.log(this.name);

    }

};

var person1 = new Person();

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();

优点:实例能够因而constructor属性找到所属布局函数

短处:原型方式该有的毛病依旧有

  1. 组合情势

布局函数情势与原型情势双剑合璧。

function Person(name) {

    this.name = name;

}

Person.prototype = {

    constructor: Person,

    getName: function () {

        console.log(this.name);

    }

};

var person1 = new Person();

可取:该分享的分享,该民用的私人民居房,使用最不足为怪的艺术

症结:有的人正是可望全部都写在一齐,即更加好的封装性

4.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 的兑现步骤:

先是新建多少个指标

接下来将对象的原型指向 Person.prototype

然后 Person.apply(obj)

归来那一个目的

瞩目此时,回看下 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

5.1 寄生布局函数格局

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

你会发觉,其实所谓的寄生构造函数模式正是比厂子形式在创造对象的时候,多利用了三个new,实际上两个的结果是生机勃勃律的。

而是俺大概是愿意能像使用普通 Array 相像使用 SpecialArray,就算把
SpecialArray 当成函数也同样能用,可是那并不是笔者的原意,也变得不美观。

在能够接收任何格局的意况下,不要选择这种方式。

可是值得风华正茂提的是,上边例子中的循环:

for (var i = 0, len = arguments.length; i < len; i++) {

    values.push(arguments[i]);

}

能够替换到:

values.push.apply(values, arguments);

5.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 的目的。

与寄生结构函数格局有两点不相同:

新成立的实例方法不征引 this

不使用 new 操作符调用构造函数

妥善对象最相符在局地康宁的遭遇中。

稳当结构函数方式也跟工厂方式相通,不能够分辨对象所属类型。

发表评论

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

网站地图xml地图