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__会见不可知鉴别,火狐和谷歌浏览器和另外某些浏览器都能够鉴别。虽然可以输出,但无能为力获取内部信息。

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

 原型链继承流程图

如果一旦实例化 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); //通过这里实现继承 //只共享了方法 //引用问题解决