ES6学习(this指向、原型、原型链)

this相关

this指向

  1. 普通函数中this指向window
  2. 立即执行函数中this指向window
  3. 定时器中this指向window
  4. 构造函数中this指向创建的实例
  5. 对象中的函数的this指向当前的对象
  6. 事件函数中的this指向事件源(谁调用该事件就返回谁)

html代码:

    <div class="box">点击</div>

js代码:

 // 1.普通函数
    function fn (){
        console.log(this);
    }
    fn();// window
    // 2.立即执行函数
    (function(a){
        console.log(this);
    })(2);  // window
    // 3.事件函数
    document.querySelector(".box").onclick=function(){
        console.log(this);  // 事件源  <div class="box">点击</div>
    }
    // 4.定时器
    setTimeout(function(){
        console.log(this);  // window    这是一个异步函数
    })
    // 5.构造函数
    function build (name,age){
        this.name= name;
        this.age = age;
        console.log(this);
    }
    var pengerzi = new build("彭忠杰",18);   // this指向实例  build {name: '彭忠杰', age: 18}   

    // 6.对象中的函数
    var obj = {
        name:"彭忠杰",
        sex :"女",
        func:function(){
            console.log(this);
        }
    }
    // 调用对象中的函数
    obj.func();  // {name: '彭忠杰', sex: '女', func: ƒ}   this指向当前对象

改变this指向(call、apply、bind)

  • .call(需要修改的this指向,参数1,参数2,…)
  • .apply(需要修改的this指向,[参数1,参数2,…]),可用于求最值
  • bind(需要修改的this指向,参数1,参数2,…)

js代码

    // call  apply  bind   改变this指向
    var obj1 = {
        x:2,
        y:3
    };
    var obj2 = {
        x:4,
        y:5
    };
    var obj3 = {
        x:1,
        y:2
    };
    var x = 6,y=7;

    function back (x,y) {
        console.log(x,y);
        console.log(this.x,this.y);
    }
    back(2,3);   // 正常情况下this指向window,   window.back(2,3)  2 3 ;67


    // 使用call
    back.call(obj1,8,9);  // obj1不影响后面的参数  8 9 ; 23

    // 使用apply
    back.apply(obj2,[4,6]);  // 使用数组形式传参   4 6 ; 4 5

    // 使用bind
    var bin = back.bind(obj3,8,9);   // bind返回一个函数体,需要手动调用
    console.log(bin);  // 返回函数
    bin(); // 8 9 ; 1 2
apply求最值
    var arr = [6,5,9,4,2,3,4];
	// 使用Math的min或者max
	console.log(Math.max(6,5,9,4,2,3,4));   // 9
	// 使用apply
	console.log(Math.max.apply(Math,arr));  // 9 
三个相互比较
  • 相同之处:都可以改变this指向
  • 不同之处:
    1. 传参方式不同:apply的参数以数组的形式传入;bind和call以枚举的形式传入
    2. 调用方式不同:call和apply是直接调用;bind需要手动调用

原型

  • 成员:构造函数内部的属性
  • 实例成员:构造函数内部通过this创建的成员,可以通过this打印出来
  • 静态成员:后续添加的内容,可以访问,不能通过this获取到
  • 显式原型:prototype。 给构造函数使用
  • 隐式原型:__ proto__ 。 实例使用
    function Per(name, age) {
        // 实例成员,构造函数内部的成员
        this.name = name;
        this.age = age;
        this.aa = function () {  // 比较占内存 所以一般在原型上添加方法
            console.log(11);
        };
    }
    var zhangsan = new Per("张三", 15);
    console.log(zhangsan);

    // prototype 显式原型,只有构造函数使用显式原型
    console.log(Per.prototype);

    // __proto__ 隐式原型,实例使用隐式原型
    console.log(zhangsan.__proto__);

    console.log(Per.prototype === zhangsan.__proto__);   // 构造函数的显式原型与实例的隐式原型是全等的

    // 静态成员  后续添加的成员
    zhangsan.fun = function () {
        console.log("这里是张三");
    }

    console.log(zhangsan);   // 能打印出fun
    console.log(Per);    // 打印不到fun

    // 给原型添加方法 
    Per.prototype.fun2 = function () {
        console.log("这是通过原型添加的方法");
    }
    console.log(Per.prototype);   // 能打印出fun2
    console.log(zhangsan.__proto__);  // 能打印出fun2

    var lisi = new Per("李四", 16);
    console.log(lisi.aa);
    console.log(zhangsan.aa);
    console.log(lisi.aa === zhangsan.aa);   // false 每次创建对象时,都会为aa这个方法创建一个空间,所以是比较浪费内存的,一般在原型上创建方法

原型链

万物皆对象,对象皆为空:所有的元素通过查找原型,最终的结果都是“null”;
构造函数实例=》构造函数原型=》Object原型=》null

  function func(name, age) {
        this.name = name;
        this.age = age;
    }
    var pzj = new func("彭忠杰", 12);
    console.log(pzj);
    console.log(pzj.__proto__);
    console.log(func.prototype);
    console.log(pzj.__proto__ === func.prototype);  // 实例的隐式原型与构造函数的显式原型全等

    console.log("-----验证万物皆对象,对象皆为空---------------------------------");


    // 验证万物皆对象,对象皆为空
    // console.log(Object.prototype);
    console.log(Object.prototype.__proto__);    // null

    // 构造函数
    // console.log(func.prototype);
    console.log(func.prototype.__proto__.__proto__);  // null

    // 实例
    // console.log(ls.__proto__);
    // console.log(ls.__proto__.__proto__);
    console.log(ls.__proto__.__proto__.__proto__);  // null 


  • constructor 用于指向原来的构造函数
    构造函数可以通过prototype找到原型,原型可以通过constructor找到构造函数
 // constructor的用处:指向原来的构造函数


    func.prototype = {
        fn:function(){               // 将原型进行覆盖
            console.log(11); 
        },
    }
    var zs = new func("张三",13)
    console.log(zs.__proto__);  // 不能显示原来的原型

    func.prototype = {
        fn:function(){               // 将原型进行覆盖
            console.log(11); 
        },
        constructor:func,     // 指向构造函数,后面再通过new创建的对象就可以正常显示原型了
    }
    var ls = new func("李四",15);
    console.log(ls.__proto__);  // 能正常显示原来的原型了

总结

  1. 构造函数的命名:首字母大写
  2. Date、String、Math、Array等都相当于构造函数,我们平时用的字符串、数组的方法都是封装在原型中的方法
  3. 构造函数有一个缺点,就是如果方法直接写在里面,每次创建新对象都会开辟一个新的空间,会占用内存,所以我们一般不直接在构造函数中添加方法,而是在原型中创建方法
  4. 万物皆对象,对象皆为空的意思是所有的元素都可以一层一层往上找,最终找到null

案例展示

我们通过给原型上添加方法,由其他元素进行调用,尝试做出一个Tab切换的效果。具体思路:创建构造函数,给构造函数的原型上添加方法,在构造函数内写好各种事件,最后通过new关键字,创建实例对象:

html代码:

<div id="bigBox">
        <div class="btnBox">
            <button class="color">按钮一</button>
            <button>按钮二</button>
            <button>按钮三</button>
        </div>
        <ul class="list">
            <li class="block"></li>
            <li></li>
            <li></li>
        </ul>
    </div>

css代码:

        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        .list>li {
            width: 300px;
            height: 300px;
            display: none;
        }

        .list>li:nth-child(1) {
            background-color: #f0f;
        }

        .list>li:nth-child(2) {
            background-color: #0ff;
        }

        .list>li:nth-child(3) {
            background-color: #ff0;
        }
        .list .block{
            display: block;
        }
        #bigBox .color{
            background-color: #ff4200;
            color: #f0f00f;
            border: 0;
        }

js代码:

 function Change(id) {
        var oBox = document.getElementById(id);
        this.btns = oBox.querySelectorAll("button");
        this.lists = oBox.querySelectorAll("li");

        // 绑定事件
        for (i = 0; i < this.btns.length; i++) {
            this.btns[i].onclick = this.qiehuan.bind(this,i);
        }
    }
    Change.prototype.qiehuan = function (a) {
        // 先清除所有的样式
        for(var j = 0 ; j < this.lists.length ; j ++){
            this.lists[j].className = "";
            this.btns[j].className = '';
        }
        this.lists[a].className = "block";
        this.btns[a].className = 'color'; 
        
    }
    var oClick = new Change("bigBox");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值