在面向进程的语言中大家习惯把形成有些特定功效的代码块称为,全部的原型都以目的

深深精晓:JavaScript原型与继承

看过众多书本,不少篇章,对于原型与后续的证实基本上让人不明觉厉,尤其是对于习惯了面向对象编制程序的人的话更难知晓,那里笔者就给大家说说笔者的接头。

先是JavaScript是一门基于原型编制程序的语言,它遵循原型编制程序的主旨规则:

  1. 拥有的数据都是目的(javascript中除去字符串字面量、数字字面量、true、false、null、undefined之外,别的值都以指标!)
  2. 要博得一个指标,不是经超过实际例化类,而是找到三个对象作为原型并克隆它
  3. 对象会铭记它的原型
  4. 要是目的不恐怕响应有些请求,它会把该请求委托给它和谐的原型

这么说来,JavaScript一定有三个根对象,全部的靶子的最终原型都将是它,它正是Object.prototypeObject.prototype也是3个对象,它是七个空的目的。(记住一点:全部的原型都以指标,但不是函数,尽管函数也是目标,Object对象实际便是二个函数)

以下代码创制空对象:

var obj1 = new Object();
var obj2 = {};
Object.getPrototypeOf(obj1) === Object.prototype; //true
Object.getPrototypeOf(obj2) === Object.prototype; //true

咱俩再来看下以下代码:

function Book(name){
    this.name = name;
}
Book.prototype.getName = function(){
    return this.name;
}
Book.num = 5;
var book1 = new Book('javascript权威指南');
book1.getName(); //javascript权威指南
Object.getPrototypeOf(book1) === Book.prototype; //true

咱俩平时说,使用了new
Book()来创造了Book的实例book1,不过JavaScript并不曾类的概念,这里的Book本质上只是一个函数而已,借使用new则把它当着构造函数对待,那么var book1 = new Book('javascript权威指南')是怎么个执行进程吧?在那前边,大家来先看下Function与Object的涉嫌

那里有张图:
图片 1

一、this

在JavaScript中this表示:什么人调用它,this正是何人。

JavaScript是由对象组成的,一切皆为目标,万物皆为指标。this是3个动态的对象,依照调用的对象分歧而发生变化,当然也得以采纳call、apply修改this指向的靶子。它表示函数运营时,自动生成的1个里面对象,只可以在函数内部选取

Function与Object的关系

console.log(Function); //[Function: Function]
console.log(Function.constructor); //[Function: Function]
console.log(Function.__proto__); //[Function]
console.log(Function.prototype); //[Function]
console.log(Function.constructor.prototype); //[Function]

console.log(Object.__proto__); //[Function]
console.log(Object.prototype); //{}
console.log(Object.constructor); //[Function: Function]
console.log(Object.constructor.prototype); //[Function]

在JavaScript中:Function和Object就如大地之母和青帝,Object提供种子(Object.prototype),Function负责繁衍。Object是由Object.prototype提供的种子经过Function创设出来的。Object.prototype会被直接继续下来,并一代一代增强。

  1. 每一个函数都有三个原型对象(prototype)和隐形的__proto__属性,函数的__proto__质量指向Function.prototype,而原型对象(prototype)是贰个对象,符合以下第③点(也有协会函数constructor和隐身的__proto__属性);
  2. 每叁个非函数对象(实例对象)都有二个构造函数(constructor)和潜伏的__proto__属性,constructor自然指的是它的构造函数,而__proto__本着的是它的构造函数的原型对象prototype
  3. 通过__proto__天性,每种对象和函数都会记住它的原型,那样就形成了原型链;

console.log(Book); //{ [Function: Book] num: 5 }
console.log(Book.__proto__); //[Function]
console.log(Book.prototype.__proto__); //{} 等于Object.prototype
console.log(Book.prototype); //Book { getName: [Function] }
console.log(Book.constructor); //[Function: Function]
console.log(Book.prototype.constructor); //{ [Function: Book] num: 5 }
console.log(Book.constructor.prototype); //[Function]
console.log(Book.__proto__.__proto__); //{} 等于Object.prototype

每1个函数都以通过Function构造出来的,函数的原型属性__proto__指向Function.prototype,而函数的原型对象prototype是表示着自家的函数对象,它的__proto__质量指向Object.prototype,它的constructor属性私下认可指向它自个儿构造函数(也可改为其余函数,如:Book.prototype.constructor
= Person;)。

console.log(book1); //Book { name: 'javascript权威指南' }
console.log(book1.__proto__); //Book { getName: [Function] }
console.log(book1.prototype); //undefined
console.log(book1.constructor); //{ [Function: Book] num: 5 }
console.log(book1.constructor.prototype); //Book { getName: [Function] }

从而,大家司空见惯说‘四个指标的原型’其实是不可靠的,应该是‘三个对象的构造器的原型’,且对象是把它相当小概响应的伸手委托给它的构造器的原型顺着原型链往上传递的。

当今来上课一下var book1 = new Book('javascript权威指南')的进行进度,是如此:new先从Object.prototype克隆二个空对象,先将空对象的构造函数内定为Book,然后将空对象的__proto__指向它的构造函数的原型Book.prototype,之后通过Book构造函数对这几个空对象实行赋值操作,并将以此目的回来给变量book1。

咱俩再看如下代码:

var obj = {name: 'Sufu'};
var Person = function(){};
Person.prototype = obj;
var a = new Person();
console.log(a.name); //Sufu

那段是如此进行的:

  1. 率先尝试寻找对象a的name属性,找不到,执行第叁步
  2. 将寻找name属性的这几个请求委托给a的构造器的原型,a.__proto__记录的是Person.prototype,Person.prototype为指标obj
  3. 在目的obj中搜索name,找到并回到它的值给a,假若还找不到,它就由此obj.__proto__找到Object.prototype,找不到就再次回到undefined,因为Object.prototype的原型不设有了,为null

好了,就介绍到此地了,以上是个人的明白,有不规则的地点欢迎提议!

参考文献:《javascript权威指南》

1.0、猜猜答案

代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>JavaScript this</title>
    </head>
    <body>
        <h2>JavaScript this</h2>
        <input type="button" value="按钮A" id="btnA"/>
        <input type="button" value="按钮B" id="btnB" onclick="sayHello()"/>
        <script type="text/javascript">
            function sayHello(){
                alert("Hello Button!");
                console.log(this);
            };

            document.getElementById("btnA").onclick=sayHello;

        </script>
    </body>
</html>

请问输出到控制台的结果是怎么?相同呢?输出八个怎么着指标?

答案:

图片 2图片 3

<input type="button" value="按钮A" id="btnA"/>
Window

View Code

1.壹 、JavaScript中等学校函授数与情势的分别

在面向进度的言语中我们习惯把实现有个别特定功效的代码块称为“函数”或“进度”,当然进程相似没有重返值。在面向对象语言中我们把目的的效应称为“方法”。但JavaScript是种介于面向对象与面向进度在那之中的语言,同样的主意有时是函数,有时是方法,如下所示:

<script type="text/javascript">
            //1
            function show(){
                console.log("这是一个函数");
            }

            //2
            (function(){
                console.log("这是一个函数表达式");
            })();

            //3
            var obj1={
                show:function(){
                    console.log("这是一个方法");
                }
            };

            //4
            function obj2(){  //obj2是函数,构造函数
                this.show=function(){
                    console.log("这是一个方法,是一个表达式");
                }
            }
            var obj3=new obj2();

        </script>

可以简简单单的以为一旦调用时不曾通过对象没有点名上下文则为函数,不然为格局。

1.贰 、指向全局对象

当在漫天限制Nelly用
this,它将会指向全局对象。一般是window对象,但全局对象不自然唯有window,越发是在node.js环境中。作为函数调用时一般针对全局对象。

        <script type="text/javascript">
            var i=5;
            i=6;
            console.log(i);   //6
            console.log(window.i);  //6
            console.log(this.i);  //6
            console.log(this);  //window
        </script>

结果:

图片 4

        <script type="text/javascript">
            var name="tom";
            console.log(this.name);      //顶层对象,一般为window    

            function show()
            {
                console.log(this.name);  //顶层对象,一般为window
                return function(){
                    console.log(this.name);  //顶层对象,一般为window,因为返回的是函数
                }
            }

            var f1=show();
            f1();

        </script>

运作结果:

图片 5

1.三 、作为艺术调用

当函数作为艺术调用时this指向调用该措施的目的。

            function show()
            {
                //当obj1.view()时this就是obj1,obj2.view()时this就是obj2
                console.log(this.name);
            }

            var obj1={name:"jack",view:show};
            obj1.view();

            var obj2={name:"mark",view:show};
            obj2.view();

运作结果:

图片 6

以身作则代码:

        <script type="text/javascript">
            var name="lucy";
            this.name="Mali";
            function show()
            {
                //当obj1.view()时this就是obj1,obj2.view()时this就是obj2
                console.log(this.name);

                return function(){
                    console.log(this.name);  //这里的this是调用时动态决定
                }
            }

            var obj1={name:"jack",view:show};
            obj1.view();

            var obj2={name:"mark",view:show};
            var f1=obj2.view();
            f1();  //因为f1属于window(浏览器环境),调用f1时的this也就是window

        </script>

运作结果:

图片 7

以身作则代码:

        <script type="text/javascript">
            var name="lucy";
            this.name="Mali";
            function show()
            {
                //当obj1.view()时this就是obj1,obj2.view()时this就是obj2
                console.log(this.name);
                that=this;  //闭包
                return function(){
                    console.log(that.name);  //这里的that指向的是外层函数调用时的对象
                }
            }

            var obj1={name:"jack",view:show};
            obj1.view();

            var obj2={name:"mark",view:show};
            var f1=obj2.view();
            f1();            
        </script>

运作结果:

图片 8

1.四 、在构造函数中的this

构造函数中的this指向新创建的对象,new出何人this便是什么人。

演示代码:

<script type="text/javascript">
            this.name="吉娃娃";
            function Dog(name)
            {
                this.name=name;
                this.bark=function(){
                    console.log(this.name+"在叫,汪汪...");
                }
            }

            var dog1=new Dog("哈士奇");
            dog1.bark();
</script>

运转结果:

图片 9

依照严峻的语法,构造函数不应该重回值,然则JavaScript是允许构造方法重临值的,暗中同意再次来到this,修改后的演示如下:

            this.name="吉娃娃";
            function Dog(name)
            {
                this.name=name;
                this.bark=function(){
                    console.log(this.name+"在叫,汪汪...");
                }
                return this.bark;
            }

            var dog1=new Dog("哈士奇");
            dog1();

运作结果:

 图片 10

1.5、内定this指向的指标

当调用方法是透过Function.call,或Function.apply时this为调用时钦赐的靶子,假诺没有点名则为顶层对象,浏览器中是window。

演示代码:

            this.name="伽啡";
            function Cat(name)
            {
                this.name=name;
            }
            var bark=function(n){
                console.log(this.name+"叫了"+(n||1)+"声喵喵...");
            }

            var cat1=new Cat("波斯");
            var cat2=new Cat("龙猫");

            bark.call(cat1,5);  //调用时this是cat1
            bark.apply(cat2,[8]);  //调用时this是cat2
            bark.apply(window,[9]);  //调用时this是window
            bark.apply();  //调用时this是顶层对象

 

运维结果:

图片 11

1.陆 、作为事件时的this

若果页面中的元素与事件进展绑定时事件中的this一般针对网页成分,如按钮,文本框等。可是在要素中一直钦赐要实践的函数则this指向window顶层对象。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>this</title>
    </head>
    <body>
        <input type="button" value="按钮A" class="btn"/>
        <input type="button" value="按钮B" class="btn"/>
        <input type="button" value="按钮C" class="btn"/>
        <input type="button" value="按钮D" onclick="handler()"/>
        <!--handler中的this指向window或顶层对象-->
        <input type="button" value="按钮E" id="btnE"/>
        <script type="text/javascript">
            var buttons = document.querySelectorAll(".btn");

            for (var i=0;i<buttons.length;i++) {
                //handler中的this指向按钮对象
                buttons[i].onclick=handler;
            }

            function handler(){
                    alert(this.value);
            }

            //handler中的this指向btnE
            document.getElementById("btnE").addEventListener("click",handler,false);
        </script>
    </body>
</html>

当点击A-C时的法力:
图片 12

当点击D时的功用:

 图片 13

当点击按钮E时的成效:

图片 14

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>this</title>
    </head>

    <body>
        <input type="button" value="按钮F的值" id="btnF" />
        <input type="button" value="按钮G的值" id="btnG" onclick="app.show()"/>
        <script type="text/javascript">
            value="window的值"
            var app = {
                value: "app的值",
                show: function() {
                    alert(this.value); //如果show为事件,则this指向触发事件的对象
                },
                init: function() {
                    //handler中的this指向btnE
                    document.getElementById("btnF").addEventListener("click", this.show, false);
                }
            };

            app.show();   //"app的值",show方法中的this指向app这个对象
            app.init();     //init中的this指向谁app对象


        </script>
    </body>
</html>

 加载时运行结果:

图片 15

点击按钮F时的作用:

图片 16

点击按钮G时的效劳:

 图片 17

在HTML元素上平昔钦赐事件严厉来说都不可能算得事件绑定,只可以描述是当按钮点击达成后执行的函数。借使想将进行时的靶子带回,能够扩大参数this。

1.7、小结

函数调用可以如下两种为主情势:

1)、fun(x,y);

2)、obj.fun(x,y);

3)、fun.apply(obj,[x,y]);

4)、fun.call(obj,x,y);

第壹,2种调用的主意最终将转换到3,4办法,也正是说1,三头是一种简化的语法糖,那么this正是apply与obj的第二个参数,指向调用时的上下文。

贰 、原型(prototype)与原型链

在javascript面向对象中关于原型(prototype)、原型链、__proto__、Function、Object等情节是较难精通的,先上几张方便人民群众大家清楚的图:

JavaScript藏宝图

图片 18

JavaScript Object Layout:

图片 19

Object Relationship Diagram with Inheritance

图片 20

图片 21

JavaScript是一种通过原型完结一连的语言与其他高级语言是有分别的,像java,C#是经过品种决定继续关系的,JavaScript是的动态的弱类型语言,总而言之可以认为JavaScript中颇具都以指标,在JavaScript中,原型也是二个对象,通过原型能够完结指标的天性持续JavaScript的目的中都包蕴了叁个”
prototype”内部属性,那特特性所对应的正是该对象的原型。

“prototype”作为指标的里边属性,是不能够被一贯访问的。所以为了便利查看三个对象的原型,Firefox和Chrome内核的JavaScript引擎中提供了”__proto__”这个非标准的访问器(ECMA新规范中引入了正规对象原型访问器”Object.getPrototype(object)”)。

1.一 、为何供给prototype

现今有三个Student构造函数,通过new调用该构造函数能够创设二个新的靶子,示例如下:

            //构造方法,用于创建学生对象
            function Student(name) {
                this.name = name;
            }

            var tom=new Student("tom");
            tom.show=function(){
                console.log(this.name);
            }

            var rose=new Student("rose");
            rose.show=function(){
                console.log(this.name);
            }

            tom.show();
            rose.show();

运维结果:

图片 22

地点的以身作则中tom与rose都亟需show方法,创制对象后大家直接为七个对象分别都扩大了show方法,可是这么做的弊病是假如再追加越来越多目的也必要添加show方法,最佳的法门是修改构造方法Student,如下所示:

            //构造方法,用于创建学生对象
            function Student(name) {
                this.name = name;
                this.show = function() {
                    console.log(this.name);
                }
            }

            var tom = new Student("tom");
            var rose = new Student("rose");

            tom.show();
            rose.show();

只是只要Student构造函数是贰个置于的函数或是别的框架定义的类型,则修改就相比较艰巨了,能够不修改源码的气象增添该指标的原型也足以高达目标,如下所示:

            //构造方法,用于创建学生对象
            function Student(name) {
                this.name = name;
            }

            //修改Student对象的原型,增加show方法
            Student.prototype.show = function() {
                console.log(this.name);
            }

            var tom = new Student("tom");
            var rose = new Student("rose");

            tom.show();
            rose.show();

在演示中大家并不曾改动Student那一个构造函数而是修改了了Student的原型对象,类似它的父类,如下图所示:

图片 23

那儿你可能会以为拥有的Object都扩张了show方法,那样想是错误的,因为Student的原型是1个对象而不是像其余高级语中的类型,我们修改的只是Student的原型对象,不会影响其他的对象。

            var mark=new Object();
            mark.name="mark";

            var lucy={name:"lucy"};
            //mark.show();
            //lucy.show();

那边的三个show方法是大错特错的。总之原型的重点职能正是为着落到实处再而三与扩大对象。

在JavaScript中,原型也是三个对象,通过原型能够达成指标的属性持续,JavaScript的指标中都涵盖了1个”[[Prototype]]”内部属性,那一个性格所对应的就是该指标的原型。

“[[Prototype]]”作为靶子的里边属性,是无法被一贯访问的。所以为了便利查看2个对象的原型,Firefox和Chrome中提供了__proto__其一非标准化准(不是装有浏览器都援助)的访问器(ECMA引入了标准对象原型访问器”Object.getPrototype(object)”)。在JavaScript的原型对象中,还隐含3个”constructor”属性,这几个天性对应创立全数指向该原型的实例的构造函数

 

1.2、typeof与instanceof

1.2.1、typeof

在 JavaScript 中,判断三个变量的档次能够用typeof,如:

             var str1="Hello";
             var str2=new String("Hello");

            console.log(typeof 1);
            console.log(typeof(true));
            console.log(typeof str1);
            console.log(typeof str2);
            console.log(typeof([1,2,3]));
            console.log(typeof Date);
            console.log(typeof undefined);
            console.log(typeof null);
            console.log(typeof zhangguo);

运转结果:

图片 24

1)、数字类型, typeof 重返的值是
number。比如说:typeof(1),重返值是number
2)、字符串类型, typeof 重回的值是
string。比如typeof(“123”)重返值是string。
3)、布尔类型, typeof 重回的值是 boolean
。比如typeof(true)重临值是boolean。
4)、对象、数组、null 再次回到的值是 object
。比如typeof(window),typeof(document),typeof(null)再次来到的值都以object。
5)、函数类型,重临的值是
function。比如:typeof(eval),typeof(Date)重回的值都是function。
6)、不存在的变量、函数大概undefined,将重回undefined。比如:typeof(abc)、typeof(undefined)都重回undefined。

1.2.2、instanceof

动用 typeof
运算符时选择引用类型存款和储蓄值会冒出一个题目,无论引用的是哪些项目标靶子,它都回到
“object”。ECMAScript 引入了另一个 Java 运算符 instanceof
来化解这几个标题。instanceof 运算符与 typeof
运算符相似,用于识别正在处理的靶子的品类。与 typeof
方法不一样的是,instanceof 方法需求开发者分明地认同对象为某一定类型。

instanceof用于判断有些对象是否被另贰个函数构造。

例如:
var oStringObject = new String(“hello world”);
console.log(oStringObject instanceof String); // 输出 “true”

             var str1="Hello";
             var str2=new String("Hello");

            console.log(str1 instanceof String);   //string false
            console.log(str2 instanceof String);  //object true

            console.log(1 instanceof Number); //false

            function Foo(){};

            var f1=new Foo();
            console.log(f1 instanceof Foo);

运维结果:

图片 25

1.3、Function与Object

1.3.1、Function

函数正是指标,代表函数的指标正是函数对象。全部的函数对象是被Function那些函数对象组织出来的。Function是最顶层的构造器。它构造了系统中具有的指标,包蕴用户自定义对象,系统内置对象,甚至席卷它自已。那也申明Function具有自举性(自已组织本身的能力)。这也直接控制了Function的call和constructor逻辑相同。各类对象都有一个constructor 属性,用于指向成立其的函数对象。

图片 26

先来看三个示范:

            function Foo(a, b, c) {  //Foo这个构造函数由Function构造,函数也是对象
                return a * b * c;
            }

            var f1=new Foo();   //f1由Foo构造,Foo是一个构造函数,可以理解为类

            console.log(Foo.length);   //参数个数 3
            console.log(typeof Foo.constructor);  //function
            console.log(typeof Foo.call);  //function
            console.log(typeof Foo.apply);  //function
            console.log(typeof Foo.prototype);  //object object

运作结果:

 图片 27

函数与指标具备同等的语言地位
从没类,只有对象
函数也是一种对象,所谓的函数对象
对象是按引用来传递的

            function Foo() {};
            var foo = new Foo();
            //Foo为foo的构造函数,简单理解为类型
            console.log(foo instanceof Foo); // true

            //但是Function并不是foo的构造函数
            console.log(foo instanceof Function); // false

            //Function为Foo的构造函数
            alert(Foo instanceof Function); //true

地方的代码解释了foo和其构造函数Foo和Foo的结构函数Function的涉及,Foo是由Function构造获得,能够简单明了为,系统中有1个如此的构造函数:

            function Function(name,body)
            {
            }

            var Foo=new Function("Foo","");

如上边例子中的构造函数,JavaScript中等高校函授数也是目的,所以就能够透过_proto_摸索到构造函数对象的原型。

Function对象作为3个函数,就会有prototype属性,该属性将对应”function ()
{}”对象。

Function对象作为三个目的,就有__proto__品质,该属性对应”Function.prototype”,也正是说,”Function._proto_
=== Function.prototype”。

在此处对“prototype”和“proto”实行简短的牵线:

对此有着的靶子,都有__proto__属性,那几个性格对相应对象的原型。

对于函数对象,除了__proto__属性之外,还有prototype属性,当3个函数被看作构造函数来成立实例时,该函数的prototype属性值将被看做原型赋值给拥有指标实例(也正是安装实例的__proto__属性)

图片 28

1.3.2、Object

对此Object它是最顶层的靶子,全部的靶子都将继承Object的原型,不过你也要驾驭的精通Object也是3个函数对象,所以说Object是被Function构造出来的。

alert(Function instanceof Function);//true 
alert(Function instanceof Object);//true 
alert(Object instanceof Function);//true 

function Foo() {};
var foo = new Foo();
alert(foo instanceof Foo); // true
alert(foo instanceof Function); // false
alert(foo instanceof Object); // true
alert(Foo instanceof Function); // true
alert(Foo instanceof Object); // true

JavaScript 原型链

            function A() {this.x="x";};
            var a=new A();

            function B() {this.y="y"};
            B.prototype=a;
            var b=new B();

            function C() {this.z="z"};
            C.prototype=b;
            var c=new C();

            console.log(c instanceof C);
            console.log(c instanceof B);
            console.log(c instanceof A);
            console.log(c instanceof Object);

            console.log(c.x+","+c.y+","+c.z);

运行结果:

图片 29

当查找二个指标的习性时,JavaScript
会向上遍历原型链,直到找到给定名称的天性甘休,到找寻到达原型链的顶部(约等于Object.prototype),假若依旧没有找到钦点的质量,就会回去 undefined。

Object对象自作者是1个函数对象。既然是Object函数,就必将会有prototype属性,所以能够见见”Object.prototype”的值就是”Object
{}”这一个原型对象。反过来,当访问”Object.prototype”对象的”constructor”那天天性的时候,就获得了Obejct函数。
另外,当通过”Object.prototype._proto_”获取Object原型的原型的时候,将会博得”null”,也正是说”Object
{}”原型对象正是原型链的终点了。

1.四 、通过prototype增添对象

JavaScript内置了广大指标,如Array、Boolean、Date、Function、Number、Object、String 

设若大家想给String类型增加多个repeat方法,达成再一次字符,如”a”.rpt(),则将输出aa,”a”.rpt(5),输出“aaaaa”,因为String是JavaScript中置放的对象,能够透过修改该对象的原型达到目标:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>prototype原型</title>
    </head>
    <body>
        <script type="text/javascript">
            var v="hi";

            String.prototype.rpt=function(n)
            {
                n=n||2;
                var temp="";
                for(var i=0;i<n;i++) temp+=this;
                return temp;
            }

            console.log(v.rpt());
            console.log(v.rpt(10));
        </script>
    </body>
</html>

运营结果:

图片 30

示范中给String对象的原型扩大了1个rpt方法,全部的String都以衍生自String.prototype,那拥有的String对象都将获得rpt方法。

            //扩展String类型,增加trim方法用于删除字符串的首尾空格
            String.prototype.trim=function()
            {
                return this.replace(/^\s+|\s+$/igm,'');
            }

            console.log("[begin]"+"  Hello JavaScript  ".trim()+"[end]");

运转结果:

图片 31

为了扩张尤其便宜,能够修改Function的原型,给每三个函数衍生的靶子扩展方法method用于扩展。

            //修改函数对象的原型,添加method方法,扩展所有的函数
            Function.prototype.method=function(name,fun){
                //如果当前扩展的函数的原型中不包含名称为name的对象
                if(!this.prototype[name]){
                    //添加
                    this.prototype[name]=fun;
                }
            }

            String.method("show",function(){
                console.log("输出:"+this);
            });

            "Hello".show();
            "JavaScript".show();

运作结果:

图片 32

1.五 、通过prototype调用函数

我们得以经过对象调用有些方法,因为那个目的的原型中早已定义好了该方式,其实大家通过原型也足以直接调用有些方法,有些措施只设有原型中,唯有当前项目涉及了该原型才足以收获该方式,但有时候大家须要采纳该形式去处理非该原型下的对象,如:

            function add(x,y,z)
            {
                var array1=[].slice.call(arguments,0,3);
                console.log(array1);
                var array2=Array.prototype.slice.apply(arguments,[0,3]);
                console.log(array2);
            }
            add(1,2,8,9,10);

运营结果:

图片 33

以身作则代码:

            var str1 = "Hello JavaScript";
            console.log(str1.toUpperCase()); //传统的调用办法

            var str2=String.prototype.toUpperCase.apply(str1); //通过原形直接调用
            console.log(str2);

            var str3=String.prototype.toUpperCase.call(str1); //通过原形直接调用
            console.log(str3);

            var array1=[2,3,5,7,8,9,10];
            var array2=array1.slice(1,3);
            console.log(array2);

            var slice=Array.prototype.slice;
            console.log(slice.apply(array1,[1,3]));//通过原形直接调用
            console.log(slice.call(array1,1,3));

运行结果:

图片 34

演习:扩张Date,扩展三个来得粤语日期的法门,如:new
Date().trandition(),输出二〇一四年0十二月0十一日23点15分18秒;使用prototype的措施直接调用该方法。

1.6、prototype和__proto__的区别

图片 35

prototype是函数才有的属性,prototype本人正是一个指标,prototype对象中颇具constractor构造器(该构造器反向指回函数)

__proto__是目的涵盖属性,用于访问创建对象的系列所对应的原型

字面量创立的靶子(o={})或Object创立的对象__proto__指向Object.prototype

示例:

var a = {};
console.log(a.prototype);  //undefined
console.log(a.__proto__);  //Object {}

var b = function(){}
console.log(b.prototype);  //b {}
console.log(b.__proto__);  //function() {}

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <script>
            //构造方法,类,函数
            function Foo(name) {
                this.name = name;
            }

            var f1 = new Foo("zhangguo");

            //prototype是函数才有的属性,prototype本身就是一个对象,prototype对象中拥有constractor构造器(该构造器反向指回函数)
            console.log(f1.prototype);  //undefined
            console.log(Foo.prototype);  //function Foo.prototype
            //__proto__是对象带有属性,用于访问创建对象的类型所对应的原型
            console.log(f1.__proto__);   //function Foo.prototype
            console.log(Foo.__proto__);  //function(){}
            //Foo.__proto__ 就是Function.prototype

            console.log(Foo.__proto__===Function.prototype);  //true
            console.log(Foo.prototype===f1.__proto__);  //true


            //字面量创建的对象(o={})或Object创建的对象__proto__指向Object.prototype
            var o={};
            console.log(o.__proto__===Object.prototype);  //true
            var obj=new Object();
            console.log(obj.__proto__===Object.prototype);  //true
            var obj2=Object.create({});
            console.log(obj2.__proto__===Object.prototype);  //false

            //            console.log(obj1.prototype);
            //            console.log(obj1.__proto__);
            //            console.log(Foo.prototype);
        </script>
    </body>

</html>

结果:

图片 36

1.7、__proto__性能指向

图片 37

/*1、字面量方式*/
var a = {};
console.log(a.__proto__);  //Object {}

console.log(a.__proto__ === a.constructor.prototype); //true

/*2、构造器方式*/
var A = function(){};
var a = new A();
console.log(a.__proto__); //A {}

console.log(a.__proto__ === a.constructor.prototype); //true

/*3、Object.create()方式*/
var a1 = {a:1}
var a2 = Object.create(a1);
console.log(a2.__proto__); //Object {a: 1}

console.log(a.__proto__ === a.constructor.prototype); //false(此处即为图1中的例外情况)

 示例:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <script>
            //构造方法,类,函数
            function Foo(name) {
                this.name = name;
            }

            var f1 = new Foo("zhangguo");

            console.log(f1.constructor === Foo); //true
            console.log(f1.__proto__ === Foo.prototype); //true

            /*1、字面量方式*/
            var a = {};
            //a的__proto__是指向了a的构造器所指向的原型
            //字面量创建的对象的__proto__指向了Object的原型
            console.log(a.__proto__ === a.constructor.prototype); //true

            /*2、构造器方式*/
            var A = function() {};

            var a = new A();

            console.log(a.__proto__); //A的原型

            console.log(a.__proto__ === a.constructor.prototype); //true
            console.log(a.__proto__ === A.prototype); //true

            /*3、Object.create()方式*/
            var a1 = {a: 1}
            var a2 = Object.create(a1);

            console.log(a2.__proto__===a1);   //true,a1就是a2的原型(父类)
        </script>
    </body>

</html>

结果:

图片 38

1.8、原型链

图片 39

示例:

var A = function(){};
var a = new A();
console.log(a.__proto__); //A {}(即构造器function A 的原型对象)
console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)
console.log(a.__proto__.__proto__.__proto__); //null

示例:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <script>
            //构造方法,类,函数
            function Foo(name) {
                this.name = name;
            }

            var f1 = new Foo("zhangguo");
            //1、var f1={};
            //2、f1.__proto__=Foo.prototype;
            //3、Foo.call(f1,"zhangguo");

            //在Foo的原型中添加属性age
            Foo.prototype.age = 80;
            Foo.prototype.show = function() {
                console.log("name:" + this.name + ",age:" + this.age);
            }

            var f2 = new Foo("zhangsan");

            console.log(f1.age == f2.age);
            f1.show();
            f2.show();

            var A = function() {};
            var a = new A();
            console.log(a.__proto__); //A {}(即构造器function A 的原型对象)
            console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)
            console.log(a.__proto__.__proto__.__proto__); //null
        </script>
    </body>

</html>

结果:

图片 40

当查找二个目的的习性时,JavaScript
会向上遍历原型链,直到找到给定名称的性情停止,到找寻到达原型链的顶部(也等于Object.prototype),若是仍旧没有找到钦赐的性质,就会回来 undefined。

function Person(name, age){ 
    this.name = name; 
    this.age = age; 
  } 
Person.prototype.MaxNumber = 9999;
Person.__proto__.MinNumber = -9999;
var will = new Person("Will", 28); 
console.log(will.MaxNumber); // 9999 
console.log(will.MinNumber); // undefined 

在这些例子中分别给”Person.prototype “和”
Person.proto”那八个原型对象添加了”马克斯Number
“和”MinNumber”属性,那里就供给澄清”prototype”和”proto”的区分了。

“Person.prototype
“对应的正是Person构造出来有所实例的原型,也正是说”Person.prototype
“属于那个实例原型链的一局地,所以当那几个实例进行品质查找时候,就会引用到”Person.prototype
“中的属性。

对象创建方式影响原型链

var July = { 
   name: "张三", 
   age: 28, 
   getInfo: function(){ 
     console.log(this.name + " is " + this.age + " years old"); 
   }
 } 
console.log(July.getInfo()); 

当使用那种方法开创3个对象的时候,原型链就改成下图了.
July对象的原型是”Object.prototype”也便是说对象的塑造方式会影响原型链的款式。

图片 41

1.九 、构造对象

在JavaScript中,每一个函数
都有三个prototype属性,当三个函数被视作构造函数来创设实例时,这一个函数的prototype属性值会被当做原型赋值给全数指标实例(相当于设置
实例的`__proto__`质量),也正是说,全部实例的原型引用的是函数的prototype属性。(唯有函数对象才会有那些本性!)

new 的长河分成三步  

var p = new Person('张三',20);

1. var p={}; 初始化一个对象p。

2. p._proto_=Person.prototype;,将对象p的 __proto__ 属性设置为 Person.prototype

3. Person.call(p,”张三”,20);调用构造函数Person来初始化p。

 

① 、prototype是函数才有的属性

2、__proto__是各类对象都有的属性,它不是W3C的科班属性,它指向prototype

3、__proto__能够清楚为“构造器原型”,__proto__===constructor.prototype(Object.create()创立的靶子不适用)

肆 、当js引擎查找对象的属性时,先物色对象自小编是还是不是留存该属性,假若不存在会在原型链上查找,但不会寻找本身的prototype

伍 、函数的原型对象constructor暗中同意指向函数自身,原型对象除了有原型属性外,为了达成延续,还有一个原型链指针__proto__,该指针指向上一层的原型对象,而上一层的原型对象的社团照旧类似,那样利用__proto__直白指向Object的原型对象上,而Object的原型对象用Object.prototype.__proto__

null表示原型链的最上端,如此变形成了javascript的原型链继承,同时也表明了怎么全部的javascript对象都抱有Object的基本方法。

 

引用

叁 、JavaScript面向对象(OOP)

3.1、封装

因为在JavaScript中从未访问修饰符,也绝非块级效用域,this所定义的习性默许对外正是当面访问的,如下示例:

            function Animal(){
                this.name="动物";
                this.weight=0;  //重量
            }

            var cat=new Animal();
            cat.name="猫";
            cat.weight=-90;
            console.log(cat);

输出:

图片 42

weight是-90,不正确,封装:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <script type="text/javascript">
            function Animal() {
                this.name = "动物";
                var weight = 0; //重量
                this.getWeight = function() { //读 
                    return weight;
                };
                this.setWeight = function(_weight) { //写
                    if(_weight > 0) {
                        weight = _weight;
                    } else {
                        throw "动物的重量必须为正数";
                    }
                }
            }

            var cat = new Animal();
            cat.name = "猫";
            try{
                cat.setWeight(-90);
            }catch(e){
                console.log(e);
            }
            console.log(cat);
        </script>
    </body>

</html>

结果:

图片 43

            function Animal()
            {
                this.name="动物";
                this.getName=function(){
                    return this.name;
                }
                this.setName=function(name){
                    this.name=name;
                }
                this.bark=function(){
                    console.log(this.name+"在叫...");
                }
            }
            var animal=new Animal();
            animal.setName("小狗");
            animal.bark();

那里定义的二个构造函数,将name封装成属性,Animal函数自个儿用于封装动物的习性与行为,运营结果:

图片 44

3.2、继承

JavaScript的接续的落实首要依靠prototype(原型)来兑现,再充实七个动物,如狗与猫:

            function Animal()
            {
                this.name="动物";
                this.getName=function(){
                    return this.name;
                }
                this.setName=function(name){
                    this.name=name;
                }
                this.bark=function(){
                    console.log(this.name+"在叫...");
                }
            }

            function Dog(){
                this.hunt=function(){console.log("狗在捕猎");};
            }
            //指定Dog构造函数的原型对象,简单理解为父类
            Dog.prototype=new Animal();

            function Cat(){
                this.hunt=function(){console.log("猫在抓老鼠");};
            }
            Cat.prototype=new Animal();

            var dog=new Dog();
            dog.bark();
            dog.hunt();

            var cat=new Cat();
            cat.bark();
            cat.hunt();

运维结果:

图片 45

3.3、多态

java与C#中的多态首要展现在重载与重写上,因为JavaScript是弱类型的,类格局参数是动态钦定的所以并没有当真意义上的重载,只可以在点子中判断参数达到目标。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>JavaScript面向对象</title>
    </head>
    <body>
        <script type="text/javascript">
            function Animal()
            {
                this.name="动物";
                this.getName=function(){
                    return this.name;
                }
                this.setName=function(name){
                    this.name=name;
                }
                this.bark=function(){
                    console.log(this.name+"在叫...");
                }
            }

            function Dog(){
                this.hunt=function(){console.log("狗在捕猎");};
            }
            //指定Dog构造函数的原型对象,简单理解为父类
            Dog.prototype=new Animal();
            //重写原型对象中的bark方法
            Dog.prototype.bark=function(){
                console.log("汪汪...");
            }

            function Cat(){
                this.hunt=function(){console.log("猫在抓老鼠");};
            }
            Cat.prototype=new Animal();
            //重写原型对象中的bark方法
            Cat.prototype.bark=function(){
                console.log("喵喵...");
            }

            function play(animal)
            {
                animal.bark();
                animal.hunt();
            }

            var dog=new Dog();
            var cat=new Cat();
            play(dog);
            play(cat);
        </script>
    </body>
</html>

运维结果:

 图片 46

示例:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <script type="text/javascript">
            //二种重写的办法
            function Animal(name) {
                this.name = name || "动物";
                this.bark = function() {
                    console.log(this.name + "叫了:嗷嗷...");
                }
            };

            function Cat() {
                this.hunt = function() {
                    console.log(this.name + "正在捕老鼠!");
                }
            }
            Cat.prototype = new Animal("猫");
            Cat.prototype.bark = function() {
                console.log("喵喵");
            }
            var cat = new Cat();
            cat.hunt();
            cat.bark();

            function Dog() {
                this.hunt = function() {
                    console.log(this.name + "正在捕猎!");
                }
                this.bark = function() {
                    console.log("汪汪");
                }
            }
            //让Dog继承Animal,修改原型的指向
            Dog.prototype = new Animal("狗");
            var dog = new Dog();
            dog.hunt();
            dog.bark();

            //重载的办法
            function add(n) {
                if(typeof n === "number") {
                    return ++n;
                }
                if(n instanceof Array){
                    var sum=0;
                    for(var i=0;i<n.length;i++){
                        sum+=n[i];
                    }
                    return sum;
                }
            }
            console.log(add(100));
            console.log(add([1, 2, 3, 4, 5]));
        </script>
    </body>

</html>

结果:

图片 47

 

练习:请使用javascript实现2个简约工厂设计情势。

四 、示例下载

https://github.com/zhangguo5/javascript003.git

https://git.coding.net/zhangguo5/javascript_01.git

五、视频

http://www.bilibili.com/video/av17173253/