来自 公司简介 2019-11-21 08:26 的文章
当前位置: 澳门太阳娱乐手机登录 > 公司简介 > 正文

对象的创建,详解面向对象

前端底蕴进级(9卡塔尔:详整面向对象、构造函数、原型与原型链

2017/04/02 · JavaScript · 1 评论 · 原型, 原型链, 构造函数, 面向对象

初藳出处: 波同学   

澳门太阳娱乐手机登录 1

.

假定要自己总括一下学学前端以来自个儿胜过了怎么瓶颈,那么面向对象一定是首先个马上就办想到的。即便自个儿今后对于面向对象有了有的的了然,然则那个时候的那种似信非信的悲苦,依旧心向往之。

为了帮扶我们能够更为直观的求学和询问面向对象,小编会用尽量简单易懂的叙说来体现面向对象的相干知识。而且也准备了有的实用的事例扶植我们特别飞速的主宰面向对象的真理。

  • jQuery的面向对象达成
  • 卷入拖拽
  • 简易版运动框架封装

那恐怕会花一点时光,可是却值得期望。所以只要风乐趣的爱侣能够来简书和大伙儿号关注自身。

而那篇作品首要来聊风度翩翩聊关于面向对象的片段器重的底子。

Object类型是JavaScript中使用最多的意气风发体系型。创造Object实例的格局有二种,接下去大器晚成一列举。

黄金时代、对象的概念

在ECMAScript-26第22中学,对象被定义为“冬日属性的聚众,其属性能够分包基本值,对象或然函数”

也正是说,在JavaScript中,对象只是便是由局地列无序的key-value对构成。个中value能够是基本值,对象也许函数。

// 这里的person便是四个目的 var person = { name: 'Tom', age: 18, getName: function() {}, parent: {} }

1
2
3
4
5
6
7
// 这里的person就是一个对象
var person = {
    name: 'Tom',
    age: 18,
    getName: function() {},
    parent: {}
}

成立对象

小编们得以因而new的点子创建多个对象。

var obj = new Object();

1
var obj = new Object();

也能够透过对象字面量的款型成立二个轻易易行的指标。

var obj = {};

1
var obj = {};

当大家想要给大家创设的简易对象加多方法时,能够如此表示。

// 能够那样 var person = {}; person.name = "TOM"; person.getName = function() { return this.name; } // 也足以如此 var person = { name: "TOM", getName: function() { return this.name; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 可以这样
var person = {};
person.name = "TOM";
person.getName = function() {
    return this.name;
}
 
// 也可以这样
var person = {
    name: "TOM",
    getName: function() {
        return this.name;
    }
}

访谈对象的属性和措施

假若大家有一个总结的对象如下:

var person = { name: 'TOM', age: '20', getName: function() { return this.name } }

1
2
3
4
5
6
7
var person = {
    name: 'TOM',
    age: '20',
    getName: function() {
        return this.name
    }
}

当咱们想要访谈他的name属性时,能够用如下三种方法访谈。

person.name // 或者 person['name']

1
2
3
4
person.name
 
// 或者
person['name']

万一咱们想要访谈的属性名是四个变量时,平时会使用第三种办法。比如大家要同期做客person的name与age,能够这么写:

['name', 'age'].forEach(function(item) { console.log(person[item]); })

1
2
3
['name', 'age'].forEach(function(item) {
    console.log(person[item]);
})

这种方法势供给注重,记住它现在在大家管理百废待举数据的时候会有十分的大的扶植。

1. Object构造函数

var person = new Object();
person.name = "Brittany";
person.age = 23;
person.job = "web front-end engineer";
person.sayName = function() {
    console.log(this.name);
};
person.sayName();   //Brittany

二、工厂方式

应用方面的法门制造对象很简短,但是在不菲时候并不能够知足我们的急需。就以person对象为例。倘诺我们在骨子里费用中,不仅须要八个名字称为TOM的person对象,同有的时候候还亟需此外三个名叫Jake的person对象,纵然她们有不计其数相通之处,然而大家只可以重新写五次。

var perTom = { name: 'TOM', age: 20, getName: function() { return this.name } }; var perJake = { name: 'Jake', age: 22, getName: function() { return this.name } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var perTom = {
    name: 'TOM',
    age: 20,
    getName: function() {
        return this.name
    }
};
 
var perJake = {
    name: 'Jake',
    age: 22,
    getName: function() {
        return this.name
    }
}

很刚毅那并非客观的章程,当相通对象太多时,我们都会崩溃掉。

我们能够利用工厂方式的法子消除这些标题。看名就能够知道意思,工厂格局正是大家提供二个模型,然后经过这一个模型复制出大家需求的目的。我们须求有个别个,就复制多少个。

var createPerson = function(name, age) { // 声爱他美个此中对象,该对象正是工厂格局的模子 var o = new Object(); // 依次增加大家须求的特性与措施 o.name = name; o.age = age; o.getName = function() { return this.name; } return o; } // 创立八个实例 var perTom= createPerson('TOM', 20); var PerJake = createPerson('Jake', 22);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var createPerson = function(name, age) {
 
    // 声明一个中间对象,该对象就是工厂模式的模子
    var o = new Object();
 
    // 依次添加我们需要的属性与方法
    o.name = name;
    o.age = age;
    o.getName = function() {
        return this.name;
    }
 
    return o;
}
 
// 创建两个实例
var perTom = createPerson('TOM', 20);
var PerJake = createPerson('Jake', 22);

相信上边的代码并不难明白,也不用把工厂情势看得太过宏大上。很鲜明,工厂方式协理大家消除了重新代码上的难为,让我们得以写相当少的代码,就可见创设很三个person对象。可是此地还应该有八个劳苦,须求我们注意。

先是个麻烦正是那样管理,大家一向不主意鉴定分别对象实例的项目。使用instanceof能够识别对象的品种,如下例子:

var obj = {}; var foo = function() {} console.log(obj instanceof Object); // true console.log(foo instanceof Function); // true

1
2
3
4
5
var obj = {};
var foo = function() {}
 
console.log(obj instanceof Object);  // true
console.log(foo instanceof Function); // true

据此在工厂方式的功底上,大家必要动用构造函数的艺术来缓慢解决那几个麻烦。

2. 目的字面量格局

var person = {
    name: "Brittany",
    age: 23,
    job: "web front-end engineer",
    sayName: function() {
        console.log(this.name);
    }
};
person.sayName();

虽说Object构造函数或对象字面量都能够用来创立单个对象,但这么些方式有个肯定的缺欠:使用同二个接口创立超级多对象,会时有发生多量的双重代码。为消灭净尽那个标题,能够动用工厂情势的后生可畏种变体。

三、构造函数

在JavaScript中,new关键字能够让一个函数变得特别。通过下边的事例,大家来风姿罗曼蒂克探new关键字的玄妙之处。

function demo() { console.log(this); } demo(); // window new demo(); // demo

1
2
3
4
5
6
function demo() {
    console.log(this);
}
 
demo();  // window
new demo();  // demo

为了能够直观的心得他们差异,提出我们入手施行观望一下。很扎眼,使用new之后,函数内部产生了生龙活虎部分变通,让this指向退换。那么new关键字到底做了如何工作吗。嗯,其实自个儿事先在篇章里用文字差不离表明了一下new到底干了什么,不过部分校友好奇心很足,总希望用代码完成一下,小编就大致以本身的明白来表述一下啊。

// 先作古正经的创制多少个构造函数,其实该函数与日常函数并无差异 var Person = function(name, age) { this.name = name; this.age = age; this.getName = function() { return this.name; } } // 将构造函数以参数格局传播 function New(func) { // 注解后生可畏(Wissu卡塔 尔(阿拉伯语:قطر‎个个中对象,该目的为末段回到的实例 var res = {}; if (func.prototype !== null) { // 将实例的原型指向构造函数的原型 res.__proto__ = func.prototype; } // ret为构造函数实行的结果,这里透过apply,将构造函数内部的this指向更改为指向res,即为实例对象 var ret = func.apply(res, Array.prototype.slice.call(arguments, 1)); // 当我们在构造函数中分明钦定了回去对象时,那么new的实践结果正是该再次回到对象 if ((typeof ret === "object" || typeof ret === "function") && ret !== null) { return ret; } // 若无鲜明钦赐再次回到对象,则暗中同意再次来到res,那么些res正是实例对象 return res; } // 通过new注脚成立实例,这里的p1,实际收到的正是new中回到的res var p1 = New(Person, 'tom', 20); console.log(p1.getName()); // 当然,这里也足以剖断出实例的类别了 console.log(p1 instanceof Person); // true

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
33
34
35
36
37
38
// 先一本正经的创建一个构造函数,其实该函数与普通函数并无区别
var Person = function(name, age) {
    this.name = name;
    this.age = age;
    this.getName = function() {
        return this.name;
    }
}
 
// 将构造函数以参数形式传入
function New(func) {
 
    // 声明一个中间对象,该对象为最终返回的实例
    var res = {};
    if (func.prototype !== null) {
 
        // 将实例的原型指向构造函数的原型
        res.__proto__ = func.prototype;
    }
 
    // ret为构造函数执行的结果,这里通过apply,将构造函数内部的this指向修改为指向res,即为实例对象
    var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
 
    // 当我们在构造函数中明确指定了返回对象时,那么new的执行结果就是该返回对象
    if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
        return ret;
    }
 
    // 如果没有明确指定返回对象,则默认返回res,这个res就是实例对象
    return res;
}
 
// 通过new声明创建实例,这里的p1,实际接收的正是new中返回的res
var p1 = New(Person, 'tom', 20);
console.log(p1.getName());
 
// 当然,这里也可以判断出实例的类型了
console.log(p1 instanceof Person); // true

JavaScript内部再通过其余的风姿洒脱对非同小可管理,将var p1 = New(Person, 'tom', 20); 等效于var p1 = new Person('tom', 20);。正是大家认知的new关键字了。具体怎么管理的,我也不晓得,别寻根究底了,一直回答下去太难 – -!

老实讲,你大概很难在任哪个地方方看看有那样扎眼的报告您new关键字到底对构造函数干了如何的小说了。了解了这段代码,你对JavaScript的驾驭又比外人浓郁了一分,所以,一本正经臭不要脸求个赞可好?

当然,超级多恋人由于对于日前几篇作品的学识精通非常不够成功,会对new的贯彻表示拾壹分纳闷。可是老实讲,如若你读了自个儿的前边几篇小说,一定会对那边new的兑现成一面如旧的感到到。何况自身这里早就全力以赴做了详实的笺注,剩下的只可以靠你自身了。

可是假使你花点时间,精晓了她的规律,那么麻烦了数不清个人的构造函数中this到底指向何人就变得特别简单了。

为此,为了能够判明实例与对象的关系,我们就选拔构造函数来消除。

var Person = function(name, age) { this.name = name; this.age = age; this.getName = function() { return this.name; } } var p1 = new Person('Ness', 20); console.log(p1.getName()); // Ness console.log(p1 instanceof Person); // true

1
2
3
4
5
6
7
8
9
10
11
12
var Person = function(name, age) {
    this.name = name;
    this.age = age;
    this.getName = function() {
        return this.name;
    }
}
 
var p1 = new Person('Ness', 20);
console.log(p1.getName());  // Ness
 
console.log(p1 instanceof Person); // true

关于构造函数,假诺你这两天不可见明白new的具体得以达成,就先记住上边那多少个结论吧。

  • 与平时函数比较,构造函数并未其他特别的地点,首字母大写只是大家约定的小规定,用于区分普通函数;
  • new关键字让构造函数具备了与平常函数差异的不在少数特点,而new的长河中,实施了如下进度:
    1. 宣示贰当中间对象;
    2. 将该中间对象的原型指向构造函数的原型;
    3. 将构造函数的this,指向该中间对象;
    4. 重临该中间对象,即重临实例对象。

3. 厂子形式 

function createPerson(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        console.log(this.name);
    };
    return o;
}

var person1 = createPerson("Brittany", 23, "Software Engineer");
var person2 = createPerson("Sam", 26, "Software Engineer");
console.log(typeof person1);   //Object

厂子格局纵然缓和了创办多少个平日对象的难点,但却从没化解对象识其余难点(即怎么样了然三个对象的体系卡塔 尔(英语:State of Qatar)。如代码中只可以检验出person1为Object类型。随着JavaScript的开采进取,又二个新格局现身了。

四、原型

固然如此构造函数解决了判定实例类型的主题素材,可是,聊起底,依旧多个指标的复制进程。跟工厂情势颇具相同的地方。也正是说,当大家申明了九二十一个person对象,那么就有97个getName方法被再度生成。

那边的每叁个getName方法完成的意义实乃大同小异的,不过由于个别归属差别的实例,就必须要直接不停的为getName分配空间。那正是工厂情势存在的第二个辛勤。

分明这是不创设的。大家希望的是,既然都是兑现同二个效果与利益,那么能还是不能就让每二个实例对象都访谈同叁个主意?

理之当然能,那就是原型对象要帮大家消释的主题材料了。

咱俩创造的每五个函数,都得以有一个prototype属性,该属性指向二个目的。那些目标,正是我们这里说的原型。

当我们在成立对象时,能够依据本身的急需,接受性的将一些质量和方法通过prototype属性,挂载在原型对象上。而每二个new出来的实例,都有三个__proto__质量,该属性指向构造函数的原型对象,通过那天性情,让实例对象也能够访谈原型对象上的法子。因而,当全部的实例都能够通过__proto__做客到原型对象时,原型对象的诀要与质量就形成了共有方法与品质。

大家通过七个简约的例证与图示,来打探构造函数,实例与原型三者之间的关系。

出于每一种函数都足以是构造函数,各样对象都能够是原型对象,由此假若在精晓原型之初就想的太多太复杂的话,反而会阻碍你的理解,这里我们要学会先简化它们。就单单的分析那三者的涉及。

// 注脚构造函数 function Person(name, age) { this.name = name; this.age = age; } // 通过prototye属性,将艺术挂载到原型对象上 Person.prototype.getName = function() { return this.name; } var p1 = new Person('tim', 10); var p2 = new Person('jak', 22); console.log(p1.getName === p2.getName); // true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 声明构造函数
function Person(name, age) {
    this.name = name;
    this.age = age;
}
 
// 通过prototye属性,将方法挂载到原型对象上
Person.prototype.getName = function() {
    return this.name;
}
 
var p1 = new Person('tim', 10);
var p2 = new Person('jak', 22);
console.log(p1.getName === p2.getName); // true

澳门太阳娱乐手机登录 2

图示

经过图示大家得以旁观,构造函数的prototype与具备实例对象的__proto__都针对原型对象。而原型对象的constructor指向构造函数。

除却,还是能从图中看出,实例对象实际对眼下我们所说的高级中学级对象的复制,而中等对象中的属性与艺术都在构造函数中加多。于是根据构造函数与原型的特征,我们就可以将要构造函数中,通过this注解的习性与办法称为私有变量与办法,它们被前段时间被某四个实例对象所独有。而由此原型申明的属性与艺术,我们可以称之为共有属性与格局,它们得以被有着的实例对象访谈。

当大家访谈实例对象中的属性或然措施时,会优先访谈实例对象自笔者的特性和议程。

function Person(name, age) { this.name = name; this.age = age; this.getName = function() { console.log('this is constructor.'); } } Person.prototype.getName = function() { return this.name; } var p1 = new Person('tim', 10); p1.getName(); // this is constructor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.getName = function() {
        console.log('this is constructor.');
    }
}
 
Person.prototype.getName = function() {
    return this.name;
}
 
var p1 = new Person('tim', 10);
 
p1.getName(); // this is constructor.

在此个事例中,我们同不平时间在原型与构造函数中都宣示了一个getName函数,运维代码的结果表示原型中的访谈并从未被访谈。

我们还是可以够透过in来剖断,三个目的是不是享有某叁性子质/方法,无论是该属性/方法存在与实例对象依然原型对象。

function Person(name, age) { this.name = name; this.age = age; } Person.prototype.getName = function() { return this.name; } var p1 = new Person('tim', 10); console.log('name' in p1); // true

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name, age) {
    this.name = name;
    this.age = age;
}
 
Person.prototype.getName = function() {
    return this.name;
}
 
var p1 = new Person('tim', 10);
 
console.log('name' in p1); // true

in的这种特征最常用的情景之风流罗曼蒂克,便是判定当前页面是还是不是在活动端张开。

isMobile = 'ontouchstart' in document; // 非常多人喜欢用浏览器UA的章程来剖断,但并不是很好的措施

1
2
3
isMobile = 'ontouchstart' in document;
 
// 很多人喜欢用浏览器UA的方式来判断,但并不是很好的方式

更简便的原型写法

依据前面例子的写法,假若大家要在原型上增添越来越多的点子,能够如此写:

function Person() {} Person.prototype.getName = function() {} Person.prototype.getAge = function() {} Person.prototype.sayHello = function() {} ... ...

1
2
3
4
5
6
function Person() {}
 
Person.prototype.getName = function() {}
Person.prototype.getAge = function() {}
Person.prototype.sayHello = function() {}
... ...

除此之外,我还足以行使越来越简易的写法。

function Person() {} Person.prototype = { constructor: Person, getName: function() {}, getAge: function() {}, sayHello: function() {} }

1
2
3
4
5
6
7
8
function Person() {}
 
Person.prototype = {
    constructor: Person,
    getName: function() {},
    getAge: function() {},
    sayHello: function() {}
}

这种字面量的写法看上去大致超级多,不过有八个急需特别注意的地点。Person.prototype = {}实际上是重新创制了一个{}对象并赋值给Person.prototype,这里的{}而不是先前时代的极度原型对象。由此它此中并不含有constructor本性。为了保障科学,我们必须要在新创制的{}对象中展现的安装constructor的指向性。即上边的constructor: Person

4. 构造函数情势

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
        console.log(this.name);
    }    
}
var person1 = new Person("Brittany", 23, "Web front-end engineer");
var person2 = new Person("Closure", 26, "Manager");
person1.sayName();
person2.sayName();
console.log(person1.sayName == person2.sayName);   //false

接收构造函数的最首要难点:每个方法都要在种种实例上海重机厂复成立三次。如代码中所示,person1的sayName和person2的sayName不对等。能够将函数定义转移到构造函数外界来缓和。

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;
}
function sayName() {
    console.log(this.name);
}

sayName函数的定义转移到了构造函数外界。而在构造函数内部,大家将sayName属性设置成等于全局的sayName函数。那样一来,由于sayName包括的是三个指向性函数的指针,因而person1和person2对象就分享了在全局功能域中定义的同多个sayName()函数。那着实消逝了七个函数做同样件事的难点,不过新主题素材又来了:在大局作用域中定义的函数实际上只可以被某些对象调用,那让全局效率域有一些鱼目混珠。而更让让人不能选择的是:假设须求定义超级多办法,那就要定义很三个全局函数,于是这几个自定义的引用类型就无封装性可言。这个主题材料可经过应用原型方式来消除。

四、原型链

原型对象实际也是惯常的对象。差相当少全数的指标都大概是原型对象,也说不佳是实例对象,况且还是能何况是原型对象与实例对象。那样的四个目的,便是结合原型链的叁个节点。因而通晓了原型,那么原型链并不是一个多么复杂的定义。

我们掌握全体的函数都有三个称为toString的法子。那么那一个措施到底是在何地的吧?

先随机声爱他美个函数:

function foo() {}

1
function foo() {}

那正是说大家得以用如下的图来表示这一个函数的原型链。

澳门太阳娱乐手机登录 3

原型链

里面foo是Function对象的实例。而Function的原型对象同不经常候又是Object的实例。那样就组成了一条原型链。原型链的寻访,其实跟功能域链有非常大的相同之处,他们都以一回单向的搜求进度。因而实例对象能够由此原型链,访谈到地处原型链上对象的具备属性与办法。那也是foo最终能够访谈到地处Object原型对象上的toString方法的原因。

基于原型链的性子,大家得以很自在的落到实处澳门太阳娱乐手机登录,继承

5. 原型格局

五、继承

大家平常结合构造函数与原型来创设三个对象。因为构造函数与原型的不相同风味,分别解决了大家不一致的忧愁。由此当大家想要完结三番五次时,就必须要得依据构造函数与原型的不等而采取差别的国策。

笔者们声美素佳儿(Friso卡塔 尔(英语:State of Qatar)个Person对象,该对象将用作父级,而子级cPerson将在接二连三Person的兼具属性与方法。

function Person(name, age) { this.name = name; this.age = age; } Person.prototype.getName = function() { return this.name; }

1
2
3
4
5
6
7
8
function Person(name, age) {
    this.name = name;
    this.age = age;
}
 
Person.prototype.getName = function() {
    return this.name;
}

率先我们来看构造函数的持续。在地点我们早就精晓了构造函数的面目,它实乃在new内部完结的三个复制进度。而大家在继续时想要的,就是想父级构造函数中的操作在子级的构造函数中再次出现三回就能够。我们得以透过call方法来到达指标。

// 构造函数的后续 function cPerson(name, age, job) { Person.call(this, name, age); this.job = job; }

1
2
3
4
5
// 构造函数的继承
function cPerson(name, age, job) {
    Person.call(this, name, age);
    this.job = job;
}

而原型的一而再,则只要求将子级的原型对象设置为父级的多少个实例,到场到原型链中就可以。

// 世袭原型 cPerson.prototype = new Person(name, age); // 增多更加的多情势cPerson.prototype.getLive = function() {}

1
2
3
4
5
// 继承原型
cPerson.prototype = new Person(name, age);
 
// 添加更多方法
cPerson.prototype.getLive = function() {}

澳门太阳娱乐手机登录 4

原型链

自然关于一而再接二连三还应该有更加好的措施,这里就不做深切介绍了,以往有空子再详尽解读呢。

1卡塔尔对象创造 

function Person() {}
Person.prototype.name = "Brittany";
Person.prototype.age = 23;
Person.prototype.job = "Web front-end engineer";
Person.prototype.getName = function() {
    console.log(this.name);
};
var p1 = new Person();
var p2 = new Person();

console.log(p1.name);                    //Brittany
console.log(p2.name);                    //Brittany
console.log(p1.getName == p2.getName);   //true

实例中开创的属性会覆盖原型中的同名属性,不能改改原型中的属性。

p1.name = "Susan";
console.log(p1.name);                    //Susan

hasOwnProperty()检查评定壹特性质是还是不是留存于实例中。

console.log(p2.hasOwnProperty("name"));  //false
p2.name = "koko";
console.log(p2.hasOwnProperty("name"));  //true
delete p2.name;
console.log(p2.hasOwnProperty("name"));  //false

isPropertyOf()

console.log(Person.prototype.isPrototypeOf(p1));   //true
console.log(Person.prototype.isPrototypeOf(p2));   //true

getPropertyOf()

console.log(Object.getPrototypeOf(p1) == Person.prototype);  //true
console.log(Object.getPrototypeOf(p1));                      //Person

六、总结

至于面向对象的幼功知识差相当少正是这个了。作者从最简易的创制叁个对象初阶,解释了干吗我们须求构造函数与原型,驾驭了那其间的细节,有支持大家在实质上支出中灵活的集体团结的目的。因为我们并不是负有的场景都会动用构造函数也许原型来创立对象,可能大家需求的对象并不会申明四个实例,恐怕不用区分对象的品类,那么大家就可以选择更简便的办法。

咱俩还须要关怀构造函数与原型的分级特点,有利于大家在创立对象时精确的论断大家的性质与办法到底是坐落构造函数中或然放在原型中。若无精晓精通,那会给大家在实际上开辟中程导弹致比一点都不小的干扰。

最后接下去的几篇小说,作者会挑几个面向对象的例证,继续协助大家精通面向对象的实际上接受。

2 赞 4 收藏 1 评论

澳门太阳娱乐手机登录 5

2)原型与in操作符

in单独行使时,通过对象访谈到特定属性时回来true,无论该属性存在于实例中仍旧原型中。hasOwnProperty(),通过对象访谈到特定属性时回来true,且该属性存在于实例中。 

var p3 = new Person();
console.log("name" in p3);                //true
console.log(p3.hasOwnProperty("name"));   //false
p3.name = "insist";
console.log(p3.hasOwnProperty("name"));   //true

规定属性到底是存在于对象中,如故存在于原型中。如下函数hasPrototypePropery()再次回到true表示该属性存在于原型中,实际不是存在于实例中。

function hasPrototypeProperty(object, name) {
    return !hasOwnProperty("name") && (name in object);
}

for..in循环,全部通过对象可以采访的,可枚举的(enumerated卡塔尔国属性,既包罗存在于实例中的属性,也囊括存在于原型中的属性。

for(var prop in p1) {
    console.log(prop);                    //name age job sayName
}

Object.keys(),ECMAScript5的办法,得到对象上全体可枚举的天性,选择三个目的作为参数,重临值是三个包括全部可枚举属性的字符串数组。注意:Person.prototype也是指标。

var keys = Object.keys(Person.prototype);
console.log(keys);             //["name age job sayName"]
var p1 = new Person(); 
console.log(Object.keys(p1));  //[]
p1.name = "get";
console.log(Object.keys(p1));  //["name"]

Object.getOwnPropertyNames(),得到全体实例属性,无论它是否可枚举。

var keys = Object.getOwnPropertyNames(Person.prototype);
console.log(keys);     //["constructor", "name", "age", "job", "getName"] 
var keys_p1 = Object.getOwnPropertyNames(p1);
console.log(keys_p1);  //[]

3)更简洁的原型语法

function Person() {}
Person.prototype = {
    name: "Brittany",
    age: 23,
    job: "Web front-end engineer",
    getName: function() {
        return this.name;
    }
};
var friend = new Person();
console.log(friend instanceof Person);      //true
console.log(friend instanceof Object);      //true
console.log(friend.constructor == Person);  //false
console.log(friend.constructor == Object);  //false

在上头的代码中,将Person.prototype设置为等于一个指标字面量格局创造的新对象,最后结果相符。但有一个两样:constructor属性不再指向Person了。每创造叁个函数,就能够同一时间创造它的prototype对象,那么些目的也会自动获取constructor属性。而小编辈在那处运用的语法,本质上完全重写了暗许的prototype对象,由此constructor属性也就改成了新对象的constructor属性(指向Object构造函数卡塔 尔(阿拉伯语:قطر‎,不再指向Person函数。那个时候固然instanceof操作符还是可以够重返精确的结果,但通过constructor已经江淹梦笔鲜明目的的类型了。

透过如下形式,将constructor手动设置为适当的值。

Person.prototype = {
    constructor: Person,
    name: "Brittany",
    age: 23,
    job: "Web front-end engineer",
    getName: function() {
        console.log(this.name);
    }
};

4卡塔 尔(阿拉伯语:قطر‎原型的动态性

在原型中查找值的进程是一次搜索,因而我们对原型对象所做的其余改进都能够立时从实例上反映出去——即便是先创设了实例后纠正原型也依旧如此。

var friend = new Person();
Person.prototype.sayHi = function() {
    console.log("hi");
};
friend.sayHi();

固然能够每三日为原型增添属性和格局,而且改正能够立即在有着目标实例中反映出去,但大器晚成旦是重写整个原型对象,情形就不相似了。

function Person() {}
var friend = new Person();
Person.prototype = {
    constructor: Person,
    name: "Brittany",
    age: 23,
    job: "Web front-end engineer",
    getName: function() {
        console.log(this.name);
    }
};
friend.getName();                  //error

假设创设实例放在重写原型对象之后,则不会报错。

5卡塔尔国原生对象的原型

富有原生引用类型(Object、Array、String卡塔 尔(英语:State of Qatar)都在其构造函数的原型上定义了点子,如:Array.prototype.sort()、String.prototype.subString(), 通过原生对象的原型能够获取富有暗许方法的引用,并能够定义新艺术。

console.log(typeof Array.prototype.sort);        //function
console.log(typeof String.prototype.substring);  //function

String.prototype.startsWith = function(text) {
    return this.indexOf(text) == 0;
};
var msg = "Hello World";
console.log(msg.startsWith("Hello"));           //true

6卡塔尔国原型对象的标题

缺陷风度翩翩:省略了为构造函数字传送递开首化参数那大器晚成环节,结果有所实例在私下认可景况下将得到风流倜傥致的属性值。

劣势二:原型中具备属性被比很多实例分享,这种共享对于函数特别切合。对于饱含基本值属性倒也说得过去,因为通过在实例上增加叁个同名属性,能够隐瞒原型中对应的属性。但对于包蕴引用类型值得属性来讲,难点相比非凡。

function Person() { }
Person.prototype = {
    constructor: Person,
    name: "Brittany",
    friends: ["pink", "judy", "sam"],
    age: 23,
    job: "Web front-end engineer",
    getName: function() {
        console.log(this.name);
    }
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("leo");
console.log(person1.friends);           //["pink", "judy", "sam", "leo"]
console.log(person2.friends);           //["pink", "judy", "sam", "leo"]
console.log(Person.prototype.friends);  //["pink", "judy", "sam", "leo"]
person1.age = 35;
console.log(person1.age);           //35
console.log(person2.age);           //23
console.log(Person.prototype.age);  //23

person1的friends属性改革影响了person2的friends,不过person1的age属性校订并未有影响person2的age属性。

由来在于:friends数组存在于Person.prototype中而非person第11中学,因而订正也会由此person2.friends(与person1.friends指向同一个数组卡塔 尔(阿拉伯语:قطر‎反映出去。而age属性在person第11中学也设有黄金年代份,修正的age属性只是改善person1中的,并不能够改正Person.prototype中的age属性。

6. 整合使用构造函数情势和原型情势

构造函数形式用于定义实例属性,而原型方式用于定义方法和分享的天性。那样,每一种实例都会有本人的风华正茂份实例属性的副本,但又同时分享着对章程的引用。

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["aa", "bb", "cc"];
}
Person.prototype = {
    constructor: Person,
    sayName: function() {
        console.log(this.name);
    }
};
var person1 = new Person("Brittany", 23, "Web front-end Engineer");
person1.friends.push("dd");     //["aa", "bb", "cc", "dd"]
console.log(person1.friends);
var person2 = new Person("Sam", 26, "Web front-end Engineer");
console.log(person2.friends);   //["aa", "bb", "cc"]
console.log(person1.friends == person2.friends);  //false
console.log(person1.sayName == person2.sayName);  //true

 

 

时间:2014-10-21

地点:合肥

援用:《JavaScript高等程序设计》 

本文由澳门太阳娱乐手机登录发布于公司简介,转载请注明出处:对象的创建,详解面向对象

关键词: