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

《JavaScript高等程序设计——原型和原型链》

媒介

此文章为加深对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

临时总结到此,有些知识点没有讲到,能够须要人人本身去看书或查阅材料来明白,本人明白也有限,文中如有难以明白的还望大神换个体式格局来论述。

未完待续

后续另有两篇解说《实行上下文与作用域》和《闭包》,末了一篇闭包能够会有一些前端面试题来说,并在文章末做个总结。

    原文作者:cduyzh
    原文地址: https://segmentfault.com/a/1190000009446174
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞