第四周js 学习笔记

125 阅读9分钟

Object面向对象:

继承:

父对象的成员(属性和方法),子对象可以直接使用
为什么继承:代码重用!节约内存空间
何时继承:只要多个子对象公用的属性和【方法】,都要集中定义在父对象之中

JS的面向对象是基于原型(爸爸)的

什么是原型:保存一类子对象共有属性和共有【方法】的父对象(原型对象),每个对象天生就有一个原型

*获取原型对象:2种

  1. 对象名.__proto__; - 前提:必须先创建出一个对象,才可以使用此属性找到原型对象
  2. 构造函数名.prototype; - 构造函数名:Array、Function、Date、RegExp、h52204...
    - 哪怕没有创建过任何对象也能找到原型

* 两链一包:

作用域链

以函数EC的scope chain属性为起点,经过AO逐级引用,形成的一条链式结构,作用:查找变量的,带来了变量的使用规则:优先使用自己的,自己没有找全局,全局没有则报错

闭包

保护了一个可以反复使用局部变量的词法结构

原型链

每个对象都有一个.__proto__的属性,可以不断的连续.找到爸爸-爷爷-祖祖...形成的一条链式结构
经过尝试,发现最顶层:Object.prototype是对象的原型,所有也就有了一句话:万物皆对象
作用:查找属性和方法,自己没有的属性和方法,可以自动顺着原型链进行查找,所以我们知道为什么人人都可以使用toString,因为toString在最顶层的

获取到原型对象则可以设置共有属性和共有方法

		原型对象.属性名=属性值;//共有属性
		原型对象.方法名=function(){};//共有方法

自有和共有

自有:保存在对象本地的属性
共有:保存在父(原型)对象的属性,所有的子对象都可以使用

笔试题:如何判断自有和共有
			判断自有:obj.hasOwnProperty("属性名");
				返回一个布尔值:true说明是自有,false可能是共有也可能是没有
			判断共有:2个条件:
				1、不是自有:obj.hasOwnProperty("属性名")==false;
				2、自动在原型链检查:"属性名" in 对象名; 
				if(obj.hasOwnProperty("属性名")==false&&"属性名" in 对象名){
					//共有
				}

完整版:

                                    if(obj.hasOwnProperty("属性名")){
					console.log("自有");
				}else{
					if("属性名" in 对象名){
						console.log("共有")
					}else{
						console.log("没有")
					}
				}
笔试题:修改或删除属性
			1、修改和删除自有属性
				修改:obj.属性名=新值;
				删除:delete obj.属性名;

			1、修改和删除共有属性
				修改:原型对象.属性名=新值;
				删除:delete 原型对象.属性名;
笔试题:为老IE的数组添加indexOf方法
  • 这道题不是固定的:为某一类人设置一个方法

            if(Array.prototype.indexOf===undefined){//我不希望主流浏览器也执行到这些代码,我只希望老IE执行到
                      Array.prototype.indexOf=function(key,starti){//indexOf的执行原理
                      starti===undefined&&(starti=0);
                      //说明用户没有传入开始位置,我们就给用户设置为从下标0开始查找
                      for(var i=starti;i<this.length;i++){
                      //从开始位置处,循环数组后面的每一个文字和用户输入的关键字进行匹配
                          if(this[i]==key){
                              return i;//匹配到了返回对应的下标
                          }
                      }
                      //没匹配到,返回-1
                      return -1;
                      }
              }
    
笔试题:判断x是不是数组?

4个方法

  1. 判断x是不是继承自Array.prototype

                                     Array.prototype.isPrototypeOf(x);
                                     //如果返回true,说明是数组,否则不是数组
     		
    
  2. 判断x是否是由构造函数Array创建的

                             x instanceof Array
    
  3. ES5提供了一个API:Array.isArray(x);
    - 此方法不是人人都有,而且ES5以上的东西,老IE都不支持

  4. 输出对象的字符串形式(利用多态):
    Object的prototype原型上放着最原始的toString
    原始的toString,默认输出[object 构造函数名]

多态(override)/重写:

我希望借用到函数:跳过爸爸,直接去找爷爷拿toString(apply)

            Object.prototype.toString.apply(x)==="[object Array]";
笔试题:实现自定义继承
  1. 实现两个对象之间的继承

     			子对象.__proto__=父对象;
    
  2. 多个对象之间,直接匹配设置继承

     			构造函数名.prototype=父对象;
     			//时机:先设置好父对象,再创建子对象
     	
    

应用:面向对象开发

      //自定义构造函数
      function  自定义函数名(parent){
         this.元素(变量)=parent.get....("");
        }
       函数名.prototype.属性名=function(){
       //通常会构造一个init属性,由该子函数调用出其他属性函数
       this.属性名()
       var me=this;
       //在点击事件之前,需要提前将this赋值给一个变量,防止this指向触发事件的元素
       元素.onclick=function(){
            me.属性名()
            }
       }
       //使用用对象
       var 自定义对象名=new 自定义构造函数名();
       自定义对象名.init(parent)
       //parent作用是传入html中模板的最外层盒子,方便反复使用时作用到不同的模板

ES5&ES6:

就是在ES3的基础添加了一些新特性、新语法、新API - 简化ES3

ES5:提供了新特性、新API

保护对象:

        保护对象的属性和方法
	1、四大特性:每个属性都有四大特性
		{
				"value": 3500, //实际保存属性值的地方
				"writable": true,//开关:控制着是否可以被修改
				"enumerable": true,//开关:控制着是否可以被for in循环遍历到
				"configurable": true//开关:控制着是否可以被删除
		}
		修改四大特性:
			Object.defineProperties(obj,{
				"属性名":{四大特性}
			})

	2、三个级别:
		1、防扩展:禁止给对象添加任何新属性
			Object.preventExtensions(obj);

		2、密封:禁止给对象添加任何新属性,也不能删除属性
			Object.seal(obj);

		3、冻结:禁止给对象添加任何新属性,也不能删除属性,也不能修改属性
			Object.freeze(obj);

	不重要的原因:
		1、如果你不用面向对象,你保护个屁
		2、前辈们都没有保护,你保护个屁

*数组的新的API:3组6个:

判断every&some:

判断数组中的元素是否符合要求
every - 每一个:判断数组中的每个元素【】要符合要求最后结果才为true,类似于&&,只要有一个不满足,结果则为false

                    var bool=arr.every(function(val,i,arr){
			console.log(val);//当前元素
			console.log(i);//当前元素的下标
			console.log(arr);//数组本身
			return 判断条件;
		           })

some - 有一些:判断数组中的是否【包含】符合要求的元素,只要有一个最后结果则为true,类似||,只要有一个满足,则为true,只有全都不满足,结果才为false

                    var bool=arr.some(function(val,i,arr){
                            console.log(val);//当前元素
			console.log(i);//当前元素的下标
			console.log(arr);//数组本身
			return 判断条件;
		           })

*遍历forEach:

对每个元素执行相同 或 相似的操作

forEach:直接修改原数组

                    arr.forEach(function(val,i,arr){
			操作;
		           })

map:不修改原数组,返回新数组

                    var newArr=arr.map(function(val,i,arr){
			return 操作;
		           })

过滤和汇总filter&reduce:

过滤 filter:筛选出原数组之中符合条件的元素组成一个新数组!原数组不变!

                    var newArr=arr.filter(function(val,i,arr){
			return 判断条件;
		           })

汇总 reduce:将数组中每一个元素,取出来整合为一个最终结果

                    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、将静默失败升级为了错误

以后如果三阶段学了gulp和webpack,可能打包时就会自动给你生成一个"use strict",需要自己去把他手动删掉

call、apply、bind:调用其他对象或构造函数的方法

call、*apply:【临时替换函数中的this】

暂时借用其他函数的方法

	差别: 
                  .call,要求传入函数的实参必须单独参入
                  .aplly,要求传入函数的实参必须是一个数组
	语法:
                    被借用的函数.call(需要借用的对象,实参1,...);
                    被借用的函数.apply(需要借用的对象,arr);
                    // apply除了有借用的功能,还会悄悄的打散我们的数组
                    //Math.max.apply(null, [1,2,3]); 

bind:【永久替换函数中的this】,

    var 新函数=老函数.bind(指定的对象)
  1. 创建了一个和原函数功能完全一样的新函数
  2. 将新函数中的this永久绑定为你指定的对象
  3. 将新函数中的部分参数永久固定

强调:bind绑定在新函数中的this,无法被call、apply再次替换借走

总结:如果临时调用一个函数,立刻执行时 -- call/apply
如果创建一个函数提前绑定this,不一定希望立刻执行 - bind
个人更推荐:借用,白嫖

使用场景

  1. 出数组中的最大值和最小值:Math.max/min.apply(Math,arr)
  2. bject最原始的toString:Object.prototype.toString.call/apply(arr);
  3. 数组对象转为普通数组:var 新数组=Array.prototype.slice.call/apply(类数组对象)

其实ES5还提供了一个数组API,可以直接将类数组对象转为普通数组:var 新数组=Array.from(类数组对象)


ES6:新语法:

常量也是ES6提供的

Math.PI...

*模板字符串:简化字符串拼接,支持在模板字符串之中书写变量

            `我的名字叫${name}`

在字符串中实现了一个简单的js环境

*let关键字:创建变量以后优先使用let,再考虑var

	let 变量名=值;

优点:

  1. 解决了声明提前
  2. 添加了块级作用域,一个{}就是一个块
  3. 如果绑定事件时,用到了let来遍历,那么let会记录住你当前元素的下标 - 你以后再也不需要自定义下标了

*箭头函数:简化一切的回调函数

            ()=>{}
	去掉function,()和{}之间添加=>,
        形参只有一个可以省略()
	函数体只有一句话,省略{}
	函数体只有一句话,并且是return,省略{}和return

for...of:垃圾

	for(var v of arr){
		v -   直接拿到值
	}
  1. 不能修改原数组 1.不能遍历hash数组和对象

其他

*解构赋值
Set和Map类型
*模块化开发
*Promise
*Class
二阶段可用可不用,但是三阶段必然会用上