第四周汇总复习

112 阅读11分钟

Object:

继承:

父对象的属性和【方法】,子对象可以直接使用;
为什么要:代码重用,节约内存!提升网站的性能!
何时使用:只要多个子对象公用的属性和方法,都要集中在父对象。

如何找到父对象(原型对象):

保存一个类型的属性和方法有两种:
1.子对象.__proto__;前提是必须要有一个子对象。
2.构造函数名.prototype;构造函数名,几乎人人都有,除了undefined/null/Math

面试题:两链一包

闭包:保护一个可以反复使用的局部变量的词法结构。
作用域链:作用域变量的是使用规则,查找变量。
原型链:每个对象都有一个属性:__proto__,可以一层一层的找到每层的父级,形成的一条链式结构,就叫做原型链。
作用:可以找到父级所有的属性和【方法】
最顶层是Object,上面放着熟悉的toString,所以所有人都可以使用toString;
js中万物皆对象。

有了原型对象,设置共有属性和共有的方法;

1,原型对象.属性名=属性值;
2,原型对象.方法名=function(){}

笔试题:判断共有和自有:

1,判断自有:
    对象名.hasOwnProperty("属性名");
    结果为true,说明一定是自有,结果是false,可能是共有,也能是没有。
2,判断共有:
    对象名.hasOwnProperty("属性名")==false&&("属性名" in 对象名)?说明是共有:没有;
3,完整版判断共有和自有:
    if(对象名.hasOwnProperty("属性名")==true){
    自有
    }else {
    if("属性名" in 对象名){
    共有
    }else{
    没有
    }
}

笔试题:修改/删除自有和共有

自有:修改:对象名.属性名=新值;
      删除:delete 对象名.属性名;
共有:修改:对象名.__proto__.属性名=新值
      删除:delete 对象名.__proto__.属性名;
共有千万不要操作本地:
      修改:会在本地添加同名属性;
      删除:没有任何效果。

笔试题:为老IE添加indexOf方法:也可以是为一类人添加某个方法

原理:
    if(Arrar.prototype.indexOf===undefined){     ->判定为true时说明是老IE
        Arrar.prototype.indexOf=function(key,starti){
            starti==undefined&&starti=0;
                for(var i=0;i<this.length;i++){
            key==this[i]&&return i;
                }
        return -1;
        }
    }
		

笔试题:判断某个对象X是不是数组; 4种方法:

1,判断X是不是继承自Array.prototypeArray.prototype.isPrototypeOf(X);
2,判断X是不是由这个构造函数创建的:
    X instanceof Array3,只有数组可用:
    Array.isArray(X);
4,最麻烦:输出【对象的字符串】形式:
    在Object上保留着最原始的toString方法
    用原始的toString方法输出的结果:[object 构造函数名]
多态:子对象觉得父对象的成员不好用,就在本地定义了同名成员,覆盖了父对象的成员;   
    如果这里我们可以跳过数组的父对象,拿到数组的顶级对象上的toString也就能判断了
    固定公式:借用: Object.prototype.toString.apply(X);
    

ES5: 给我们带来了新的API

保护对象:保护对象的成员(属性和方法)

如何保护:
1.四大特性:
    Object.defineProperties(对象名,{
    "属性名":{
        value:实际保存的值,
        writable:true/false 开关 -> 控制着这个对象能否被修改
        enumerable:true/false 开关 -> 控制着这个对象能否被for in 遍历
        configurable:ture/false 开关 -> 控制着这个对象能否被删除      这一句是总开管,一旦设置为false,其他特性不可被修改,一旦设置为false不可逆。
            }
    }
    
2,三个级别
    1、防拓展:禁止给对象添加新属性;
        Object.preventExtensions(对象名);
    2,密封:禁止给对象添加和删除属性;
        Object.seal(对象名);
    3,冻结:禁止给对象添加,删除,修改属性;
        Object.freeze(对象名);

其实保护对象对我们没什么意义:

1,如果你是面向过程开发,对象都没有你保护个p
2,别人根本不可能知道我们的对象名是什么
3,前辈们的代码都没有保护,你保护个寂寞

数组的API: 3组 6个

1、判断:

判断的结果一定是一个boolea值;
语法:var bool=arr.every(function(val,i,arr){
    return 判断条件;
})
val:当前值		i:当前下标		arr:数组本身
every:每一个  -> 要求每一个元素都要满足,只要有一个满足着为false;都满足才为true。类似于我们之前的&&

语法:var bool=arr.some(function(val,i,arr){
return 判断条件;
})
some:有一些 -> 只要有一个元素满足,则结果为true;都不满足结果为false。类似我们之气的||

2、遍历:

将数组中的每一个元素拿出来执行相同 或者 相似的操作;

forEach:遍历数组,直接修改原数组。
语法:arr.forEach(function(val,i,arr){
    直接做操作
})

map:遍历数组,不会修改原数组,只会返回一个新数组。
语法:var newArr=arr.map(function(val,i,arr){
    return 操作的结果;
})

3、过滤和汇总:

过滤:筛选出自己想要的,但是不会修改原数组。
语法:var subArr=arr.filter(function(val,i,arr){
    return 判断条件;
})
		
汇总:把数组中的每一个元素汇总到一起;
语法:var sum=arr.reduce(function(prev,val,i,arr){
    return prev+val;
},基础值)
基础值会和最后的结果加在一起;

以上6个API的底层都是for循环,它们的目的也是为了简化for循环

Object.create(): 根据父对象创建子对象,继承已经设置好了

语法:var 子对象=Object.create(父对象,{
"自有属性名":{
        四大特性;
        ...
    }
});

面试题:严格模式

开启:在你的任何作用域之前加上一句:"use strict";
功能:1、禁止给为声明的变量赋值 - 解决全局污染;
      2、把静默失败升级为报错。

call/apply/bind:不是自己的方法也可以使用,笔试面试很容易遇到。

call/apply :暂时替换了函数中this的指向 - 借用

语法:函数名.call(借用对象,实参,...)        单独传入每一个实参;
      函数名.apply(借用对象,[实参,...])   只能传入一个数组参数,apply会悄悄地将数组打散。
强调:call/apply,相当于立即调用函数,立即执行;

bind:永久的替换了函数中this的指向 - 买

语法:var 新函数名=函数名.bind(指定对象,永久实参,...)	
注意:1、函数中this的指向会永久的指向【指定对象】,别人都借不走。
      2、相当于创建了一个和原函数一摸一样功能的新函数。
      3、可以将函数中的部分参数永久固定住。
      4、不是立即执行的,需要调用
强调:bind绑定的值不能别call/apply替换,借用。

个人更推荐call/apply,不会创建新的函数,可以节约内存。

固定套路:

Math.max/min.apply(Math.arr);
Object.prototype.toString.call/apply(arr);

类数组转换成普通数组:
类数组名称=Array.prototype.slice.cll/apply(类数组);

ES6:简化ECMAScript - 语法有较大的变化

1,模板字符串 - 可以在字符串中放入变量 - 不需要再拼接字符串,在字符串中实现了一个简单的js执行环境;

语法:\`我的名字叫${name}\`

2,块级作用域: 以后能用let就用let声明

语法:let 变量名=值;
作用:1、禁止声明提前;
      2、添加了块级作用域,一个{}就是一个块级作用域;
      3、记录着当前触发事件的元素的下标;

3,箭头函数:简化回调函数;

公式:去掉function,在(){}之间添加=> :()=>{},
    如果形参只有一个可以省略小括号(),
    如果操作只有一句话可以省略大括号{},
    如果操作只有一句话且这句话是return,那么return和大括号{}都省略。
特殊:千万不要将事件也转化成箭头函数(暂时),会有this指向问题。

4,for...of...循环 ---- 垃圾

forvar val of  数组名){
    val==当前值;
}	

为什么垃圾:有三个缺点;
    1、不能修改原数组,只会返回一个新数组。
    2、不能遍历hash数组,也就意味着不能遍历对象,只能遍历索引数组。
    3、不能获得当前下标。

DOM

什么是DOM:Document Object Model(文档对象模型) - 操作HTML文档

将每个元素/标签/文本/属性/注释都会看作是一个DOM节点/元素/对象

面试题:HTML/XHTML/DHTML/XML?

1HTML - 网页
2XHTML - 更严格的网页
3DHTML - Dynamic:动态的网页,其实并不是新技术,也不是新概念,而是现有技术的一个整合统称:让我们的网页再离线版也能具有动态效果
		DHTML:HTML+CSS+JS
4XML - 全部自定义,数据格式:淘汰了:JSON数据格式

DOM:原本是可以操作一切结构化文档的HTML和XML,后来为了方便各类开发者,就分为了三个部分;

1、核心DOM:【无敌】,即可操作HTML也可以操作XML
	缺点:API比较繁琐
2HTML:只能操作HTML,优点:API简单; 缺点:自定义的东西操作不了;

3、XML:只能操作XML,不会学习它。
	
开发建议:优先使用HTMLHTML实现不了的,再用核心DOM。

DOM树:树根:Document 不许要我们创建,一个页面只有一个Document,由JS解释器自行创建。

作用:通过树根,我们可以找到任何想要的DOM元素/节点/对象。

每个DOM都有三个特性:

1、elem.nodeType:描述节点的类型;
	document 		节点:9
	element	 	        节点:1
	attribute 		节点:2
	text 			节点:3
以前有用,可以判断某个XX是不是页面元素,现在又新的方法。	

2、elem.nodeValue:获取【属性节点】的值;

3、elem.nodeName:获取节点【名称/标签名】;
	!!!注意:返回的是一个全**大写**组成的标签名。

通过关系找元素; 前提是必须先找到一个元素

1、找到父元素:		元素名.parentNode;
2、找到所有子元素:	元素名.children;
3、找到第一个子元素:	元素名.firstElementchild;
4、找到最后一个子元素:	元素名.lastElementchild;
5、找到上一个同级元素:	元素名.previousElementSibling;
6、找到下一个同级元素:	元素名.nextElementSibling;

递归: 简单来说就是在函数中再次调用函数本身,满足条件后停止。

何时使用:遍历DOM树,专门用于【层级不明确】的树状结构;
如何使用:
	function 函数名(根元素){
		1、要做什么就直接做;
		2、判断它有没有下一级,如果有下一级,则再次调用此函数,并将此函数的参数设置为这个元素的下一级;
	}
	函数名(实际的根);

算法:深度优先,优先遍历当前节点的子节点,子节点遍历完再跳到i兄弟节点;
缺点:同时开启大量的函数调用,浪费内存;只有一个情况会使用到【层级不明确】
面试:递归和纯循环的区别
	递归:直观,易用 但是会 浪费内存,效率较低;
	循环:难用的一B,但是相对效率较高;

遍历层级不明确的API:TreeWalker -> 行走再DOM树上的人

缺点:只能遍历层级不明确的DOM树,不能遍历层级不明确的数据;
如何使用:2步;
	1、创建TW:
		var tw=document.creartTreeWalker(根元素,NodeFiltes.SHOW_ELEMENT)
	
	2、反复调用:
		while((node=tw.nextNode())!=null){
			node要干什么	
		}

直接找元素:

    1、通过HTML属性找元素:
	之前教过:class/id/标签名
	新的:通过name找元素:var 变量名=document.getElementsByName("Name值")

2、通过css选择器找元素:
	1var 变量名=document.querySelector("任意CSS选择器")
		只会找到一个元素,如果同时匹配到多个,也是会返回第一个;
		没有找到返回的是null2var 变量名=document.querySelectorAll("任意CSS选择器")
		找的所有匹配倒是元素,找到了是一个集合;
		没有找到返回的是一个空集合;

面试题:getXXX和quetyXXXX的区别?

返回的结果不一样;
    1、getXXXX:返回的是一个动态集合HTMLCollection
        特点:每一次DOM树修改后,js都会悄悄地再次查找元素,保证数据和页面相对应,效率相对较低;
    2、queryXXX:返回的是一个静态集合Nodelist
        特点:只管第一次查找出来的结果,后续DOM树的修改,我们的数据也不会跟着变化,效率相对较高;
        优点:1、查找简单
              2、还支持forEach
              

创建元素&渲染页面:

核心DOM_渲染页面

1、先创建空标签
	var elem=document.createElement("标签名");
	
2、为其添加必要属性和事件
	elem.属性名="属性值";
	elem.on事件名=function(){操作}

3、渲染DOM树/页面:3种
        1、父元素.appendChild(elem);              elem追加到父元素里面,当最后一个儿子
	2、父元素.insertBefore(elem,已有子元素);  elem追加到父元素里面,插入在已有子元素的前面 - 影响其他元素的下标,不推荐
	3、父元素.replaceChild(elem,已有子元素);  elem追加到父元素里面,新元素替换掉已有子元素 - 不推荐

删除元素:elem.remove();

核心DOM学习完毕,你已经无敌了:

总结一句话DOM可以干什么:

增删改查DOM元素(元素、文本、属性、样式)

HTML DOM:简化核心DOM开发,核心语法太繁琐,提供了一些常用的对象

1、image对象:垃圾,仅仅只是简化了创建部分
	创建:var img=new Image(); - 不是人人都可以简化为构造函数创建方式

2、form对象:垃圾,仅仅只是简化了查找部分
	查找form元素:var form=document.forms[i];
	以及找表单控件:var inp=form.elements[i];

3、*select对象:牛逼:提供了2个属性,2个方法,1个事件
	属性:
		1select.options === select.children; 获取select里面的所有的option
		2、*select.selectedIndex - 获取当前选中项的下标,一定是搭配联动一起使用

	方法:
		1、*sel.add(option); - 完全相当于appendChild
		2、elem.remove(i); - 当时当remove删除元素出现过后,他就当场淘汰了

	专属事件:onchange - 选中项发生了变化才会触发

4、*option对象:仅仅只是简化了创建部分
	创建:var opt=new Option("innerHTML","value")

	一句话完成4个操作:sel.add(new Option("榴莲","榴莲"));
		1、创建了空的option	
		2、为option设置了innerHTML
		3、为option设置了value
		4、上树
                    

用户确认框:var bool=confirm("提示文字");