深刻理解JavaScript闭包、原型、this指向

1、this指向问题

a、普通函数,谁调用就指向谁。注意,严格模式下全局作用域的this是undefined。

  function fn() {
        console.log('普通函数的this'+this);
    }
    fn(); //实际是window.fn() 所以这里指向window

b、对象的方法

 var o ={
        sayHi:function () {
            console.log('对象方法的this:'+this);
        }
    };
    o.sayHi();  //this指向的是对象o,因为o对象调用此方法

c、构造函数,this指向实例对象(严格模式下,如果构造函数不加new调用,this指向的是undefined)

   //构造函数 this指向cc实例对象
    function star() {
    }
    //原型对象里面的this指向的也是cc实例对象
    star.prototype.sing=function () {
    };
    var cc=new star();

d、绑定事件函数,this指向函数的调用者

 //绑定事件函数 this指向的是函数的调用者,btn这个按钮对象
    var btn=document.querySelector('button');
    btn.onclick=function () {
        console.log('绑定事件函数的this:'+this);
    };

e、定时器函数,this指向的也是window

//定时器函数   this指向的也是window
    setInterval(function () {
        console.log('定时器的this'+this);
    },1000);

f、立即执行函数,this指向也是window

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

2、改变this指向的三种方法

a、call()方法,既可以调用函数,也可以改变this指向。
b、apply方法,也可调用函数,但是参数必须是数组。
c、bind方法,不会调用函数,但是能改变内部this指向。

3、ES6新特性及其特点

a、let和const:let声明变量,作用域为局部。const用于声明一个常量,设定后值不会再改变。
b、箭头函数:操作符左边为参数,右边为具体操作和返回值。注意,箭头函数的this指向定义时所在的对象。
c、解构赋值:可以从数组和对象中提取值,对变量进行赋值。

4、执行上下文

全局执行上下文:预处理,收集全局数据,执行全局代码。
函数执行上下文:调用函数的时候产生,收集函数内部的局部变量。

5、变量提升和函数提升

变量提升:在var a=1之前打印a,会输出undefined。
函数提升:在函数定义之前执行函数,能正常运行输出,函数提升优先级比变量提升高,即后执行函数提升。

6、浅拷贝和深拷贝

a、浅拷贝,拷贝地址,一旦改变拷贝后的数据,原数据也会改变。

 var obj={
        id:1,
        name:'cc',
        msg:{
            age:21
        },
        color:['gray','red']
    };
    var o={};

    //将obj拷贝给o(浅拷贝)
    for(var i in obj){
        o[i]=obj[i];
    }
    console.log(o);
    //这里是将地址拷贝,一旦改变数值改变,原来对象的数值也会改变
    o.msg.age=20;
    console.log(obj);

ES6新写法:

 Object.assign(o,obj);

b、深拷贝,改变拷贝的数据,不会影响被拷贝的数据。

  //深拷贝
    function deepCopy(newobj,oldobj) {
        for(var k in oldobj){
          //判断属性值属于哪种数据类型
            //获取属性值 oldobj[k]
            var item=oldobj[k];

            if (item instanceof Array){
                //判断这个值是否是数组
                newobj[k]=[];
                deepCopy(newobj[k],item);
            }else if(item instanceof Object){
                //判断这个值是否是对象
                newobj[k]={};
                deepCopy(newobj[k],item)
            }else{
                //是否是简单数据类型
                newobj[k]=item;
            }
        }
    }
    deepCopy(o,obj);
    console.log(o);
    o.msg.age=18;
    //深拷贝不会影响被拷贝的数据·
    console.log(obj);

7、闭包

a、闭包生命周期:闭包在嵌套内部函数定义执行完成时就产生了,在嵌套的内部函数成为垃圾对象时死亡。
b、闭包产生条件:函数嵌套,并且内部函数引用外部函数的变量。
c、闭包作用:使用函数内部的变量在函数执行完后,仍然存活在内存中,延长了局部变量的生命周期;让函数外部可以直接操作函数内部的数据。

8、函数的prototype属性

a、每个函数都有一个prototype属性,默认指向一个Object空对象(原型对象)。每个实例对象都有一个属性__proto__,指向构造函数的prototype原型对象。__proto__对象原型和原型对象prototype是等价的。
b、原型对象中有一个属性constructor,它指向函数对象。

9、内存溢出和内存泄漏

内存溢出:是一种程序运行出现的错误,当程序运行所需内存超过剩余内存时,就会抛出内存溢出的错误。
内存泄漏:是占用的内存没有及时释放,如有意外的全局变量、没有及时清理的计时器和回调函数、还有闭包,都可能内存泄漏。内存泄漏积累多了就容易导致内存溢出。

10、ES6的class概念

在ES5中,生成实例对象的方法是通过构造函数,如下代码所示:

function Fn(x,y){
	this.x = x
	this.y = y
}
Fn.prototype.toString = function(){
	 return '(' + this.x + ', ' + this.y + ')';
}
let one = new Fn(1,2)


ES6中引入class的概念,让类的编写更加清晰,如下代码所示:

class Fn{
	constructor(x,y){
		this.x = x
		this.y = y
	}
	toString(){
		return '(' + this.x + ', ' + this.y + ')';
	}
}

如上代码用ES6语法定义了一个类,constructor相当于构造方法,this则代表实例对象,除了构造方法外,还定义了一个方法toString。注意:定义类的时候不需要加function关键字,直接使用class 类名,类中的方法也不需要使用逗号分隔!!

关于类的继承:这里有详解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值