JS的Object类的属性、方法及咋样制造对象

属性

  constructor:对创设对象的函数的引用(指针)。对于Object类,该指针指向原始的object()函数。

  prototype:对该目的的目标原型的引用。对于具有的类,它默认重返Object对象的一个实例。

方法

  hasOwnProperty(property):判断目的是否有某个特定的性质。必须用字符串指定该属性(例如,o.hasOwnProperty(”name”))。

  isPrototypeOf(object):判断该对象是不是为另一个对象的原型。

  propertyIsEnumerable(property):判断给定的习性是否足以用for….in语句举行枚举

  toString():再次来到对象的原始字符串表示。对于Object类,ECMA-262未曾定于那么些值,所以不同的ECMASCRIPT实现所有不同的值

  valueOf():再次回到最契合该对象的原值。对于需对类,该情势重临的值都与toString()的再次回到值相同

javascript创立对象

创办一个对象,然后给那多少个目标新建属性和章程。

var box = new Object();//创建一个 Object 对象

box.name = 'Lee';//创建一个 name 属性并赋值

box.age = 100;//创建一个 age 属性并赋值

box.run = function () {//创建一个 run()方法并返回值

  return this.name + this.age + '运行中...';

};

alert(box.run());//输出属性和方法的值

 

地方创设了一个目的,并且创办属性和方法,在 run()方法里的 this,就是意味
box 对象自我。这种是 JavaScript
创建对象最基本的法门,但有个毛病,想成立一个看似的目的,就会生出大量的代码。

var box2 = box;//得到 box 的引用
box2.name = 'Jack';//直接改变了 name 属性
alert(box2.run()); //用 box.run()
发现 name 也改变了
var box2 = new Object();
box2.name = 'Jack';
box2.age = 200;
box2.run = function () {
  return this.name + this.age + '运行中...';
};
alert(box2.run());//这样才避免和 box 混淆,从而保持独立 
为了解决多个类似对象声明的问题,我们可以使用一种叫做工厂模式的方法,这种方法就是为了解决实例化对象产生大量重复的问题。
 function createObject(name, age) {//集中实例化的函数
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function () {
  return this.name + this.age + '运行中...';
};
return obj;
}
var box1 = createObject('Lee', 100);
var box2 = createObject('Jack', 200);
alert(box1.run()); alert(box2.run()); //第一个实例 //第二个实例 //保持独立

 工厂模式解决了再次实例化的问题,但还有一个问题,这就是识别问题,因为根本不能够搞了然他们究竟是哪位目的的实例。

alert(typeof box1);//Object
alert(box1 instanceof Object);//true

ECMAScript 中得以应用构造函数(构造方法)可用来创立特定的靶子。类型于
Object 对象。

function Box(name, age) {//构造函数模式
this.name = name;
this.age = age;
this.run = function () {
   return this.name + this.age + '运行中...';
};
}
var box1 = new Box('Lee', 100);
var box2 = new Box('Jack', 200); //new Box()
alert(box1.run());
alert(box1 instanceof Box); //很清晰的识别他从属于 Box

 使用构造函数的格局,即解决了再次实例化的题目,又化解了对象识其余问题,但问题是,这里并没有
new Object(),为何可以实例化
Box(),那些是哪个地方来的吧?使用了构造函数的主意,和接纳工厂形式的法门他们不同之处如下:

1.构造函数方法没有出示的成立对象(new Object());

2.平素将性能和形式赋值给 this 对象;

3.没有 renturn 语句。

构造函数的法子有部分专业:

1.函数名和实例化构造名相同且大写,(PS:非强制,但诸如此类写有助于区分构造函数和
普通函数);

2.透过构造函数创建对象,必须运用 new 运算符。
既然经过构造函数可以成立对象,那么这么些目的是何地来的,new
Object()在怎么地方执行了?执行的进程如下:

1.当运用了构造函数,并且 new 构造函数(),那么就后台执行了 new Object();

2.将构造函数的功效域给新目的,(即 new
Object()成立出的靶子),而函数体内的 this 就意味着 new Object()出来的目的。

3.实践构造函数内的代码;

4.重临新对象(后台平素再次来到)。

有关 this 的行使,this 其实就是代表当前功用域对象的引用。倘使在全局范围
this 就表示 window
对象,假使在构造函数体内,就象征当前的构造函数所讲明的靶子。

var box = 2; alert(this.box);//全局代表
window构造函数和普通函数的唯一区别,就是他们调用的方式不同。只不过,构造函数也是函数,必须用 new 运算符来调用,否则就是普通函数。
var box = new Box('Lee', 100);//构造模式调用
alert(box.run());
Box('Lee', 20);
var o = new Object();
Box.call(o, 'Jack', 200) alert(o.run()); //普通模式调用,无效 //对象冒充调用

 琢磨构造函数内部的办法(或函数)的问题,首先看下六个实例化后的性质或艺术是否等于。

var box1 = new Box('Lee', 100);//传递一致
var box2 = new Box('Lee', 100);//同上
alert(box1.name == box2.name);//true,属性的值相等
alert(box1.run == box2.run);//false,方法其实也是一种引用地址
alert(box1.run() == box2.run());//true,方法的值相等,因为传参一致

 可以把构造函数里的章程(或函数)用 new
Function()方法来取代,得到平等的效用,更加证实,他们最终判断的是引用地址,唯一性。

function Box(name, age) {//new Function()唯一性
  this.name = name;
  this.age = age;
  this.run = new Function("return this.name + this.age + '运行中...'");
}

咱俩可以通过构造函数外面绑定同一个函数的点子来保证引用地址的一致性,但那种做法没什么必要,只是加重学习明白:

function Box(name, age) {
  this.name = name;
  this.age = age;
  this.run = run;
}
function run() {//通过外面调用,保证引用地址一致
  return this.name + this.age + '运行中...';
}

即便采纳了大局的函数
run()来解决了确保引用地址一样的题材,但这种格局又带来了一个新的问题,全局中的
this 在对象调用的时候是 Box 本身,而作为普通函数调用的时候,this 又表示
window。

原型 我们创立的每个函数都有一个
prototype(原型)属性,这么些特性是一个目标,它的用途是带有可以由特定类型的装有实例共享的性能和格局。

逻辑上得以这样领会:prototype
通过调用构造函数而创办的分外目的的原型对象。使用原型的便宜可以让所有目标实例共享它所包含的特性和办法。也就是说,不必在构造函数中定义对象信息,而是可以一贯将这些消息添加到原型中。

function Box() {}//声明一个构造函数
Box.prototype.name = 'Lee';
Box.prototype.age = 100;
Box.prototype.run = function () {
  return this.name + this.age + '运行中...';
};

相比一下原型内的办法地址是否同样:

var box1 = new Box(); //在原型里添加属性 //在原型里添加方法
var box2 = new Box();
alert(box1.run == box2.run); //true,方法的引用地址保持一致

在原型情势评释中,多了六个特性,这几个特性都是创立对象时自动生成的。__proto__性能是实例指向原型对象的一个指针,它的功效就是指向构造函数的原型属性
constructor。通过这三个特性,就可以访问到原型里的属性和格局了。PS:IE
浏览器在剧本访问__proto__会不可能分辨,火狐和Google浏览器及此外某些浏览器均能鉴别。即使可以输出,但无能为力获取内部音讯。

alert(box1.__proto__);//[object Object]

看清一个对象是不是针对了该构造函数的原型对象,能够行使
isPrototypeOf()方法来测试。

alert(Box.prototype.isPrototypeOf(box));

若果实例化对象,即都会指向 原型形式的履行流程:

1.先查找构造函数实例里的性能或模式,假设有,立即回去;

2.只要构造函数实例里不曾,则去它的原型对象里找,即使有,就回到;
固然我们得以经过对象实例访问保存在原型中的值,但却不能够访问通过对象实例重写原型中的值。

var box1 = new Box(); alert(box1.name);//Lee,原型里的值
box1.name = 'Jack'; alert(box.1name);//Jack,就近原则,
var box2 = new Box(); alert(box2.name); //Lee,原型里的值,没有被 box1 修改

万一想要 box1
也能在前面继续访问到原型里的值,可以把构造函数里的习性删除即可,具体如下:

delete box1.name;//删除属性 alert(box1.name);

如何判断属性是在构造函数的实例里,如故在原型里?可以接纳hasOwnProperty()函数来阐明:

alert(box.hasOwnProperty('name'));//实例里有返回 true,否则返回 false

构造函数实例属性和原型属性,in 操作符会在经过对象可以访问给定属性时重临true,无论该属性存在于实例中仍旧原型中。

alert('name' in box);//true,存在实例中或原型中

我们得以经过
hasOwnProperty()hasOwnProperty()方法检测属性是否存在实例中,也可以由此in
来判定实例或原型中是否存在属性。那么结合这三种办法,可以看清原型中是否留存属性。

function isProperty(object, property) {//判断原型中是否存在属性
   return !object.hasOwnProperty(property) && (property in object);

}
var box = new Box();
alert(isProperty(box, 'name')) //true,如果原型有 [/task] 为了让属性和方法更好的体现封装的效果,并且减少不必要的输入,原型的创建可以使用字面量的方式:
function Box() {};
  Box.prototype = {//使用字面量的方式
  name : 'Lee', age : 100, run : function () {
    return this.name + this.age + '运行中...';
  }
};  

运用构造函数成立原型对象和行使字面量成立对象在动用上基本相同,但依然有部分有别于,字面量创建的不二法门采取constructor 属性不会针对实例,而会针对
Object,构造函数创制的方法则相反。

var box = new Box();
alert(box instanceof Box);
alert(box instanceof Object);
alert(box.constructor == Box);//字面量方式,返回 false,否则,true
alert(box.constructor == Object);//字面量方式,返回 true,否则,false 

假若想让字面量格局的 constructor 指向实例对象,那么可以如此做:

Box.prototype = {
   constructor : Box,//直接强制指向即可
};

 PS:字面量情势为何 constructor 会指向 Object?因为
Box.prototype={};这种写法其实就是创制了一个新对象。而每成立一个函数,就会同时创设它
prototype,这多少个目的也会自动得到 constructor 属性。所以,新对象的
constructor 重写了 Box 原来的
constructor,因而会针对新对象,这一个新对象没有点名构造函数,那么就默认为
Object。原型的宣示是有先后顺序的,所以,重写的原型会切断以前的原型。

 function Box() {};
Box.prototype = {
constructor : Box, name : 'Lee', age : 100, //原型被重写了
run : function () {
   return this.name + this.age + '运行中...';
}
};
Box.prototype = { age = 200 };
var box = new Box();
alert(box.run()); //在这里声明 //box 只是最初声明的原型

原型对象不仅可以在自定义对象的意况下使用, ECMAScript
内置的引用类型都可而以使用这种办法,并且放置的引用类型我也使用了原型。

alert(Array.prototype.sort);//sort 就是 Array 类型的原型方法
alert(String.prototype.substring);//substring 就是 String 类型的原型方法
String.prototype.addstring = function () {
  return this + ',被添加了!';
};
alert('Lee'.addstring()); //给 String 类型添加一个方法 //this 代表调用的字符串 //使用这个方法

 PS:即使给原生的放权引用类型充分方法应用起来特别有益,但我们不引进使用这种措施。因为它可能会导致命名争执,不便宜代码维护。
原型格局成立对象也有投机的弱项,它大概了构造函数传参最先化这一历程,带来的败笔就是最先化的值都是一模一样的。而原型最大的老毛病就是它最大的独到之处,这就是共享。原型中具备属性是被不少实例共享的,共享对于函数非常确切,对于富含基本值的习性也还足以。但一旦属性包含引用类型,就存在必然的问题:

function Box() {};
Box.prototype = {
  constructor : Box, name : 'Lee', age : 100, family : ['父亲', '母亲', '妹妹'],//添加了一个数组属性
  run : function () { return this.name + this.age + this.family; }
};
var box1 = new Box();
box1.family.push('哥哥');
alert(box1.run());
var box2 = new Box();
alert(box2.run()); //在实例中添加'哥哥' //共享带来的麻烦,也有'哥哥'了

PS:数据共享的因由,导致成千上万开发者放任选择原型,因为每一遍实例化出的数码需要保留自己的特色,而不可以共享。为了化解协会传参和共享问题,可以组合构造函数+原型情势

function Box(name, age) {//不共享的使用构造函数
   this.name = name; this.age = age; this. family = ['父亲', '母亲', '妹妹'];
};
Box.prototype = {//共享的使用原型模式
  constructor : Box, run : function () {
     return this.name + this.age + this.family;
   }
};

PS:那种混合情势很好的缓解了传参和引用共享的大难题。是创立对象相比较好的章程。原型形式,不管您是否调用了原型中的共享方法,它都会初步化原型中的方法,并且在宣称一个目的时,构造函数+原型部分让人感觉又很奇幻,最好就是把构造函数和原型封装到一道。为了缓解这么些问题,大家可以运用动态原型情势。

function Box(name ,age) {//将所有信息封装到函数体内
this.name = name; this.age = age;
   if (typeof this.run != 'function') {//仅在第一次调用的初始化
    Box.prototype.run = function () {
       return this.name + this.age + '运行中...';
      };
   }
}
var box = new Box('Lee', 100);
alert(box.run());

 当第一次调用构造函数时,run()方法发现不设有,然后起始化原型。当第二次调用,就不会先导化,并且第二次制造新目的,原型也不会再开头化了。这样及取得了打包,又实现了原型方法共享,并且属性都保持独立。

if (typeof this.run != 'function') {
  alert('第一次初始化');//测试用
  Box.prototype.run = function () {
    return this.name + this.age + '运行中...';
  };
}
var box = new Box('Lee', 100);
alert(box.run());
alert(box.run());
var box2 = new Box('Jack', 200);
alert(box2.run());
alert(box2.run()); //第一次创建对象 //第一次调用 //第二次调用 //第二次创建对象

PS:使用动态原型格局,要专注一点,不可以再利用字面量的章程重写原型,因为会切断实例和新原型之间的关联。以上讲解了各类方法对象创设的不二法门,即便这三种模式都不可以知足急需,可以使用一始发这种格局:寄生构造函数。

function Box(name, age) {
  var obj = new Object();
  obj.name = name;
  obj.age = age;
  obj.run = function () {
    return this.name + this.age + '运行中...';
  };
   return obj;
}

寄生构造函数,其实就是工厂格局+构造函数格局。这种形式比较通用,但不能确定目的关联,所以,在可以应用在此之前所说的情势时,不提议拔取此情势。在什么样情形下采用寄生构造函数相比较适度呢?假诺要创设一个装有额外措施的引用类型。由于事先表达不提议直接String.prototype.addstring,可以透过寄生社团的办法丰裕。

function myString(string) {
   var str = new String(string);
   str.addstring = function () {
    return this + ',被添加了!';
  };
  return str;
}
var box = new myString('Lee'); alert(box.addstring()); //比直接在引用原型添加要繁琐好多

在有的康宁的条件中,比如禁止选择 this 和 new,这里的 this
是构造函数里不行使 this,这里的 new 是在外部实例化构造函数时不使用
new。这种创制形式叫做稳妥构造函数。

function Box(name , age) {
  var obj = new Object();
  obj.run = function () {
     return name + age + '运行中...';//直接打印参数即可
   };
  return obj;
}
var box = Box('Lee', 100); alert(box.run());

PS:稳妥构造函数和寄生类似。 继承 继承是面向对象中一个比较基本的定义。其他标准面向对象语言都会用二种办法贯彻持续:一个是接口实现,一个是延续。而
ECMAScript 只襄助继承,不补助接口实现,而实现连续的不二法门依靠原型链完成。

function Box() {
  this.name = 'Lee';
}

function Desk() {
  this.age = 100;
}
Desk.prototype = new Box();
var desk = new Desk();
alert(desk.age);
alert(desk.name);
function Table(){ 
this.level = 'AAAAA';
}
Table.prototype = new Desk();
var table = new Table();
alert(table.name); //Box 构造 //直接调用函数 //Desk 构造 //Desc 继承了 Box,通过原型,形成链条 //得到被继承的属性 //Table 构造 //继续原型链继承 //继承了 Box 和 Desk

 原型链继承流程图

图片 1

倘诺要实例化 table,那么 Desk 实例中有 age=100,原型中追加相同的特性
age=200, 最终结果是不怎么啊?

Desk.prototype.age = 200;//实例和原型中均包含 age

 PS:以上原型链继承还不够一环,这就是 Obejct,所有的构造函数都继承自
Obejct。而持续 Object
是半自动完成的,并不需要程序员手动继承。经过持续后的实例,他们的隶属关系会怎么呢?

alert(table instanceof Object);//true
alert(desk instanceof Table);//false,desk 是 table 的超类
alert(table instanceof Desk);//true
alert(table instanceof Box);//true

在 JavaScript
里,被延续的函数称为超类型(父类,基类也行,其他语言叫法),继承的函数称为子类型(子类,派生类)。继承也有在此之前问题,比如字面量重写原型会中断关系,使用引用类型的原型,并且子类型还不能够给超类型传递参数。为了化解引用共享和超类型无法传参的题目,大家利用一种叫借用构造函数的技术,或者成为目的冒充(伪造对象、经典延续)的技巧来化解这二种问题。

function Box(age) {
  this.name = ['Lee', 'Jack', 'Hello'] this.age = age;
}
function Desk(age) {
   Box.call(this, age); //对象冒充,给超类型传参
}
var desk = new Desk(200);
alert(desk.age);
alert(desk.name);
desk.name.push('AAA');
alert(desk.name); //添加的新数据,只给 desk

借用构造函数即使缓解了刚刚三种问题,但绝非原型,复用则无从谈起。所以,我们需要原型链+借用构造函数的格局,这种形式变成构成继承

function Box(age) {
   this.name = ['Lee', 'Jack', 'Hello'] this.age = age;
}
Box.prototype.run = function () {
  return this.name + this.age;
};
function Desk(age) {
  Box.call(this, age);
}
Desk.prototype = new Box();
var desk = new Desk(100);
alert(desk.run()); //对象冒充 //原型链继承

再有一种持续形式叫做:原型式继承;这种持续借助原型并依照已有些对象创设新目的,同时还不用为此创制自定义类型。

function obj(o) {//传递一个字面量函数
   function F() {}//创建一个构造函数
  F.prototype = o;//把字面量函数赋值给构造函数的原型
  return new F();//最终返回出实例化的构造函数
}
var box = { name : 'Lee', arr : ['哥哥','妹妹','姐姐'] };
var box1 = obj(box);
alert(box1.name); //字面量对象 //传递
box1.name = 'Jack';
alert(box1.name);
alert(box1.arr);
box1.arr.push('父母');
alert(box1.arr);
var box2 = obj(box);
alert(box2.name);
alert(box2.arr); //传递 //引用类型共享了

 寄生式继承把原型式+工厂形式整合而来,目标是为着封装创制对象的长河。

function create(o) {//封装创建过程
   var f= obj(o);
   f.run = function () {
     return this.arr;//同样,会共享引用 }; return f;
}

组合式继承是 JavaScript
最常用的接轨情势;但,组合式继承也有一点小题目,就是超类型在行使过程中会被调用五回:一遍是创制子类型的时候,另五次是在子类型构造函数的内部。

function Box(name) {
  this.name = name;
  this.arr = ['哥哥','妹妹','父母'];
}
Box.prototype.run = function () {
   return this.name;
};
function Desk(name, age) {
  Box.call(this, name); this.age = age;
}
Desk.prototype = new Box(); //第二次调用 Box //第一次调用 Box

 以上代码是事先的咬合继承,那么寄生组合继承,解决了一遍调用的题目。

function obj(o) {
  function F() {} F.prototype = o; return new F();
}
function create(box, desk) {
  var f = obj(box.prototype);
   f.constructor = desk;
   desk.prototype = f;
}
function Box(name) {
   this.name = name;
   this.arr = ['哥哥','妹妹','父母'];
}
Box.prototype.run = function () {
  return this.name;
};
function Desk(name, age) {
   Box.call(this, name); this.age = age;
}
inPrototype(Box, Desk);
var desk = new Desk('Lee',100);
desk.arr.push('姐姐');
alert(desk.arr);
alert(desk.run());
var desk2 = new Desk('Jack', 200);
alert(desk2.arr); //通过这里实现继承 //只共享了方法 //引用问题解决