1、到目前为止,我们是时候分析下前面的使用原型语法来定义对象有哪些不足的地方,代码如下:

    function Person(){
}
Person.prototype.name="张三";
Person.prototype.age=22;
Person.prototype.job="coder";
Person.prototype.sayName=function(){
alert(this.name);
}

当我们为Person对象每添加一个属性和方法,就要敲一遍Person.prototype,而且Person.prototype没有体现出封装性;

所以下面来改进原型语法,代码如下:

    function Person(){
}
Person.prototype={
name:"张三",
age:22,
job:"coder",
sayName:function(){
alert(this.name);
}
}

改进之后的原型语法将Person.prototype设置为等于一个以对象字面量形式创建的新对象。最终的结果相同,但有一个列外:constrcutor属性不再指向Person了。

因为当我们每创建一个函数,同时就会创建一个prototype属性对象(原型属性对象),而这个对象会自动获得constructor属性。

而我们在这里使用的语法,本质上完全重写了默认的prototype属性对象,因此constructor属性也就变成了新对象的constuctor属性(该属性指向Object构造函数),不在指向Person函数,所以尽管instanceof操作符还能返回正确的结果,但通过constructor属性来确定对象的类型已经不可能了,如下代码可以说明:

    function Person(){
}
Person.prototype={
name:"张三",
age:22,
job:"coder",
sayName:function(){
alert(this.name);
}
}
var person=new Person();
alert(person instanceof Object); //输出:true 因为person是Object的实例(Object是所有类的基类)
alert(person instanceof Person); //输出:true 因为person是Person的实例
alert(person.constructor==Object);
alert(person.constructor==Person); //输出false 说明Person构造函数的Person.prototype属性对象(原型对象)内的constructor属性已经不指向Person函数,而
//是指向Object函数

如果constructor属性真的很重要,我们可以向下面代码那样将它设回适当的值,代码如下:

    function Person(){
}
Person.prototype={
constructor:Person, //自定义添加constructor属性,并让他指向Person函数
name:"张三",
age:22,
job:"coder",
sayName:function(){
alert(this.name);
}
}
var person=new Person();
alert(person instanceof Object); //输出:true 因为person是Object的实例(Object是所有类的基类)
alert(person instanceof Person); //输出:true 因为person是Person的实例
alert(person.constructor==Object); //输出:false; 原因如下
alert(person.constructor==Person); //输出:true constructor:Person,=》在对象里面自定义了constructor属性,并让它指向了Person函数
// 所以person.constructor重新指向了Person,而不是Object

注意:以上这种方式添加constructor属性会导致它的[[Enumerable]]设为true,而原生的constructor属性是不可枚举的,所以我们需要用ECMAScript 5中定义的Object.definePropery()方法来重新定义constructor属性,使他变成不可枚举的属性,且值是指向对象构造函数的指针,代码如下:

   function Person(){
}
Person.prototype={
name:"张三",
age:22,
job:"coder",
sayName:function(){
alert(this.name);
}
}
Object.defineProperty(Person.prototype,"constructor",{
enumerable:false,
value:Person
});

JavaScript之面向对象学习三原型语法升级的更多相关文章

  1. JavaScript之面向对象学习七(动态原型模式、寄生构造函数模式、稳妥构造函数模式创建自定义类型)

    一.动态原型模式 在面向对象学习六中的随笔中,了解到组合构造函数模式和原型模式创建的自定义类型可能最完善的!但是人无完人,代码亦是如此! 有其他oo语言经验的开发人员在看到独立的构造函数和原型时,很可 ...

  2. 【JAVASCRIPT】React学习-JSX 语法

    摘要 react 学习包括几个部分: 文本渲染 JSX 语法 组件化思想 数据流 JSX 语法 1. 定义 JSX 是javascript + xml 的合集,我们可以将javascript 与 ht ...

  3. JavaScript之面向对象学习一

    1.通过Object构造函数和对象字面量来创建对象缺点:使用同一个接口创建很多的对象,会产生大量的重复代码.比如我需要创建人的对象,并且需要三类人,医生.工程师.老师,他们可以抽象出很多属性,比如姓名 ...

  4. JavaScript之面向对象学习八(继承)

    简介:继承是OO语言中的一个最为人津津乐道的概念.许多OO语言都支持两种继承方式:接口继承和实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法. 但是JS的函数并没有签名,所以在ECMASc ...

  5. JavaScript之面向对象学习六原型模式创建对象的问题,组合使用构造函数模式和原型模式创建对象

    一.仔细分析前面的原型模式创建对象的方法,发现原型模式创建对象,也存在一些问题,如下: 1.它省略了为构造函数传递初始化参数这个环节,结果所有实例在默认的情况下都将取得相同的属性值,这还不是最大的问题 ...

  6. JavaScript之面向对象学习五(JS原生引用类型Array、Object、String等等)的原型对象介绍

    1.原型模式的重要性不仅仅体现在创建自定义类型方面,就连所有的原生的引用类型(Obejct.Array.String等等)都在构造函数的原型上定义方法和属性.如下代码可以证明: alert(typeo ...

  7. JavaScript之面向对象学习四原型对象的动态性

    1.由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反映出来---即便是先创建了实例后修改原型也是如此.代码如下: function Person(){ } va ...

  8. JavaScript之面向对象学习二(原型属性对象与in操作符)获取对象中所有属性的方法

    1.原型属性对象于in操作符之in单独使用 有两种方式使用in操作符:单独使用和在for-in循环中使用.在单独使用中,代码如下: function Person(){ } Person.protot ...

  9. 治愈 JavaScript 疲态的学习计划【转载】

    来源:伯乐在线 - Rose Wang 像其他人一样,最近我读了 Jose Aguinaga 的文章 <How it feels to learn JavaScript in 2016>. ...

随机推荐

  1. 转:Javascript异步编程的4种方法

    你可能知道,Javascript语言的执行环境是"单线程"(single thread). 所谓"单线程",就是指一次只能完成一件任务.如果有多个任务,就必须排 ...

  2. MATLAB中文论坛帖子整理(GUI)

    MATLAB中文论坛帖子整理(GUI) 目   录  1.GUI新手之——教你读懂GUI的M文件... 10 2.GUI程序中改变current directory引起的问题... 15 3.GUI中 ...

  3. Linux中service命令和/etc/init.d/的关系

    Linux中service命令和/etc/init.d/的关系   service xxx启动 /etc/init.d/ 目录下的xxx脚本 如一个脚本名为 mysvc保存在/etc/init.d/下 ...

  4. MFC CWnd仿按钮

    CBtn::CBtn() { RegisterWndClass(); } bool CBtn::RegisterWndClass(void) { WNDCLASS n; HINSTANCE hInst ...

  5. AndroidUI 侧滑菜单 DrawerLayout的使用

    直接上代码: activity_main.xml: <android.support.v4.widget.DrawerLayout xmlns:android="http://sche ...

  6. CocoaPods的安装及安装出现问题的处理

    ocoaPods安装分两步:第一步.修改本机的Ruby环境:第二步.安装. 第一步:步骤1.打开终端输入   gem sources -l   查看本机的Ruby环境:若显示“https://ruby ...

  7. iOS7.0中UILabel高度调整注意事项(转)

    注释:原文链接丢失. 我的“记词助手”在升级到iOS7之后,一直出现UILabel错位的问题: 我的label是用- (CGSize)sizeWithFont:(UIFont *)font const ...

  8. js堆栈溢出错误

    function prompt() { var answer = prompt("What is your name","") if (answer) { al ...

  9. Service的基本组成

    Service与Activity的最大区别就是一有界面,一个没有界面. 如果某些程序操作很消耗时间,那么可以将这些程序定义在Service之中,这样就可以完成程序的后台运行, 其实Service就是一 ...

  10. Android dump .so 文件crash log

    众所周知,在android系统上,有时候我们遇到so文件的crash仅仅能打log,可是非常多时候并不知道crash在什么地方,幸运的是crash后,一般能够产生一个.dmp文件. 我们能够依据这个文 ...