二阶段 day13

84 阅读2分钟

面向对象:

1、*****继承具有很多的面试笔试题:

1、判断是自有还是共有:

1)、判断自有:obj.hasOwnProperty("属性名");

如果结果为true,说明是自有属性,如果结果为false,有两种可能,说明可能是共
    有,也可能是没有

2)、判断共有:

	if(obj.hasOwnProperty("属性名")==false&&"属性名" in obj){
            //in关键字,会自动查找整条原型链上的属性,找到了结果为true,
            找不到结果为false
			共有				
		}else{
			没有
		}

		**完整公式:**
			if(obj.hasOwnProperty("属性名")){
				自有
			}else{
				if("属性名" in obj){
					共有
				}else{
					没有
				}
			}

2、修改和删除:自有和共有

	自有:
		修改:obj.属性名=新属性值;
		删除:delete obj.属性名;
	共有:
		修改:原型对象.属性名=新属性值;//千万不要觉得,自己能拿
                    到,就能直接修改,这样很危险,并没有修改原型的东西,而是
                    在本地添加了一个同名属性
		删除:delete 原型对象.属性名;//如果你对着本地直接删除,
                    那么此操作直接无效

3、*如何为老IE的数组添加indexOf方法:- 这道题不是固定的:可能问如何为一类人创建某个方法

		if(Array.prototype.indexOf===undefined){//老IE
			Array.prototype.indexOf=function(key,starti){
				starti===undefined&&(starti=0);
				for(var i=starti;i<this.length;i++){
					if(this[i]===key){
						return i;
					}
				}
				return -1;
			}
		}
		var arr1=[1,2,3,4,5];
		var arr2=[2,4,6,8,10];

4、*如何判断x是不是一个数组:4种方法:千万别用typeof(),只能检查原始类型,不能检查引用类型,如果检查引用类型得到的结果都是一个object。

1)、判断x是否继承自Array.prototype:

		Array.prototype.isPrototypeOf(x);
		结果为true,说明是数组,结果为false,说明不是数组
	

2)、判断x是不是由Array这个构造函数创建的

		x instanceof Array;
		结果为true,说明是数组,结果为false,说明不是数组

3)、Array.isArray(x); - ES5新增的方法,只有数组可以这么使用

		结果为true,说明是数组,结果为false,说明不是数组

4)、*输出【对象的字符串】形式

Object的原型上保存着最原始的toString方法
     原始的toString输出形式:[object 构造函数名]
      ***多态:子对象觉得父对象的成员不好用,就在本地定义了同名函数,覆盖了父
      对象的成员,不严格定义:同一个方法,不同的人使用,效果不同,有多种形态
 固定套路:
        Object.prototype.toString.call(x)==="[object Array]"

5)、实现自定义继承:

	1、两个对象之间设置继承
		子对象.__proto__=父对象

	2、多个对象之间设置继承
		构造函数名.prototype=父对象;
		时机:应该在开始创建对象之前就设置好继承关系

2、class关键字:简化面向对象(封装、继承、多态)

class 类名 extends 老类{
constructor(name,age,hobby,...){//放在constructor里面的都是自有属性
		super(name,age);
		this.hobby=hobby;
	}//放在constructor外面的都是共有方法
	//还会继承到老类所有的API,也可以添加新的
}

3、*****Function:闭包

作用域:2种
	1、全局:随处可用,可以反复使用,缺点:容易被污染

	2、函数:只能在函数调用时内部可用,不会被污染,缺点:一次性的,是会自动释放的

***函数的执行原理:

1、程序加载时
		创建执行环境栈(ECS):保存函数调用顺序的数组
		首先压入全局执行环境(全局EC)
		全局EC引用着全局对象window
		window中保存着我们全局变量

2、定义函数时
创建函数对象:封装代码段
在函数对象之中有一个scope(作用域)属性:记录着函数来自己的作用域是哪里
全局函数的scope都是window

3、调用前
	在执行环境栈(ECS)压入新的EC(函数的EC)
	创建出活动对象(AO):保存着本次函数调用时用到的局部变量
	在函数的EC中有一个scope chain(作用域链)属性引用着AO
	AO有一个parent属性是函数的scope引用着的对象

4、调用时:
        正是因为有前面三步,才来带变量的使用规则:优先使用自己的,自己没有找全
        局,全局没有就报错

5、调用完:
	函数的EC会出栈,没人引用AO,AO自动释放,局部变量也就释放了
            

*****闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊

	何时使用:希望保护一个可以【反复使用的局部变量】的时候
	如何使用:
		1、两个函数进行嵌套
		2、外层函数创建出受保护的变量
		3、外层函数return出内层函数
		4、内层函数再操作受保护的变量

强调:

1、判断是不是闭包:有没有两个函数嵌套,返回了内层函数,内层函数再操作受保护的变量
2、外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本
3、同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量

缺点:受保护的变量,永远都不会被释放,使用过多,会导致内存泄漏 - 不可多用
问题:应该在哪里去使用呢?
		1、三个事件需要防抖节流 - 共同点:触发的速度飞快
			1、elem.onmousemove - 鼠标移动事件
			2input.oninput - 每次输入/改变都会触发
			3、onresize - 每次窗口改变大小都会触发

防抖节流的公式:

		function fdjl(){
			var timer=null;
			return function(){
				if(timer!==null){clearTimeout(timer);timer=null;}
				timer=setTimeout(()=>{
					操作
				},500)
			}
		}
		
		var inner=fdjl();

		elem.on事件名=function(){
			inner();
		}
总结:
两链一包:
1、作用域链:以函数的EC的scope chain属性为起点,经过AO,逐级引用,形成的
    一条链式结构,我们就称之为叫做作用域链
作用:查找变量,带来了变量的使用规则:优先使用自己的,自己没有找全局,全局
    没有就报错
2、原型链:每个对象都有一个属性叫做.__proto__,可以一层一层的找到每个对象
    的原型对象,最顶层的就是Object的原型,形成的一条链式结构,我们就称之为叫做
    原型链
作用:查找属性和方法,哪怕自己没有也会顺着原型链向上找,怪不得人人都能用
    toString(),因为他在最顶层
3、闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一
    个函数,只是写法比较特殊
作用:专门用于防抖节流