原型链

首先回顾下实列、构造函数、原型对象之间的关系;

实列都包含指向原型对象的一个指针(_proto_);

构造函数都有prototype(原型属性)指向原型对象的指针;

原型是一个对象也存在一个内部属性(_proto_)指向父类(上一级)原型对象;

那么原型链就是:实例通过 _proto_ 递归往上查找就构成实例与原型的链条(object除外,它是基类);

function Person(){

    }

链图:

总结:

1、所有引用类型默认都继承Object

2、所有函数的默认原型都是Object的实例,类似于:原型对象=new Object(),因此默认原型都会包含一个内部指针(_proto_),指向Object.Prototype;

3、所有引用类型对象都有_proto_属性指向原型对象,所有function 对象都有prototype 属性,指向原型对象;

原型链-继承

我所知道的继承有两种方式:

1、接口继承:只继承方法签名;

2、实现继承:继承实际的方法;

因为js中函数没有签名所以无法实现接口继承,只支持方法继承,并且是依靠原型链来实现的;

    function Person(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;

    }
    Person.prototype.sayHello=function(){ console.log("hello word!")};

   function Man(){

   }
    Man.prototype=new Person();
    var instance=new Man();
    console.log(instance.sayHello);// hello word!

以上就是很简单的继承,把Man原型指针指向Person的一个实例,这样new Man()的实例就可以访问到Person中的sayHello方法,如图所示;

原型链也是存在一些问题把上面代码改下:

    function Person(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.color=["red","blue","green"];

    }
    Person.prototype.sayHello=function(){ console.log("hello word!")};

   function Man(){

   }
    Man.prototype=new Person();
    var instance=new Man();
    instance.color.push("black");
    console.log(instance.color);//["red", "blue", "green", "black"]
    var instance2=new Man();
    console.log(instance2.color); //["red", "blue", "green", "black"]

我们知道原型是所有实例共享属性、方法,当使用原型来实现继承时,原型实际上会变成另一个类型的实例,所以就会出现上面的问题;

组合继承

组合继承的原理很简单,在构造子类对象实例的时候通过改变this 指针让子类对象实例拥有父类属性以及自身构造的属性,这样可以达到实例之间有独立的属性副本,

方法的继承还是通过原型来实现,来看代码:

  function Person(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.color=["red","blue","green"];

    }
    Person.prototype.sayHello=function(){ console.log("hello word!")};

    function Man(name,age,sex,job){
        Person.call(this,name,age,sex);
        this.job=job;
    }
    Man.prototype=new Person();
    var instance=new Man("张三",20,"男","农民");
    instance.color.push("black");
    console.log(instance.color);//["red", "blue", "green", "black"]
    console.log(instance.job);//农民
    console.log(instance.sayHello);//hello word!

    var instance2=new Man("张三",20,"男","地主");
    console.log(instance2.color); //["red", "blue", "green"]
    console.log(instance2.job);//地主
    console.log(instance2.sayHello);//hello word!

通过在构造函数中指向父类,这样实例对象存在父类的属性,前面说过搜索原理是从实例开始的,那么即使是原型对象是父类的实例对象,属性还是取的是实例对象中的属性;

组合模式是JavaScript中常用的继承方式;

call、apply、bind(绑定)

JavaScript中函数可以通过3种方法改变自己的this指向,它们是call、apply、bind。它们3个非常相似,但是也有区别。下面表格可以很直观看出三者的不同

方法 是否直接执行函数 传入的参数 调用方式
call

(context,arg1,arg2,arg3...)

第二个参数之后都是实参

function.call(context,arg1,arg2,arg3...)

apply

(context,[arg1,arg2,arg3...])

第二个参数必须是数组

function.apply(context,[arg1,arg2,arg3...])

bind

(context,arg1,arg2,arg3...)

第二个参数之后都是实参

var newFunction = function.bind(context);

newFunction(arg1,arg2,arg3...)

call和apply功能:使用指定的对象调用当前函数。call和apply的功能完全相同,只是在语法上略有不同。

call :

var a = {x: 1};
    var b = function (y, z) {
        console.log(this.x + y + z)
    };
    b.call(a, 3, 4);//此时b的this(即b执行时的上下文)被改变为a,因此this.x为1,第二个参数之后都是传给b实参。

apply:

 var a = {x: 1};
    var b = function (arr) {
        console.log(this.x + arr[0] + arr[1])
    };
    b.call(a, [3, 4]);//此时b的this(即b执行时的上下文)被改变为a,第二个参数是一个数组

bind:

var a = {x: 1};
    var b = function (y, z) {
        console.log(this.x + y + z)
    };
    var newB = b.bind(a);//此时b的this(即b执行时的上下文)被改变为a,由此生成一个新函数,函数不会立即执行。
    newB(3, 4);//函数此时才执行

call或apply是将执行上下文对象换了后,立即执行;而bind是将执行上下文对象换了后,创建一个新函数。

function fun(){
               console.log(this.name);
           }
           function obj1(){
               this.name = 'call||apply';
           }
           function obj2(){
               this.name = 'bind';
           }
           var o1 = new obj1();
           var o2 = new obj2();
           fun.call(o1);
           //手动调用bind创建的新函数
           fun.bind(o2)();

在网上找了张比较完整原型链图:

总结

1、原型链的形成真正是靠 _proto_,指向原型对象;

2、引用类型默认都继承Object;

3、所有函数的默认原型都是Object 实例,即默认原型对象也有一个内部属性 _proto_指向 Object prototype 对象;

4、Function.prototype是函数类型的原型;

5、继承主要是基于原型链实现的,而原型链主要是基于实例与原型对象链条实现,引用类型任何对象都有内部属性 _proto_指向原型对象;

javaScript-原型、继承-02的更多相关文章

  1. 再谈javascript原型继承

    Javascript原型继承是一个被说烂掉了的话题,但是自己对于这个问题一直没有彻底理解,今天花了点时间又看了一遍<Javascript模式>中关于原型实现继承的几种方法,下面来一一说明下 ...

  2. 彻底理解Javascript原型继承

    彻底理解Javascript原型继承 之前写过一篇Javascript继承主题的文章,这篇文章作为一篇读书笔记,分析的不够深入. 本文试图进一步思考,争取彻底理解Javascript继承原理 实例成员 ...

  3. [转]Javascript原型继承

    真正意义上来说Javascript并不是一门面向对象的语言,没有提供传统的继承方式,但是它提供了一种原型继承的方式,利用自身提供的原型属性来实现继承.Javascript原型继承是一个被说烂掉了的话题 ...

  4. JavaScript原型继承工作原理

    原型继承的定义 当你阅读关于JS原型继承的解释时,你时常会看到以下这段文字: 当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止.——出自JavaScript秘 ...

  5. 【读书笔记】读《编写高质量代码—Web前端开发修炼之道》 - JavaScript原型继承与面向对象

    JavaScript是基于原型的语言,通过new实例化出来的对象,其属性和行为来自于两部分,一部分来自于构造函数,另一部分是来自于原型.构造函数中定义的属性和行为的优先级比原型中定义的属性和优先级高, ...

  6. JavaScript 原型继承开端

    1.原型继承本质       就javascript对象系统的实现来讲,对象并没有原型,而构造器有原型(构造器.prototype指向其原型).对象只有构造自某个原型的说法,并没有持有某个原型的说法. ...

  7. 浅析Javascript原型继承(转)

    引自: http://blog.csdn.net/kittyjie/article/details/4380918 原作者解释的浅显易懂,非常不错的JavaScript prototype总结 JS没 ...

  8. Javascript原型继承容易忽略的错误

    编写Javascript的开发者都知道,JS虽然没有类(ES6添加了class语法),但是可以模拟出OOP语言的类和面向对象的概念,比如我们都知道的一句话,Javascript中处处是对象,而面向对象 ...

  9. javascript原型继承圣杯模式

    javascript纯面向对象开发需要使用到的一个模式,来对对象之间原型继承做中间层代理避免重复继承与代码杂乱 <!DOCTYPE html> <html lang="en ...

  10. javascript原型继承

    在传统的基于Class的语言如Java.C++中,继承的本质是扩展一个已有的Class,并生成新的Subclass. 由于这类语言严格区分类和实例,继承实际上是类型的扩展.但是,JavaScript由 ...

随机推荐

  1. vhosts.conf

    <VirtualHost *:80> ServerAdmin webmaster@dummy-host.example.com DocumentRoot "/opt/lampp/ ...

  2. JQuery Mobile实现手机新闻浏览器(2)

    在上一篇文章中,已经讨论了程序的结构和页面的布局,并简单介绍了一些jQuery Mobile的使用技巧.在本篇文章中,笔者将继续完成我们web应用的新闻浏览器的设计. 程序的启动 我们现在来研究一下程 ...

  3. 嵌入式 H264视频通过RTMP直播

    前面的文章中提到了通过RTSP(Real Time Streaming Protocol)的方式来实现视频的直播,但RTSP方式的一个弊端是如果需要支持客户端通过网页来访问,就需要在在页面中嵌入一个A ...

  4. 从date中获取相应信息

    创建测试用表: CREATE OR REPLACE VIEW v AS SELECT TO_DATE('2015-5-5 13:14:15', 'YYYY-MM-DD HH24:MI:SS') AS ...

  5. linux中清除cache的方法

    在进行测试文件导入的时候,发现内存占用很大,如下所示: [root@python ~]# vmstat 1 -S M 3 procs -----------memory---------- ---sw ...

  6. 重新开始吧(ADB+AndroidManifest.xml)

    我现在默认已经搭建好了开发环境.如果没有,可以参见去Google一下,或者我上两篇文章中也有提到. 先补充一点: SDK不用FQ.也能更新 修改hosts文件 下载sdk版本: 在hosts文件中追加 ...

  7. 数往知来 ASP.NET 表单的提交_url传值_重定向 <十八>

    一.表单提交时注意 如果是以get方式提交数据的时候,在接收时是用QueryString方式进行接收 如果是以post请求数据时在接收时是用Form进行接收 为什么么要这样做呢?我们用Request[ ...

  8. 移动开发必备!15款jQuery Mobile插件

    移动互联网的发展,来自PC端的网页并不能完全自适应移动端页面需求,使得响应式设计体验产生并成为潮流,也正是这样一种需求,促成了jQuery Mobile的流行.jQuery Mobile这样一款基于j ...

  9. CSS抗锯齿 font-smoothing

    CSS3里面加入了一个“-webkit-font-smoothing”属性. 这个属性可以使页面上的字体抗锯齿,使用后字体看起来会更清晰舒服. 加上之后就顿时感觉页面小清晰了. 淘宝也在用哦! 它有三 ...

  10. 轻松学习Linux之AWK使用初步

    AWK最初是Unix平台上一种可以对文本进行逐行处理的编程语言,它来源于3个创作者的名字:Aho.(Peter)Weinberg和(Brain)Kernighan. 现在广泛应用于Linux,他与se ...