您的位置:永利集团登录网址 > web资讯 > JavaScript 深入之创建对象的多种方式以及优缺点

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

2019-11-30 02:29

JavaScript 浓厚之继续的有余方法和优劣势

2017/05/28 · JavaScript · 继承

最早的文章出处: 冴羽   

JavaScript 深切之成立对象的有余艺术以至优短处

2017/05/28 · JavaScript · 对象

原作出处: 冴羽   

再谈javascript原型世袭,javascript原型世袭

实在含义上来讲Javascript并非一门面向对象的语言,未有提供古板的继续格局,但是它提供了风华正茂种原型世袭的不二等秘书籍,利用本人提供的原型属性来得以达成持续。

原型与原型链

说原型世袭在此以前照旧要先说说原型和原型链,终究那是促成原型世袭的底工。
在Javascript中,各个函数都有两个原型属性prototype指向自身的原型,而由那几个函数创设的目的也会有二个__proto__性子指向这些原型,而函数的原型是三个指标,所以那一个指标也是有一个__proto__针对自身的原型,这样逐层深刻直到Object对象的原型,那样就造成了原型链。上面那张图很好的分解了Javascript中的原型和原型链的涉嫌。

图片 1

种种函数都以Function函数创立的靶子,所以种种函数也可能有一个__proto__性格指向Function函数的原型。这里要求提议的是,真正产生原型链的是每一个对象的__proto__质量,实际不是函数的prototype属性,那是很关键的。

原型世襲

基本格局

复制代码 代码如下:

var Parent = function(){
    this.name = 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(){
    this.name = 'child' ;
} ;
Child.prototype = new Parent() ;

var parent = new Parent() ;
var child = new Child() ;

console.log(parent.getName()) ; //parent
console.log(child.getName()) ; //child

这种是最简易完毕原型世襲的方式,直接把父类的目的赋值给子类构造函数的原型,那样子类的靶子就能够访谈到父类以至父类布局函数的prototype中的属性。 这种办法的原型继承图如下:

图片 2

这种办法的长处很分明,达成丰富数之差非常的少,不需求别的特殊的操作;同一时候短处也很明显,借使子类供给做跟父类布局函数中平等的伊始化动作,那么就得在子类布局函数中再重新一次父类中的操作:

复制代码 代码如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    this.name = name || 'child' ;
} ;
Child.prototype = new Parent() ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(parent.getName()) ; //myParent
console.log(child.getName()) ; //myChild

地点这种情状还只是急需起头化name属性,假使早先化工作持续追加,这种情势是十分不低价的。由此就有了上边风华正茂种改革的方法。

借用构造函数

复制代码 代码如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
Child.prototype = new Parent() ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(parent.getName()) ; //myParent
console.log(child.getName()) ; //myChild

上边这种方法在子类构造函数中经过apply调用父类的构造函数来进展相符的起头化职业,那样无论父类中做了多少开首化工作,子类也足以实行同豆蔻梢头的早先化职业。不过下面这种实现还存在二个主题素材,父类构造函数被实行了三回,三遍是在子类结构函数中,一遍在赋值子类原型时,那是比超级多余的,所以我们还需求做三个改正:

复制代码 代码如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
Child.prototype = Parent.prototype ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(parent.getName()) ; //myParent
console.log(child.getName()) ; //myChild

这样大家就只须要在子类构造函数中实施三遍父类的构造函数,同不常候又足以世袭父类原型中的属性,那也比较切合原型的初志,便是把需求复用的剧情放在原型中,大家也只是持续了原型中可复用的从头到尾的经过。上边这种办法的原型图如下:

图片 3

暂且布局函数形式(圣杯方式卡塔尔(قطر‎

地方借用构造函数形式最后改进的本子依旧存在问题,它把父类的原型间接赋值给子类的原型,那就能够以致四个主题素材,正是大器晚成旦对子类的原型做了改换,那么这几个改过相同的时候也会耳濡目染到父类的原型,从而影响父类对象,这么些一定不是富贵人家所希望看到的。为了消除这么些标题就有了权且结构函数格局。

复制代码 代码如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
var F = new Function(){} ;
F.prototype = Parent.prototype ;
Child.prototype = new F() ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(parent.getName()) ; //myParent
console.log(child.getName()) ; //myChild

该方法的原型继承图如下:

图片 4

相当轻松能够看看,通过在父类原型和子类原型之间走入一个不经常的布局函数F,切断了子类原型和父类原型之间的联系,那样当子类原型做修正时就不会影响到父类原型。

自己的不二等秘书诀

《Javascript方式》中到圣杯形式就停止了,不过不管上面哪意气风发种办法都有三个不轻便被发觉的标题。我们能够看看本身在'Parent'的prototype属性中投入了叁个obj对象字面量属性,不过一向都并未有用。大家在圣杯格局的根基上来会见下边这种气象:

复制代码 代码如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
var F = new Function(){} ;
F.prototype = Parent.prototype ;
Child.prototype = new F() ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(child.obj.a) ; //1
console.log(parent.obj.a) ; //1
child.obj.a = 2 ;
console.log(child.obj.a) ; //2
console.log(parent.obj.a) ; //2

在地点这种景观中,当小编修正child对象obj.a的时候,同偶然候父类的原型中的obj.a也会被更动,那就发出了和分享原型同样的问题。现身那一个情状是因为当访谈child.obj.a的时候,大家会沿着原型链平昔找到父类的prototype中,然后找到了obj属性,然后对obj.a进行更改。再看看上面这种场馆:

复制代码 代码如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
var F = new Function(){} ;
F.prototype = Parent.prototype ;
Child.prototype = new F() ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(child.obj.a) ; //1
console.log(parent.obj.a) ; //1
child.obj.a = 2 ;
console.log(child.obj.a) ; //2
console.log(parent.obj.a) ; //2

此地有八个根本的难题,当指标访谈原型中的属性时,原型中的属性对于目的的话是只读的,也正是说child对象足以读取obj对象,不过不能够改过原型中obj对象援引,所以当child更改obj的时候并不会对原型中的obj爆发潜移暗化,它只是在本身对象增多了四个obj属性,覆盖了父类原型中的obj属性。而当child对象校勘obj.a时,它先读取了原型中obj的援用,那时child.obj和Parent.prototype.obj是指向同三个指标的,所以child对obj.a的校正会影响到Parent.prototype.obj.a的值,进而影响父类的对象。AngularJS中有关$scope嵌套的接轨情势正是模范Javasript中的原型世袭来实现的。
依据地点的叙说,只要子类对象中做客到的原型跟父类原型是同多个目的,那么就可以现出上边这种景象,所以大家能够对父类原型举行拷贝然后再赋值给子类原型,那样当子类纠正原型中的属性时就只是订正父类原型的二个拷贝,并不会潜移暗化到父类原型。具体落实如下:

复制代码 代码如下:

var deepClone = function(source,target){
    source = source || {} ;
    var toStr = Object.prototype.toString ,
        arrStr = '[object array]' ;
    for(var i in source){
        if(source.hasOwnProperty(i)){
            var item = source[i] ;
            if(typeof item === 'object'){
                target[i] = (toStr.apply(item).toLowerCase() === arrStr) : [] ? {} ;
                deepClone(item,target[i]) ;   
            }else{
                deepClone(item,target[i]) ;
            }
        }
    }
    return target ;
} ;
var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : '1'} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
Child.prototype = deepClone(Parent.prototype) ;

var child = new Child('child') ;
var parent = new Parent('parent') ;

console.log(child.obj.a) ; //1
console.log(parent.obj.a) ; //1
child.obj.a = '2' ;
console.log(child.obj.a) ; //2
console.log(parent.obj.a) ; //1

综述上边装有的假造,Javascript世袭的求实实现如下,这里只考虑了Child和Parent都以函数的情形下:

复制代码 代码如下:

var deepClone = function(source,target){
    source = source || {} ;
    var toStr = Object.prototype.toString ,
        arrStr = '[object array]' ;
    for(var i in source){
        if(source.hasOwnProperty(i)){
            var item = source[i] ;
            if(typeof item === 'object'){
                target[i] = (toStr.apply(item).toLowerCase() === arrStr) : [] ? {} ;
                deepClone(item,target[i]) ;   
            }else{
                deepClone(item,target[i]) ;
            }
        }
    }
    return target ;
} ;

var extend = function(Parent,Child){
    Child = Child || function(){} ;
    if(Parent === undefined)
        return Child ;
    //借用父类布局函数
    Child = function(){
        Parent.apply(this,argument) ;
    } ;
    //通过深拷贝世袭父类原型   
    Child.prototype = deepClone(Parent.prototype) ;
    //重置constructor属性
    Child.prototype.constructor = Child ;
} ;

总结

说了那样多,其实Javascript中得以完毕持续是非凡灵活两种的,并从未豆蔻年华种最棒的艺术,需求根据差异的急需完结分化措施的一而再三回九转,最入眼的是要精晓Javascript中贯彻接二连三的规律,相当于原型和原型链的主题材料,只要知道了这个,本人达成三翻五次就足以贯虱穿杨。

真正意义上的话Javascript实际不是一门面向对象的言语,未有提供古板的两次三番格局,可是它提供了大器晚成种...

写在前面

本文批注JavaScript种种世袭形式和优劣点。

唯独注意:

那篇小说更疑似笔记,哎,再让本人感叹一句:《JavaScript高端程序设计》写得真是太好了!

写在前面

那篇文章解说创建对象的各个办法,以至优劣势。

而是注意:

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

1.原型链世袭

function Parent () { this.name = 'kevin'; } Parent.prototype.getName = function () { console.log(this.name); } function Child () { } Child.prototype = new Parent(); var child1 = new Child(); console.log(child1.getName()) // kevin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Parent () {
    this.name = 'kevin';
}
 
Parent.prototype.getName = function () {
    console.log(this.name);
}
 
function Child () {
 
}
 
Child.prototype = new Parent();
 
var child1 = new Child();
 
console.log(child1.getName()) // kevin

问题:

1.援引类型的性质被有着实例分享,比方:

function Parent () { this.names = ['kevin', 'daisy']; } function Child () { } Child.prototype = new Parent(); var child1 = new Child(); child1.names.push('yayu'); console.log(child1.names); // ["kevin", "daisy", "yayu"] var child2 = new Child(); console.log(child2.names); // ["kevin", "daisy", "yayu"]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Parent () {
    this.names = ['kevin', 'daisy'];
}
 
function Child () {
 
}
 
Child.prototype = new Parent();
 
var child1 = new Child();
 
child1.names.push('yayu');
 
console.log(child1.names); // ["kevin", "daisy", "yayu"]
 
var child2 = new Child();
 
console.log(child2.names); // ["kevin", "daisy", "yayu"]

2.在创设 Child 的实例时,无法向Parent传参

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

瑕疵:对象无法甄别,因为具备的实例都照准三个原型

2.借出布局函数(精髓接二连三卡塔尔(قطر‎

function Parent () { this.names = ['kevin', 'daisy']; } function Child () { Parent.call(this); } var child1 = new Child(); child1.names.push('yayu'); console.log(child1.names); // ["kevin", "daisy", "yayu"] var child2 = new Child(); console.log(child2.names); // ["kevin", "daisy"]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Parent () {
    this.names = ['kevin', 'daisy'];
}
 
function Child () {
    Parent.call(this);
}
 
var child1 = new Child();
 
child1.names.push('yayu');
 
console.log(child1.names); // ["kevin", "daisy", "yayu"]
 
var child2 = new Child();
 
console.log(child2.names); // ["kevin", "daisy"]

优点:

1.防止了援用类型的质量被全数实例分享

2.可以在 Child 中向 Parent 传参

比方:

function Parent (name) { this.name = name; } function Child (name) { Parent.call(this, name); } var child1 = new Child('kevin'); console.log(child1.name); // kevin var child2 = new Child('daisy'); console.log(child2.name); // daisy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Parent (name) {
    this.name = name;
}
 
function Child (name) {
    Parent.call(this, name);
}
 
var child1 = new Child('kevin');
 
console.log(child1.name); // kevin
 
var child2 = new Child('daisy');
 
console.log(child2.name); // daisy

缺点:

主意都在布局函数中定义,每回创建实例都会创立三遍方法。

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

可取:实例可以分辨为一个特定的项目

缺欠:每便成立实例时,每一种方法都要被成立一遍

3.组成世袭

原型链世襲和精粹连续双剑合璧。

function Parent (name) { this.name = name; this.colors = ['red', 'blue', 'green']; } Parent.prototype.getName = function () { console.log(this.name) } function Child (name, age) { Parent.call(this, name); this.age = age; } Child.prototype = new Parent(); var child1 = new Child('kevin', '18'); child1.colors.push('black'); console.log(child1.name); // kevin console.log(child1.age); // 18 console.log(child1.colors); // ["red", "blue", "green", "black"] var child2 = new Child('daisy', '20'); console.log(child2.name); // daisy console.log(child2.age); // 20 console.log(child2.colors); // ["red", "blue", "green"]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
 
Parent.prototype.getName = function () {
    console.log(this.name)
}
 
function Child (name, age) {
 
    Parent.call(this, name);
    
    this.age = age;
 
}
 
Child.prototype = new Parent();
 
var child1 = new Child('kevin', '18');
 
child1.colors.push('black');
 
console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]
 
var child2 = new Child('daisy', '20');
 
console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]

优点:融入原型链世袭和结构函数的长处,是 JavaScript 中最常用的存续形式。

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

优点:消除了每一个方法都要被重新创建的难点

破绽:那叫什么封装……

4.原型式世袭

function createObj(o) { function F(){} F.prototype = o; return new F(); }

1
2
3
4
5
function createObj(o) {
    function F(){}
    F.prototype = o;
    return new F();
}

即便 ES5 Object.create 的模拟实现,将盛传的对象作为成立的对象的原型。

缺点:

含有引用类型的属性值始终都会分享相应的值,那点跟原型链世袭同样。

var person = { name: 'kevin', friends: ['daisy', 'kelly'] } var person1 = createObj(person); var person2 = createObj(person); person1.name = 'person1'; console.log(person2.name); // kevin person1.firends.push('taylor'); console.log(person2.friends); // ["daisy", "kelly", "taylor"]

1
2
3
4
5
6
7
8
9
10
11
12
13
var person = {
    name: 'kevin',
    friends: ['daisy', 'kelly']
}
 
var person1 = createObj(person);
var person2 = createObj(person);
 
person1.name = 'person1';
console.log(person2.name); // kevin
 
person1.firends.push('taylor');
console.log(person2.friends); // ["daisy", "kelly", "taylor"]

注意:修改person1.name的值,person2.name的值并未有发生转移,并非因为person1person2有独立的 name 值,而是因为person1.name = 'person1',给person1增多了 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. 无法开头化参数

5. 寄生式世襲

创制二个仅用于封装世襲进度的函数,该函数在中间以某种格局来做增长对象,最终回到对象。

function createObj (o) { var clone = object.create(o); clone.sayName = function () { console.log('hi'); } return clone; }

1
2
3
4
5
6
7
function createObj (o) {
    var clone = object.create(o);
    clone.sayName = function () {
        console.log('hi');
    }
    return clone;
}

破绽:跟借用构造函数形式形似,每趟创造对象都会创制一回方法。

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属性

6. 寄生组合式世袭

为了便于我们阅读,在此处再度一下结缘继承的代码:

function Parent (name) { this.name = name; this.colors = ['red', 'blue', 'green']; } Parent.prototype.getName = function () { console.log(this.name) } function Child (name, age) { Parent.call(this, name); this.age = age; } Child.prototype = new Parent(); var child1 = new Child('kevin', '18'); console.log(child1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
 
Parent.prototype.getName = function () {
    console.log(this.name)
}
 
function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}
 
Child.prototype = new Parent();
 
var child1 = new Child('kevin', '18');
 
console.log(child1)

结合世袭最大的缺点是会调用若干回父布局函数。

壹遍是设置子类型实例的原型的时候:

Child.prototype = new Parent();

1
Child.prototype = new Parent();

壹次在制造子类型实例的时候:

var child1 = new Child('kevin', '18');

1
var child1 = new Child('kevin', '18');

回想下 new 的比葫芦画瓢完结,其实在此句中,大家会进行:

Parent.call(this, name);

1
Parent.call(this, name);

在那,大家又会调用了叁回 Parent 构造函数。

就此,在这里个例子中,如若我们打字与印刷 child1 对象,大家会意识 Child.prototype 和 child1 都有叁个个性为colors,属性值为['red', 'blue', 'green']

那就是说大家该如何改善,制止那二次重复调用呢?

后生可畏旦大家不使用 Child.prototype = new Parent(卡塔尔(英语:State of Qatar) ,而是直接的让 Child.prototype 访谈到 Parent.prototype 呢?

会见哪些贯彻:

function Parent (name) { this.name = name; this.colors = ['red', 'blue', 'green']; } Parent.prototype.getName = function (卡塔尔国 { console.log(this.name卡塔尔(قطر‎ } function Child (name, age卡塔尔 { Parent.call(this, name卡塔尔(英语:State of Qatar); this.age = age; } // 关键的三步 var F = function (卡塔尔(قطر‎ {}; F.prototype = Parent.prototype; Child.prototype = new F(卡塔尔(英语:State of Qatar); var child1 = new Child('kevin', '18'卡塔尔(英语:State of Qatar); console.log(child1卡塔尔(英语:State of Qatar);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
 
Parent.prototype.getName = function () {
    console.log(this.name)
}
 
function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}
 
// 关键的三步
var F = function () {};
 
F.prototype = Parent.prototype;
 
Child.prototype = new F();
 
 
var child1 = new Child('kevin', '18');
 
console.log(child1);

最后我们封装一下那几个接二连三方法:

function object(o卡塔尔(英语:State of Qatar) { function F(卡塔尔 {} F.prototype = o; return new F(卡塔尔国; } function prototype(child, parent卡塔尔国 { var prototype = object(parent.prototype卡塔尔(英语:State of Qatar); prototype.constructor = child; child.prototype = prototype; } // 当我们接受的时候: prototype(Child, Parent卡塔尔(英语:State of Qatar);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}
 
function prototype(child, parent) {
    var prototype = object(parent.prototype);
    prototype.constructor = child;
    child.prototype = prototype;
}
 
// 当我们使用的时候:
prototype(Child, Parent);

引用《JavaScript高档程序设计》中对寄生组合式世襲的称道正是:

这种艺术的高效能浮现它只调用了一回 Parent 构造函数,况兼因而防止了在 Parent.prototype 下面创建不要求的、多余的性质。与此同期,原型链还可以维持不改变;因而,还是可以够健康使用 instanceof 和 isPrototypeOf。开垦职员遍布认为寄生组合式世袭是援用类型最卓绝的存续范式。

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属性找到所属布局函数

症结:原型格局该有的毛病依旧有

深深类别

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
  14. JavaScript 长远之创造对象的有余艺术以致优劣势

    1 赞 3 收藏 评论

图片 5

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

亮点:该分享的分享,该民用的村办,使用最广泛的格局

劣点:有的人正是期待全体都写在生龙活虎道,即越来越好的封装性

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'卡塔尔(英语:State of Qatar); var person2 = new Person('daisy'卡塔尔国; // 报错 并未该情势person1.getName(卡塔尔; // 注释掉上面包车型地铁代码,那句是能够进行的。 person2.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')

若果对 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);

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 赞 收藏 评论

图片 6

本文由永利集团登录网址发布于web资讯,转载请注明出处:JavaScript 深入之创建对象的多种方式以及优缺点

关键词: