当前位置 博文首页 > 小丞同学:JS学习笔记

    小丞同学:JS学习笔记

    作者:[db:作者] 时间:2021-07-20 18:41

    预编译

    1. 创建AO对象
    2. 找函数形参和变量声明,值给undefined
    3. 实参形参统一
    4. 在函数体里面找函数声明,值赋予函数体
    function fn(a){
       console.log(a); //在AO里找值--->输出 function a() {}
       var a = 123; //预编译将 var a,提升上去了,执行 a = 123;修改AO中a的值
       console.log(a); //输出 123
       function a() {} //预编译读过,不再读
       console.log(a); //输出 123
       var b = function() {} //函数表达式,将AO中b的值改为function () {}
       console.log(b); //输出funtion () {}
       function d() {}
    }
    fn(1);
    
    第一步:AO{ }
    第二步:
    AO{
    a : undefined,
    b : undefined
    }
    第三步:
    AO{
    a : 1,
    b : undefined
    }
    第四步:
    AO{
    a : function a() {},
    b : undefined,
    d : function d() {}
    }
    

    立即执行函数

    此类函数没有声明,在一次执行过后即释放,可以用来做初始化

    var mrDeng = (function(){
        var Deng = {
            name : "MrDeng",
            age : 40,
            sex : "male",
            health : 100,
            smoke : function () {
                console.log('I am smoking! cool!!!');
                this.health --;
            },
            drink : function () {
                console.log('I am drink');
                this.health ++;
            }
        }
        return Deng;
    }())
    

    这样可以实现初始化的效果


    闭包

    内部函数被返回到外部,函数本身保留了父函数的AO,即使父元素执行完了,取消对AO的引用,但依旧被子函数保留下来了,就形成了闭包。

    闭包会导致原有作用域链不释放,造成内存泄漏。

    作用

    1. 实现公有变量(累加器)

    因为子函数保留有父函数的AO,并在此基础上搭建自己的AO,所以父函数的AO会被作为一个公有变量被使用,即使函数执行完毕,也只会销毁自己创建的AO对象。

    1. 实现封装,属性私有化

    简单理解就是函数结束会销毁父函数的执行上下文,但是应用闭包可以使父函数的执行上下文被保留下来,给父函数下的其他函数使用,这样就实现了属性的私有化

    1. 模块化开发

    2. 防止污染全局变量

    var name = 'abc';//全局变量
    var init = (function() {
        var name = 'ljc';
        function callName() {
            console.log(name);
        }
        return function () {
            callName();
        }//返回一个函数形成闭包,留有父函数的AO{name: 'ljc'}
    }())
    init();//ljc
    
    1. 缓存(存储结构)

    防范

    闭包会导致多个执行函数共用一个公有变量,应当尽量避免

    利用闭包解决for循环绑定事件的问题

    function test(){
       var liCollection = document.getElementByTagName('li');
       for(var i = 0; i < liCollection.length; i++){
          (function (j){
             liCollection[j].onclick = function(){ //把函数绑定到了每个li元素(外部)
                console.log(i);
             }
          }(i))
       }
    }
    test();
    

    包装类

    原始值没有属性和方法,强行添加属性或者访问属性的话,系统就会新建一个包装类,然后在包装类上进行操作,操作完成后再销毁。

    var num = 4;//这里的num是原始值没有属性和方法
    
    num.len = 3;//强行添加属性
    //new Number(4).len = 3;执行完立刻销毁 delete
    //再次调用的时候再次生成Number()
    //new Number(4).len
    consloe.log(num.len);
    

    数组在改小length的时候会被截短


    原型

    原型是function对象下的属性,它定义了构造函数的共同祖先,也就是一个父子级的关系,子对象会继承父对象的方法和属性

    1. prototype是函数下的属性,对象想要查看原型使用隐式属性__Proto__
    2. constructor指向构造函数
    3. 自己身上有属性,原型上也有属性,取近的,用自己的

    通过给原型添加属性,可以让所有的实例化对象共享属性和方法

    Car.prototype = {
    	height : 1400,
    	lang : 4900,
    	carName : 'BMW'
    }
    function Car() {
    }
    var car = new Car();
    

    原型链

    每个实例对象下都有__proto__属性,通过属性__proto__指向构造函数的原型对象,当到达末端时,返回null,这样一层一层向顶端查找,就形成了原型链

    prototype是函数特有的,__proto__是对象有的,js中万物皆对象

    prototype和——proto——区别与作用

    prototype把共有属性预先定义好,给之后对象使用

    prototype的存在实现了继承,节省内存空间

    __proto__是对象的,prototype是函数的,因为函数也是对象,所以函数也有__proto__

    __proto__的作用是就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会沿着它的**__proto__**属性所指向的那个对象(父对象)里找,也就是原型链

    prototype的作用是就是让该函数所实例化的对象们都可以找到公用的属性和方法

    __proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype

    constructor构造函数

    constructor属性存在于__proto__prototype,它指向构造函数本身

    一般情况下,对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法,我们可以给原型对象采取对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了。此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。

    问题 修改了函数的原型对象,constructor的指向是谁

     function Star(uname, age) {
         this.uname = uname;
         this.age = age;
     }
     // 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
     Star.prototype = {
     // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
       constructor: Star, // 手动设置指回原来的构造函数
       sing: function() {
         console.log('我会唱歌');
       },
       movie: function() {
         console.log('我会演电影');
       }
    }
    var zxy = new Star('张学友', 19);
    console.log(zxy)
    

    在修改函数原型时,因为Star.prototype就是一个对象,所以constructor指向构造这个对象的原型,也就是object

    call/apply

    通过call``apply可以改变this的指向,借用别人的函数完成自己的功能

    区别:call传多个参数 apply传一个参数数组

    function Person(name,age,sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    function Student(name,age,sex,tel,grade) {
        //var this = {name: "lin", age: "19", sex: "male", tel: 123, grade: 78}
        Person.call(this,name,age,sex);//通过call改变this的指向这个函数
        //Person.apply(this,[name,age,sex])
        this.tel = tel;
        this.grade = grade;
    }
    var student = new Student('lin','19','male',123,78);
    

    new()

    1. 创建一个空对象
    2. 构造函数的this,继承函数原型
    3. 让this指向构造函数的对象实例,执行构造函数内容为新对象添加属性和方法
    4. 返回this
    var obj = {}//创建空对象
    obj.__proto__ = Person.prototype;//继承作用域
    Person.call(obj,)//改变this指向
    //这三步是隐式的
    var person = new Person();//new操作
    

    继承

    原型链方法

    继承了过多没用的属性

    通过使用new关键字来实现继承父元素属性和方法,再通过prototype属性来改变函数原型,从而实现一条完整的原型链,从而实现子函数可以继承父函数的属性和方法

    function Father() {
        this.name = 'hhh';
    }
    var father = new Father();
    Son.prototype = father;
    function Son() {
    }
    var son = new Son();//son下继承了father的name
    

    借用构造函数

    不能继承构造函数的原型

     // 1. 父构造函数
     function Father(uname, age) {
       // this 指向父构造函数的对象实例
       this.uname = uname;
       this.age = age;
     }
      // 2 .子构造函数 
    function Son(uname, age, score) {
      // this 指向子构造函数的对象实例
     // 3.使用call方式实现子继承父的属性
      Father.call(this, uname, age);
      this.score = score;
    }
    var son = new Son('lin', 19, 100);
    console.log(son);
    

    共享原型

    Son.prototype = Father.prototype,不能改动自己的原型

    Father.prototype.lastName = 'lin';
    function Father() {
        this.name = 'hhh';
    }
    function Son() {
    }
    Son.prototype = Father.prototype;//son和father共用原型
    var father = new Father();
    var
    
    下一篇:没有了