JavaScript高级

构造函数

  1. new关键字的执行过程:

  1. 在内存中创建一个空对象

  1. this指向这个空

  1. 给空对象添加属性和方法

  1. 构造函数不需要return

静态成员和实例成员

构造函数里面的属性和方法 我们称为成员

function Star(uname, age) {
            this.uname = uname;
            this.age = age;
            this.sing = function () {
                console.log('我会唱歌');
            }
        }

实例成员 就是构造函数内部 通过this指向的成员,上述代码中,uname、age、sing就是实例成员

var dlrb = new Star("迪丽热巴", 18);
        console.log(dlrb.uname);
        console.log(Star.uname);

实例成员只能通过实例化对象来访问

        Star.address = "哈尔滨";
        console.log(dlrb.address);      
        console.log(Star.address);

静态成员 在构造函数上添加的成员

静态成员 只能通过构造函数来访问

构造函数的问题

        function Star(uname, age) {
            this.uname = uname;
            this.age = age;
            //问题就是多个对象的方法会占用好多内存,浪费内存
            // this.sing = function () {
            //     console.log('我会唱歌');

            // }
        }

        //每一个构造函数都有一个属性 指向原型对象 prototype

        console.dir(Star)
        Star.prototype.sing = function () {
            console.log('我会唱歌');
        }
        var ldh = new Star('刘德华', 18);
        var zxy = new Star('张学友', 19);
        console.log(ldh, zxy);
        ldh.sing();
        console.log(ldh.sing === zxy.sing);

        

一般情况,我们的公共属性定义到构造函数里面

公共的方法放到原型对象上

对象原型__proto__

var obj = {};
        console.dir(obj)

        // var arr = [];
        // console.log(arr);

        function Star(uname, age) {
            this.uname = uname;
            this.age = age;
        }
        var dlrb = new Star("迪丽热巴", 18);
        // 对象身上系统自己添加了一个__proto__  
        // 构造函数有一个属性叫prototype
        // 对象的__proto__  指向 构造函数的prototype

        console.log(dlrb);
        console.log(dlrb.__proto__ === Star.prototype);

        //查找规则
        //首先看自己对象本身有没有这个方法  有的话 执行自己的
        //如果没有  就去原型对象查找  找到就可以执行

原型

function Star(uname, age) {
            this.uname = uname;
            this.age = age;
        }
        // Star.prototype.sing = function () {
        //     console.log("我会唱歌");
        // }
        // Star.prototype.eat = function () {
        //     console.log("我会吃");
        // }

        Star.prototype = {
            // 如果我们修改了原来的原型对象,给原型对象重新赋值 一个新的对象,导致原来的原型对象的constructor属性消失
            //解决办法:手动添加一个constructor 属性
            sing: function () {
                console.log("我会唱歌");
            },
            eat: function () {
                console.log("我会吃");
            },
            // constructor 是原型对象的属性
            constructor: Star
        }

        var fdd = new Star();
        console.log(Star.prototype);
        // 构造函数的 prototype对象默认都有一个 constructor属性,指向 prototype 对象所在函数。
        console.log(Star.prototype.constructor);
        console.log(fdd.__proto__.constructor);

原型链

 function Star(uname, age) {
            this.uname = uname;
            this.age = age;
        }
        Star.prototype.sing = function () {
            console.log('我会唱歌');
        }
        var ldh = new Star('刘德华', 18);

        // 只要是对象 就有一个属性 __proto__ 原型 , 指向原型对象
        console.log(Star.prototype);
        // Star.prototype 原型对象  本质也是一个对象  所以有__proto__ 原型, 指向Object原型对象
        console.log(Star.prototype.__proto__);
        console.log(Star.prototype.__proto__ === Object.prototype);
        // Object原型对象 本质也是一个对象  所以有__proto__ 原型   指向null
        console.log(Object.prototype.__proto__);

原型对象的this指向

function Star(uname, age) {
            this.uname = uname;
            this.age = age;
        }

        var that;
        Star.prototype.sing = function () {
            console.log("唱歌");
            console.log(this);
            that = this
        }
        // 1. 在构造函数中,里面this指向的是对象实例 ldh
        var ldh = new Star('刘德华', 18);
        // 2、在原型对象函数里  this也指向实例化对象 ldh
        ldh.sing();
        console.log(that === ldh);

给内置对象新增方法

 //给原型对象扩展这个求和的方法
        Array.prototype.sum = function () {
            var sum = 0;
            for (var i = 0; i < this.length; i++) {
                sum += this[i]
            }
            return sum;
        }

        var arr = [1, 2, 3];
        console.log(arr.sum());

        console.log(Array.prototype);

call方法

function fn(a, b) {
            console.log("今天星期一");
            console.log(this);
            console.log(a + b);
        }
        // fn();

        var obj = {
            uname: "fanfan"
        }

        // 1、调用函数
        // fn.call();

        //2、改变this指向  第一个参数 就是this的指向  剩下的参数就是正常传参数
        fn.call(obj, 1, 2)

继承

// 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数实例的对象
            this.uname = uname;
            this.age = age;
        }

        //子构造函数
        function Son(uname, age) {
            // this 指向子构造函数实例的对象
            Father.call(this, uname, age)
        }

        var son = new Son("xiaoxiao", 18)
        console.log(son);

借用原型对象继承方法

  // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        Father.prototype.money = function () {
            console.log(1000000000);
        }
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age);
            this.score = score;
        }

        //这样直接赋值会有问题 改了子构造函数原型上的方法  父原型对象也会跟着修改
        // Son.prototype = Father.prototype;
        Son.prototype = new Father();
        //如果利用对象的形式修改原型对象,千万别忘了改这个constructor属性  指回原来的构造函数
        Son.prototype.constructor = Son;

        Son.prototype.study = function () {
            console.log("儿子就的学习");
        }
        console.log(Father.prototype);
        console.log(Son.prototype.constructor);

函数的定义和调用方式

        //1、自定义函数(命名函数)
        function fun() { }
        fun();

        //2、函数表达式(匿名函数)
        var fn = function () { }
        fn();

        //3、利用new Function("参数1","参数2"...,函数体)

        var f = new Function("a", "b", "console.log(a+b)");
        f(1, 2);
        // 所有的函数  都是 Function的实例对象
        console.dir(f)

        // instanceof
        // 函数也属于对象
        console.log(f instanceof Object);

函数的调用方法

// 1. 普通函数
        function fn() {
            console.log('人生的巅峰');

        }
        fn();
        fn.call()


        // 2. 对象的方法
        var o = {
            sayHi: function () {
                console.log('人生的巅峰');

            }
        }
        o.sayHi();

        // 3. 构造函数
        function Star() { };
        new Star();

        //4、绑定事件函数
        btn.onclick = function () { };//点击按钮调用函数

        //5、定时器
        setInterval(function () { }, 1000);//每隔1秒调用这个函数

        //6、立即执行函数
        (function () { })()  //立即执行函数 自动调用

this的指向

// 函数的不同调用方式决定了this 的指向不同
        // 1. 普通函数 this 指向window
        function fn() {
            console.log('普通函数的this' + this);
        }
        fn()

        // 2. 对象的方法  this指向的是对象 o
        var o = {
            sayHi: function () {
                console.log('对象方法的this:' + this);
            }
        }
        o.sayHi();

        // 3. 构造函数 this 指向 实例对象
        function Star() { };
        Star.prototype.sing = function () {
            console.log(this);
        }
        var ldh = new Star();

        //4、绑定事件函数 this 指向  事件源
        var btn = document.querySelector('button');
        btn.onclick = function () {
            console.log('绑定时间函数的this:' + this);
        };

        // 5. 定时器函数 this 指向的也是window
        window.setTimeout(function () {
            console.log('定时器的this:' + this);

        }, 1000);

        // 6. 立即执行函数 this还是指向window
        (function () {
            console.log('立即执行函数的this' + this);
        })();

apply方法

//apply 方法  也可以改变this的指向
        function fn(arr) {
            console.log(this);
            console.log(arr);//"fanfan"
        }
        // fn();

        var obj = {
            name: "fanfan"
        }
        var arr = [1, 2]
        fn.apply(obj, arr)
        fn.apply(obj, arr)

        //1、apply可以调用函数  也可以变this的指向
        //2、它的参数必须是数组(伪数组)
        //3、apply的主要应用   比如 我们可以利用apply借助于数学内置对象求数组的最大值  最小值
        var arr = [1, 2, 3, 3, 4];
        var max = Math.max.apply(Math, arr);
        console.log(max);
//apply参数传递规则
     // function foo() {
        //     var str = Array.prototype.join.apply(arguments, ["-"]);
        //     return str;
        // }
        // var str = foo(1, 2, 3, 4, 4)
        // console.log(str);


        var str = ""
        function fn(arr) {
            console.log(this);
            str += arr;
            return str;
        }
        // fn();

        //apply 方法在调用的时候  会将数组里面每一个元素拿出来,作为形参,挨个传递给函数
        var obj = {
            name: "fanfan"
        }
        var arr = [1, 2]
        var res = fn.apply(obj, arr)
        console.log(res);

bind方法

/bind方法 改变this的指向  不会立即执行

        var obj = {
            name: "fanfan"
        }
        function fn() {
            console.log(this);
        }
        var fun = fn.bind(obj);
        fun();

        //1、不会调用原来的函数  可以改变原来函数this的指向
        //2、返回的是原函数改变this之后的新函数
        //3、什么时候用bind  想改变this指向 但是我不想立即执行原来的函数

        // var btn = document.querySelector("button");
        // btn.addEventListener("click", function () {
        //     this.disabled = true;//this指向btn
        //     var that = this;
        //     setTimeout(function () {
        //         that.disabled = false;//this指向window
        //     }, 3000)
        // })


        var btns = document.querySelectorAll("button");
        for (var i = 0; i < btns.length; i++) {
            btns[i].onclick = function () {
                this.disabled = true;
                setTimeout(function () {
                    this.disabled = false
                }.bind(this), 3000)
            }
        }

call apply bind 三种方法总结

相同点

可以改变函数内部的this指向

不同点

1、call和apply 会调用这个函数 并且改变this指向

2、call和apply的传递参数不一样 call传递参数 aru1,aru2, apply必须以 数组形式[aru1,aru2]

3、bind不会调用函数 可以改变this指向

主要应用

1、call经常做继承

2、apply 经常跟数组相关,借助一些Math对象的求最大值最小值方法等的

3、bind 需要变this 但是有不直接执行函数的 比如定时器内部的this指向

严格模式

JavaScript 除了提供正常模式外,还提供了严格模式(strict mode)。ES5 的严格模式是采用具有限制性 JavaScript 变体的一种方式,即在严格的条件下运行 JS 代码。

严格模式在 IE10 以上版本的浏览器中才会被支持,旧版本浏览器中会被忽略。

严格模式对正常的 JavaScript 语义做了一些更改:

1 消除了 Javascript 语法的一些不合理、不严谨之处,减少了一些怪异行为。

2 消除代码运行的一些不安全之处,保证代码运行的安全。

3 提高编译器效率,增加运行速度。

4 禁用了在 ECMAScript 的未来版本中可能会定义的一些语法,为未来新版本的 Javascript 做好铺垫。比如一些保留字如:class, enum, export, extends, import, super 不能做变量名

高阶函数

// 高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出

        //回调函数 就是高阶函数的一种
        function fn(a, b, callback) {
            console.log(a + b);
            callback && callback();
        }
        fn(1, 2, function () {
            alert("计算完毕")
        })


        // 函数作为返回值
        function fun() {
            return function () {
                console.log(111);
            }
        }
        var res = fun();
        console.log(res);

闭包

 // 变量根据作用域的不同分为两种:全局变量和局部变量。
        // 1. 函数内部可以使用全局变量。
        // 2. 函数外部不可以使用局部变量。
        // 3. 当函数执行完毕,本作用域内的局部变量会销毁。

        // 闭包  指一个函数 可以 访问另一个函数的局部变量 的 函数

        function fn() {
            var num = 10;
            function fun() {
                console.log(num);
            }
            fun();
        }
        fn();

闭包作用

// 我们fn 外面的作用域可以访问fn 内部的局部变量
        // 闭包的主要作用: 延伸了变量的作用范围
        function fn() {
            var num = 10;
            // function fun() {
            //     console.log(num);
            // }
            // fun();
            return function () {
                console.log(num);
            }
        }
        var f = fn();
        // f = function(){
        //     console.log(num);
        // }
        f();

闭包的应用

点击li获取索引号

// 传统方式获取索引号
        var lis = document.querySelectorAll("li");
        // for (var i = 0; i < lis.length; i++) {
        //     lis[i].setAttribute("index", i);
        //     lis[i].addEventListener("click", function () {
        //         console.log(this.getAttribute("index"));
        //     })
        // }

        //利用闭包获取索引号
        for (var i = 0; i < lis.length; i++) {
            // for 循环会产生4个立即执行函数
            (function (i) {
                lis[i].addEventListener("click", function () {
                    console.log(i);
                })
            })(i)
        }

定时器里的闭包

<ul>
        <li>星期一</li>
        <li>星期2</li>
        <li>星期3</li>
        <li>星期4</li>
</ul>
    <script>
        var lis = document.querySelectorAll("li");
        for (var i = 0; i < lis.length; i++) {
            (function (i) {
                setTimeout(function () {
                    console.log(lis[i].innerHTML);
                }, 3000)
            })(i)
        }
    </script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值