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 类名,类中的方法也不需要使用逗号分隔!!
关于类的继承:这里有详解