JavaScript高级程序设计——原型和原型链

JS原型

前言

此文章为加深对JS中重要概念进行理解,不建议没有任何JS基础的人看,只为加深对概念理解通过实际的例子,而不是看书以为自己读懂了,可能几天后就忘了,主要是为了理解核心概念,以及对重难点解释。

一切都是对象

“一切都是对象”这句话的重点在于如何去理解“对象”这个概念。

概念

JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象函数对象,Object 、Function 是 JS 自带的函数对象。
当然,也不是所有的都是对象,值类型就不是对象。

function show(x) {

            console.log(typeof x);    // undefined
            console.log(typeof 10);   // number
            console.log(typeof 'abc'); // string
            console.log(typeof true);  // boolean

            console.log(typeof function () {});  //function

            console.log(typeof [1, 'a', true]);  //object
            console.log(typeof { a: 10, b: 20 });  //object
            console.log(typeof null);  //object
            console.log(typeof new Number(10));  //object
        }
        show();

以上代码列出了typeof输出的集中类型标识,其中上面的四种(undefined, number, string, boolean)属于简单的值类型,不是对象。剩下的几种情况——函数、数组、对象、null、new Number(10)都是对象。他们都是引用类型

对象——若干属性的集合

概念

数组是对象,函数是对象,对象还是对象。

对象里面的一切都是属性,只有属性,没有方法

那么这样方法如何表示呢?——方法也是一种属性。因为它的属性表示为键值对的形式。
而且,javascript中的对象可以任意的扩展属性,没有class的约束。这个大家应该都知道,就不再强调了。

先说个最常见的例子:

var obj = {
            a: 10,
            b: function(x) {
                alert(this.a + x)
            },
            c: {
                name: "yzh",
                age: 21
            }
        }

以上代码中,obj是一个自定义的对象,其中a、b、c就是它的属性,而且在c的属性值还是一个对象,它又有name、year两个属性。

这个可能比较好理解,那么函数和数组也可以这样定义属性吗?——当然不行,但是它可以用另一种形式,总之函数/数组之流,只要是对象,它就是属性的集合。

var fn = function () {
            alert(100);
        };
        fn.a = 10;
        fn.b = function () {
            alert(123);
        };
        fn.c = {
            name: "yzh",
            age: 21
        };

上段代码中,函数就作为对象被赋值了a、b、c三个属性——很明显,这就是属性的集合。

(引用类型)都是对象,对象是属性的集合。最需要了解的就是对象的概念。

创建对象

前言

这块在《JS高级程序设计》也算是大章节下的一块大内容,我只把一些重要的概念写出来让大家理解,具体的深入要自己去看书中的讲解。

函数和对象的关系

对象都是通过函数创建的

function Fn() {
            this.name = 'yzh';
            this.year = 1996;
        }
        var fn1 = new Fn();

有人可能会举出如下反例

var obj = { a: 10, b: 20 };
var arr = [5, 'x', true];

这种做法属于使用“快捷方式”,在编程语言中,一般叫做“语法糖”。
其实以上代码的本质是:

//var obj = { a: 10, b: 20 };
//var arr = [5, 'x', true];

        var obj = new Object();
        obj.a = 10;
        obj.b = 20;

        var arr = new Array();
        arr[0] = 5;
        arr[1] = 'x';
        arr[2] = true;

而其中的 Object 和 Array 都是函数:

console.log(typeof (Object));  // function
console.log(typeof (Array));  // function

总结:对象都是通过函数来创建的

prototype

函数也是一种对象。他也是属性的集合,你也可以对函数进行自定义属性

每创建一个函数,就会同时创建函数的prototype对象。
这个prototype的属性值是一个对象(属性的集合,再次强调!),默认的只有一个叫做constructor的属性,指向这个函数本身。

function Fn() { }
        Fn.prototype.name = '王福朋';
        Fn.prototype.getYear = function () {
            return 1988;
        };

        var fn = new Fn();
        console.log(fn.name);
        console.log(fn.getYear());

Fn是一个函数,fn对象是从Fn函数new出来的,这样fn对象就可以调用Fn.prototype中的属性。

因为每个对象都有一个隐藏的属性——“proto”,这个属性引用了创建这个对象的函数的prototype。

即:fn.proto === Fn.prototype
这里的"proto"成为“隐式原型”

隐式原型

每个函数function都有一个prototype,即原型。这里再加一句话——每个对象都有一个proto,可成为隐式原型。proto用于指向创建它的构造函数的原型对象

对象 person1 有一个 proto属性,创建它的构造函数是 Person,构造函数的原型对象是 Person.prototype ,所以:

person1.proto == Person.prototype

又比如:obj这个对象本质上是被Object函数创建的,因此obj.proto=== Object.prototype

在说明“Object.prototype”之前,先说一下自定义函数的prototype。自定义函数的prototype本质上就是和 var obj = {} 是一样的,都是被Object创建,所以它的proto指向的就是Object.prototype。

但是Object.prototype确是一个特例——它的proto指向的是null.
至于为什么简单解释下:

所有的构造器都来自于 Function.prototype,甚至包括根构造器Object及Function自身。所有构造器都继承了·Function.prototype·的属性及方法。如length、call、apply、bind

console.log(typeof Function.prototype) // function
console.log(typeof Object.prototype)   // object
console.log(typeof Number.prototype)   // object
console.log(typeof Boolean.prototype)  // object
console.log(typeof String.prototype)   // object
console.log(typeof Array.prototype)    // object
console.log(typeof RegExp.prototype)   // object
console.log(typeof Error.prototype)    // object
console.log(typeof Date.prototype)     // object
console.log(typeof Object.prototype)   // object

知道了所有构造器(含内置及自定义)的proto都是Function.prototype,

Function.prototype的proto是谁呢

console.log(Function.prototype.proto === Object.prototype) // true
这说明所有的构造器也都是一个普通 JS 对象,可以给构造器添加/删除属性等。同时它也继承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。

最后Object.prototype的proto是谁?

Object.prototype.proto === null // true
已经到顶了,为null。

原型链

概念

访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着proto这条链向上找

javascript中的继承是通过原型链来体现的.

传统原型语法

function Foo() {}

        Foo.prototype.a = 100;
        Foo.prototype.b = 200;
        var f1 = new Foo();
        f1.a = 10;
        alert(f1.a);  //10
        alert(f1.b);  //200
function Foo() {}
        var f1 = new Foo();
        f1.a = 10;
        Foo.prototype.a = 100;
        Foo.prototype.b = 200;
        
        alert(f1.a);  //10
        alert(f1.b);  //200

对象字面量方法添加属性和方法的注意事项

function Foo() {}

        Foo.prototype = {
            a: 100,
            b: 200
        }
        var f1 = new Foo();
        f1.a = 10;
        alert(f1.a); //10
        alert(f1.b); //200
function Foo() {}
        var f1 = new Foo();
        f1.a = 10;
        Foo.prototype = {
            a: 100,  
            b: 200
        }
        
        alert(f1.a);  //10
        alert(f1.b);  //undefined

原型的属性和方法赋值要在,新建实例对象之前,不然无法获得原型的值和属性,alert返回相应的undefined

重写原型对象问题

接上面的例子讲,如果在实例上添加新属性,这个属性就会屏蔽原型对象中保存的同名属性,就是阻止访问了属性,而不是修改原型的属性。

function Foo() {}
        var f1 = new Foo();
        f1.a = 10;
        Foo.prototype = {
            a: 100,  
            b: 200
        }
        
        alert(f1.a);  //10
        alert(f1.b);  //undefined

总结:重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的关系,它们的引用的仍然是最初的原型

End

暂时总结到此,有些知识点没有讲到,可能需要大家自己去看书或查阅资料来理解,本人理解也有限,文中若有难以理解的还望大神换个方式来阐述。

未完待续

后续还有两篇讲解《执行上下文与作用域》和《闭包》,最后一篇闭包可能会有一些前端面试题来讲,并在文章末做个总结。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容