Js-原型链-this,构造函数-继承:call语法,以及实现。对象原型__proto__

js进阶第三天

成长必经之路

目录

  1. 构造函数: 原型对象及原型链
  2. 构造函数: 继承

##构造函数-原型对象

构造函数的实例成员

目标: 实例成员的内存问题

  • 通过构造函数封装后,创建多个对象,对象调用同一个方法,在内存中执行的并不是同一个方法
//1.构造函数设置形参
        function Person(name, age) {
            this.name = name;
            this.age = age;
            this.sing = function () {
            console.log("我会唱歌");
       }
 }
//创建:创建是实例化对象!
let p1 = new Person("zs", 18);  let p2 = new Person("ls", 28);
//问题
//1.实例化对象功能方法:打印结果一摸一样
console.log(p1.sing); //调用,我会唱歌
 console.log(p2.sing);  //我会唱歌
// 2.回顾,函数是什么数据类型?复杂
        console.log(p1.sing == p2.sing); //false
//3.结论:两个方法是功能完全一样,来自各功能的实例化对象;但是内存是不同的地址;形成内存浪费!
  • 如上问题会导致内存浪费, 传统方式也是这样的问题

原型对象prototype

目标: 知道什么是原型对象prototype及作用

  • prototype: 叫原型对象,是每一个构造函数身上的一个属性,该属性是以对象的形式存在的(原型对象)

    //导入:
    //构造函数:学习其他的知识是可以解决内存浪费的问题
    //字面量的方式:到此为止;不能解决内存浪费的问题!
    
    //知识:
         //prototype是属性名,构造函数上属性:prototype
         //值:对象;如果给自定义构造函数上添加方法,添加到prototype属性值对象上!
         //解决内存的问题!
     function Person(name, age) {this.name = name;this.age = age }
            //语法
            Person.prototype.sing = function () {
                console.log("我会唱歌");
            }
            Person.prototype.eat = function () { console.log("我会跳舞"); }
            //调用:实例化对象
            let p1 = new Person("zs", 15)
            let p2 = new Person("ww", 19)
            //测试1:是否有sing方法
            p1.sing(); p2.sing()   //我会唱歌
            //测试2:看两个方法是否功能是一样?
            console.log(p1.sing);   //ƒ () {console.log("我会唱歌");}
            console.log(p2.sing);  //ƒ () {console.log("我会唱歌");}
            console.log(p1.eat);    //ƒ () {console.log("我会跳舞");}
            console.log(p2.eat);    //ƒ () {console.log("我会跳舞");}
            //测试3:测试两个方法是否来自同一个内存空间 ?(内存地址)
            console.log(p1.sing == p2.sing);   //true
    // 结论:学习prototype,给未来的实例化对象上设置一些方法,直接设置给 构造函数.prototype上,
    //       Fn/Person:   构造函数
    //       let p1 = new Person();  实例化对象;
     //       prototype     原型对象;
    
  • 作用: 通过原型对象设置构造函数中功能的方法, 设置公共方法, 解决内存浪费问题!

  • 语法: 构造函数.prototype.方法名 = function(){ };

对象原型__proto__

目标: 能够了解__proto__的作用

  1. 导入: 解释数组的实例化, 为什么都可以使用push方法? 而且是同一个功能, 同一个地址!
  2. 为什么实例化 会有构造函数原型 prototype上的方法
    1. 实例化对象上有一个属性名 proto , 属性值是一个对象; proto 上保存有对象的地址, 地址指向哪里? 指向构造函数的prototype
    2. ldh.__proto__==Star.prototype 返回true; 保存了一个地址, 是同一个地址;
 function Person(name, age) {this.name = name;this.age = age;};
    // 语法:
 Person.prototype.sing = function () {console.log("我会唱歌");};
    // 实例化
    let p1 = new Person("zs", 15);
    let p2 = new Person("ls", 26);
// ***问题1:p1  p2 为什么上有sing这个方法?
// 知识:
    //实例化对象:对象就会有 __proto__:上面有sing方法  有属性:constructor
    //注意:__前后都是两个下划线
// true:p1.__proto__ 和 原型对象 其实是一个东西;
    //原型对象上有sing   p1.__proto__上也有同样这个sing方法
    console.log(p1.__proto__ == Person.prototype);  	//true
    console.log(p2.__proto__ == Person.prototype); 		//true
// ***问题2:为什么这样调用呢 p1.sing();  合理:p1.__proto__.sing();
    // __proto__:原型链:
    // 记住规则:如果 实例化对象.xxx(); 
    //    1.先在自己实例化对象上先找下是否有xxx方法,如果没有;
    //    2.会去实例化.__proto__去找;
    // __proto__:非标准属性,开发过程中不出现代码;
    //            为了给方法寻找提供链的方向;
    console.log(p1);   //Person {name: "zs", age: 15}

constructor构造函数

目标: 掌握constructor及作用

  • 概念: constructor构造函数,每一个原型对象prototype和对象原型身上都有属性
  • 作用: 通过constructor构造函数记录当前对象属于哪个构造函数的
 //构造函数:创建对象,实例化对象
        // 封装插件
        // 创建对象比直接使用字面量形式创建对象更加性能好
function Person() {}
// 原型对象:添加占内存一个空间方法;
//          默认自带属性:constructor:构造函数;
// console.log(Person.prototype.constructor);
//          意义:通过原型对象,    知道隶属于哪个构造函数而已!
//               实例化.__proto__  知道实例化对象由谁构造出来!
let p1 = new Person();
  console.log(p1);   //Person {}
  • 构造函数,原型对象,对象原型之间的关系

在这里插入图片描述

原型链

目标: 原型链及作用

概念: 每一个对象都会__proto__,指向是哪里的地址呢?

  • 原型链的形成:
    • 每一个对象有一个__proto__属性,地址指向为其构造函数的原型对象prototype,及为同一个对象;
      构造函数的原型对象prototype也是一个对象,也有__proto__属性,这样一层一层往上找就形成了原型链;
  • __proto__的意义:就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此
    实际开发中,不可以使用这个属性,我们只需要知道它的指向和构造函数的prototype指向同一个地址;
  • 为什么要设置原型链?给对象上的方法设置查找机制:
    • 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性或方法。
    • 如果没有就查找它的原型对象(也就是 __proto__指向的 prototype 原型对象)。
    • 如果还没有就查找原型对象的原型(Object的原型对象)。
    • - 依此类推一直找到 Object 为止(null)。
    • - 如果还没有,就报错这个对象没有这个方法; Uncaught Typ

在这里插入图片描述

 // 原型链
        function Person(name, age) {
            this.name = name;
            this.age = age;
        }
        Person.prototype.sing = function () {
            console.log("我会唱歌");
        }
        //实例化对象:
        let p1 = new Person("zs", 18)
        //原型对象:也是对象,发现这个对象上_proto_
        // 对象其实也应该是某个构造函数的实例化对象
        let obj1 = Person.prototype;
        //Object:date内置构造函数
        //{}字面量简单方式 object();内置构造函数的方式,创建空{}
        // Object.prototype
        console.log(Object.prototype == obj1._proto_);  //true
        //obj1  其实就是objet一个实例化

        // 原型链,不是逻辑, 是客观存在; 是什么 ? 一个对象,有_proto_ 指向其原型对象: 原型对象其实也是个普通对象,
        //    也有proto_属性,指向其原型对象Object.prototype;

原型链 -this

// this
        let c;
        function Person() {
            this.name = "zs";
            this.age = 18;
        }
        Person.prototype.sing = function () {
            console.log("我会嫦娥");  //我会嫦娥
            c = this
        }
        let a = new Person()
        a.sing()  //this赋值一份给c
        console.log(c == a);  //true
        //-----------------使用------------------------
        //落地:构造函数内部this,型对象上方法内this其实都是未来其次实例化对象!
        function Person() {
            this.name = "zs"
            this.age = "28"
        }
        Person.prototype.sing = function () {
            console.log(this.name + "会唱歌");  //true
        }
  • 练习:

    1.查看原型对象上方法内部this的指向

    2.给数组Array的原型对象上拓展求和的方法;

// 需求:让  你在  数组原型对象 上  添加一个求和的方法;getSum
//     1. 找到 数组 原型对象  Array.prototype
// console.log(arr.__proto__); // 非标准属性,开发不用!
 // console.log(Array.prototype); // Array Object 内置构造函数名!
//     2. 往对象上填加新的方法
  Array.prototype.getSum = function() {
    //   3. 求和:数组求和封装为一个方法  
    //      封装步骤:
    //        1.实际过程;
    //        2.套个函数壳子;
    //        3.设置形参(调用的时候是否需要传入实参)?返回值(调用的时候,看是否要得到函数执行结果)?
    //      this考虑:实例化对象;
    var sum = 0;
    for (var i = 0; i < this.length; i++) {
      sum += this[i];
    }
    return sum;
  };
// 遇到报错:
  //     1.解读英文   "xxx" of null / undefined  
  //     2.告诉报错位置;
  var arr = [10, 20, 30];
  var res = arr.getSum();
  console.log(res);

构造函数-继承

继承

目标: 掌握属性和方法继承

实例属性的继承: 直接复制?

//1------------------手动复制方式:维护不方便!
//           other内部属性名发生改变,My内部不会自动改变!
function Other(house, money,car){
   this.house = house;
    this.money = money;
    this.car = car;}
function My(house,money,car) {
    this.house = house;
    this.money = money;
    this.car = car;}

实例属性的继承: call语法

// 2---------------------新的语法:一次性把对方身上所有属性全部拿过!
// call:打电话呼叫;基础语法
//
function other(house,money,car){
    this.house = house;
	this.money = money;
    this.car = car;}
var obj = {
info:"我就是个单独对象"};
other.call(obj,102010);
// call语法规则:【需要重点记忆】
//  1.Other丞数肯定是要执行!
//	2.参数:第一个参数other执行,other内部this上的所有的属性名即将要去到这个参数上;
//  3.剩余参数,必须逗号分隔;就是oTher执行时,需要传入的实参;
console.log(obj);

实例属性的继承: call方式实现

//构造函数的内部数据的继承:
function other(house, money,car) {
    this.house = house;
	this.money = money;
    this.car = car;}
function My2(a, b,){
    //这个My2构造函数内部的实例化对象
    other.call(this,a, b,c);
	//相当于:
// this.house = a;
//this.money = b;
// this.car - c;}

###继承

原型对象上的方法继承

//别人写好杓造函数+原型对象
function other(house){
    this.house = house;
}
other.prototype.show = function() {
	console.log("你看老子多有钱,我有”+this.house +“套房子");
};
Other.prototype.sing - function() {
	console.log(“你看老子多有钱,我会唱歌“);
};
//自己:
function My (house){
other.call(this,house);
}
方式1: 把其他构造函数的原型对象直接使用( 不可取)
My.prototype = other.prototype;
My.prototype.dance = function() {
	console.log("我会跳舞");
}
// m实例化:上面有show sing dance这些方法没有问题; 
// var m = new My(10);
// m.show();
// m.sing();
//ll m.dance();
//执行结果:o这个实例化也有dance这个方法,other.prototype被修改了!
var o = new other(2e);
console.log(o);
方式2: 直接修改原型对象的__proto__属性值为 对方的原型对象( 逻辑正确, 代码不合适)
//默认情况:My.prototype._proto_ -= Object.prototype
//现在修改:相当于做了手术,做了修改,把other原型对象上方法继承过来;
My.prototype._proto_ = other.prototype;
// 1.测试My
My.prototype.dance = function() {
console.log("我是y原型对象上方法dance");
};
方式3: 最终方案
My.prototype = new other();
// My.prototype 本质是_proto__ : Object的原型对象﹔自带了constructor:My;1/
//    想被替换为_proto__本来就是指向other原型对象;
//    let o = new other(); o._proto__本来就是指向other原型对象﹔
My.prototype.constructor = My;
//对上面的分解
//var o = new other(50); // o{house:50 ,__proto__:other.prototype}
// My.prototype = o;
My .prototype.dance = function() {
console.log("我是ly原型对象上一个方法");
}
继承-示意图

C:\Users\27222\Pictures\笔记照片
记得三连呦,是个新手。知识点都是自己平常整理的,记得点赞关注。谢谢

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值