JavaScript重要知识点复习

本文深入探讨JavaScript中的面向对象编程概念,包括类与对象、继承、多态性等核心特性,并介绍了深拷贝与浅拷贝的区别及实现方法。此外,还详细解析了闭包的概念、应用场景以及闭包面试题的解答。

1、js

面向对象、面向过程。

面向对象:

面向对象是一种程序开发的方法,它将对象作为程
序的基本单元,将程序和数据封装其中,以提高软
件的灵活性、重用性和扩展性。对象是把数据及对
数据的操作方法放在一起,作为一个相互依存的整
体。再说一下类与对象,类描述了一组有相同特性
和相同行为的对象,具有相同属性和相同方法的对象的抽象就是类。即,对象的抽象是类,类的实例是对象。在面向对象的编程中,把用类创建对象的过程称为实例化。

面向过程与面向对象的区别

面向过程是一种直接的编程方法,它是按照编程语言的思路考虑问题。通过顺序执行一组语句来实现一个功能,这些语句的执行过程就是整个程序。
面向对象是一种抽象度更高的编程方法。它的目标是使模块的抽象度更高,目的是可复用。

面向对象三大特性:封装,继承,多态。

面向过程可以说是从细节方面思考问题

面向对象可以说是从宏观方面思考问题

对象的创建方式有对象字面量,工厂方式,原型方式,构造函数,混合模式。==

对象的创建-字面量,原型,构造函数等各自特点
(你开发过什么什么插件)

1.字面量

<script>
			var obj={
				name:"Join",
				sayHello:function(){
					console.log(this.name)
				}
			}
			
			var obj1=new Object()
			obj1.name="Mary"
			console.log(obj,obj1)
		</script>

2.工厂模式

<script>
			function creatObject(name){
				var obj=new Object();
				obj.name=name;
				obj.sayHello=function(){
					console.log(this.name)
				}
				return obj;
				
			}
			var obj1=creatObject("John")
			var obj2=creatObject("Mary")
			obj1.sayHello()
			obj2.sayHello()

		</script>

3.构造函数

<script>
			//可以把构造函数看成是某个类型
			//一个构造函数加new运算符之后 会进行一下4步操作
			/*
			* 1.创建一个新对象
			* 2.改变构造函数里的this指向,指向这个新创建的对象
			* 3.执行构造函数里的代码
			* 返回这个新对象
			*/
			
			function Person(name){
				this.name=name;//
				this.sayHello=function(){
					console.log(this.name)//Apple
				}
			}
			var person= new Person("Apple")
			var person1=new Person("Apple1")
			person.sayHello()
			console.log(person instanceof Person)//true
			console.log(person instanceof Object)//true
			//每创建一个实例,就会开辟一块内存空间,保存实例方法
			console.log(person.sayHello==person1.sayHello)//false
		</script>

4.借助原型对象

<script>
			//原型对象上的属性和方法能被实例所访问
			function Person(){
				
			}
			Person.prototype.name="John"
			Person.prototype.sayHello=function(){
				console.log(this.name)
			}
			
			var person=new Person()
			person.sayHello()
			var person1=new Person()
			console.log(person.sayHello==person1.sayHello)//true
			
		</script>

5.组合方式

<script>
			//属性放到构造函数里,方法放到原型对象上
			function Person(name,age){
				this.name=name;
				this.age=age;
			}
			Person.prototype.sayHello=function(){
				console.log(this.name)
			}
			var person=new Person("Mary")
			person.sayHello()
			var person1=new Person("Mary1")
			console.log(person.sayHello==person1.sayHello)//true
		</script>
继承 - 原型,原型连,es6继承 ,call,apply

原型继承

每一个构造函数都有一个原型对象,每一个原型对象都有一个指针constructor指向构造函数

每一个实例都有一个内部指针(proto),指向原型对象,原型对象上的属性和方法能够被实例访问

函数都有prototype,每一个实例对象都有__proto__

混合继承

使用原型链与构造函数继承

构造函数继承 只能继承 实例属性

原型链继承 只能继承方法

ES6中的继承

ES6 要求,子类的构造函数必须执行一次super函数

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。

<script>
			class Person{
				constructor(name,age) {
				    this.name=name;
					this.age=age;
				}
				
				Hello(){
					console.log(this.name)
				}
			}
			class Male extends Person{
				constructor(name,age){
					super(name,age)
				}
				
			}
			var male=new Male('Join',20)
			male.Hello()
		</script>
call和apply

call方法的第一个参数的值赋值给类(即方法)中出现的this

//call方法的第二个参数开始依次赋值给类(即方法)所接受的参数

//以列表形式传参

apply方法接受2个参数,

// A、第一个参数与call方法的第一个参数一样,即赋值给类(即方法)中出现的this

// B、第二个参数为数组类型,这个数组中的每个元素依次赋值给类(即方法)所接受的参数

// 以数组形式传参

<script>
			function Person(name,age){
				this.name=name;
				this.age=age;
				this.hello=function(){
					console.log(this.name+this.age)
				}
			}
			
			function Male(name,age){
				//继承父类Person  call方法继承
				//call方法的第一个参数的值赋值给类(即方法)中出现的this
				//call方法的第二个参数开始依次赋值给类(即方法)所接受的参数
				//以列表形式传参
				Person.call(this,name,age)
			}
			function Female(name,age){
// 				apply方法接受2个参数,
//     			A、第一个参数与call方法的第一个参数一样,即赋值给类(即方法)中出现的this
//     			B、第二个参数为数组类型,这个数组中的每个元素依次赋值给类(即方法)所接受的参数
//				以数组形式传参
				Person.apply(this,[name,age])
			}		
			var yyz=new Male('yyz',20)
			yyz.hello()
			var ywy=new Female('aaa',18)
			ywy.hello()
		</script>

利用apply使用math的min和max 方法

 var arr1 = [1,2,3,4,5,6,6,45,45];
              console.log(Math.min.apply(null,arr1));
              console.log(Math.max.apply(null,arr1));
闭包-是什么,什么情况会出现,项目中用它处理什么

在一个函数外部,可以访问改函数内部局部变量的函数

            function foo(){
				 var a=1  //在函数内部定义的a是局部变量
				 return function(){
					 console.log(a++)
				 }
			}
			var bar=foo();
			console.log(bar)//ƒ (){console.log(a++) }
			bar() //1
			bar()//2
			bar()//3
			foo()()//1
			foo()()//1
			foo()()//1

闭包的应用:

<body>
		<ul>
			<li>1</li>
			<li>2</li>
			<li>3</li>
			<li>4</li>
			<li>5</li>

		</ul>
		<script>
			let aLis = document.querySelectorAll('li')
			var obj=(function(){
				var a=10;
				var b=20;
				function foo(){
					console.log(a)
				}
				function bar(){
					console.log(b)
				}
				return {
					foo:foo,
					bar:bar
				}
			})()
			obj.foo()
			console.log(obj.b)//undefined
		</script>
	</body>

闭包的特点

1:可以读取函数内部的变量。
变量的作用域无非就是两种:全局变量和局部变量。

JS语言的特殊之处,就在于函数内部可以直接读取全局变量。另一方面,函数外部自然无法读取函数内的局部变量

2:让这些变量的值始终保存在内存中。

闭包的好处:

减少全局变量和全局函数的定义,减少内存的占用

闭包的应用场景

1:函数作为返回值。

2:函数作为参数被传递
回调函数

<body>
		<script>
			//减少全局函数或全局变量的定义,减少内存占用
			var obj=(function(){
				var a=10;
				var b=20;
				function foo(){
					console.log(a)
				}
				function bar(){
					console.log(b)
				}
				return {
					foo:foo,
					bar:bar
				}
			})()
			obj.foo()
		</script>
	</body>

闭包面试题:

<body>
		<script>
			function fun(n,o){
				console.log(o)
				return {
					fun:function(m){
						return fun(m,n)
					}
				}
			}
			
			var a=fun(0)//undefined n:0
			a.fun(1)//fun(1,0)  0
			a.fun(2)//fun(2,0)  0
			a.fun(3)//fun(3,0)  0
			
			var b=fun(0).fun(1).fun(2).fun(3)  //undefined 0 1 2
			
			
			var c=fun(0).fun(1)//0
			c.fun(2)//1
			c.fun(3)//1
		</script>
	</body>
es6相对于es5新增技术,你常用哪些?

es5:

1.strict模式

严格模式,限制一些用法,‘use strict’;

  1. Array增加方法

增加了every、some 、forEach、filter 、indexOf、lastIndexOf、isArray、map、reduce、reduceRight方法

PS: 还有其他方法 Function.prototype.bind、String.prototype.trim、Date.now

  1. Object方法

Object.getPrototypeOf

Object.create

Object.getOwnPropertyNames

Object.defineProperty

Object.getOwnPropertyDescriptor

Object.defineProperties

Object.keys

Object.preventExtensions /

Object.isExtensible

Object.seal / Object.isSealed

Object.freeze / Object.isFrozen

Es6

ECMAScript6在保证向下兼容的前提下,提供大量新特性

1.块级作用域 关键字let, 常量const

2.对象字面量的属性赋值简写(property value shorthand)

3.赋值解构

4.函数参数 - 默认值、参数打包、 数组展开(Default 、Rest 、Spread)

5.箭头函数 Arrow functions

6.字符串模板 Template strings

  1. Iterators(迭代器)+ for…of

8.生成器 (Generators)

9.Class

Class,有constructor、extends、super,但本质上是语法糖(对语言的功能并没有影响,但是更方便程序员使用)。

10.Modules

ES6的内置模块功能借鉴了CommonJS和AMD各自的优点:

(1).具有CommonJS的精简语法、唯一导出出口(single exports)和循环依赖(cyclic dependencies)的特点。

(2).类似AMD,支持异步加载和可配置的模块加载。

11.Map + Set + WeakMap + WeakSet

四种集合类型,WeakMap、WeakSet作为属性键的对象如果没有别的变量在引用它们,则会被回收释放掉。

12.Math + Number + String + Array + Object APIs

  1. Proxies

使用代理(Proxy)监听对象的操作,然后可以做一些相应事情。

14.Symbols

Symbol是一种基本类型。Symbol
通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。

15.Promises

Promises是处理异步操作的对象,使用了 Promise 对象之后可以用一种链式调用的方式来组织代码,让代码更加直观(类似jQuery的deferred 对象)。

promise怎么用的?用它做过什么功能?

异步编程的解决方案,解决回调函数的嵌套问题

登录的时候,有些内容需要用户登录后才进行显示

resolve函数的作用是 在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject函数的作用是 在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

<script>
        let p = new Promise(function(resolve,reject){
            let url = 'http://jx.xuzhixiang.top/ap/api/allproductlist.php?pagesize=20&pagenum=4'
            ajax(url,function(res){
                 console.log(res)
                resolve(res)
            },function(erorr){
                reject(error)
            })

        })
        p.then(function(r){
            console.log(r)

            return new Promise(function(resolve,reject){
                let url = 'http://jx.xuzhixiang.top/ap/api/allproductlist.php?pagesize=20&pagenum=4'
                ajax(url,function(res){
                    console.log(res)
                    resolve(res)
                },function(erorr){
                    reject(error)
                })
            })

        }) .then(function(res){
            console.log(res)
			let url = 'http://jx.xuzhixiang.top/ap/api/allproductlist.php?pagesize=20&pagenum=4'
			ajax(url,function(res){
			    console.log(res)
			    resolve(res)
			},function(erorr){
			    reject(error)
			})
            
        }).catch(function(error){
            console.log(error)
        })
        
        
    </script>

ajax交互的底层原理,如何封装ajax;

Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。这其中最关键的一步就是从服务器获得请求数据。要清楚这个过程和原理,我们必须对 XMLHttpRequest有所了解。

XMLHttpRequest是ajax的核心机制,它是在IE5中首先引入的,是一种支持异步请求的技术。简单的说,也就是javascript可以及时向服务器提出请求和处理响应,而不阻塞用户。达到无刷新的效果。

所以我们先从XMLHttpRequest讲起,来看看它的工作原理。

首先,我们先来看看XMLHttpRequest这个对象的属性。

它的属性有:

onreadystatechange 每次状态改变所触发事件的事件处理程序。

responseText 从服务器进程返回数据的字符串形式。

responseXML 从服务器进程返回的DOM兼容的文档数据对象。

status 从服务器返回的数字代码,比如常见的404(未找到)和200(已就绪)

status Text 伴随状态码的字符串信息

readyState 对象状态值

0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法)

1 (初始化) 对象已建立,尚未调用send方法

2 (发送数据) send方法已调用,但是当前的状态及http头未知

3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误,

4 (完成) 数据接收完毕,此时可以通过通过responseXml和responseText获取完整的回应数据

ajax,axios,fetch区别对比

1、ajax的优势

1:无刷新更新数据。(局部刷新)

2:异步与服务器通信。(不让界面卡顿)

3:基于标准被广泛支持。

4:界面与应用分离。(前后端分离)

5:节省带宽

ajax缺点:

  • 本身是针对MVC的编程,不符合现在前端MVVM的浪潮
  • 基于原生的XHR开发,XHR本身的架构不清晰,已经有了fetch的替代方案
  • JQuery整个项目太大,单纯使用ajax却要引入整个JQuery非常的不合理

ajax的封装:

<script>
    function ajax(url, callbackfn,errorcallback) {
    	let xhr = new XMLHttpRequest();
    	xhr.open('GET', url)
    	xhr.send(null)
    	xhr.onload = function() {
    		if (xhr.status == 200) {
    			//let str=xhr.responseText
    			let jsonStr = xhr.responseText
    			let obj = JSON.parse(jsonStr)
    
    			console.log(obj)
    			callbackfn(obj)
    
    			return obj
    
    		} else {
    			if (errorcallback) {
    				errorcallback(xhr.responseText)
    
    			}
    		}
    	}
    }

</script>
2、axios
axios({
    method: 'post',
    url: '/user/12345',
    data: {
        firstName: 'Fred',
        lastName: 'Flintstone'
    }
})
.then(function (response) {
    console.log(response);
})
.catch(function (error) {
    console.log(error);
});
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,它本身具有以下特征:
1.从浏览器中创建 XMLHttpRequest
2.支持 Promise API
3.客户端支持防止CSRF
4.提供了一些并发请求的接口(重要,方便了很多的操作)
5.从 node.js 创建 http 请求
6.拦截请求和响应
7.转换请求和响应数据
8.取消请求
9.自动转换JSON数据


3、fetch

fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多了,参数有点像jQuery ajax。但是,一定记住fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。

try {
  let response = await fetch(url);
  let data = response.json();
  console.log(data);
} catch(e) {
  console.log("Oops, error", e);
}
fetch的优点:

1.  语法简洁,更加语义化
2.  基于标准 Promise 实现,支持 async/await
3.  同构方便,使用 [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)
4.更加底层,提供的API丰富(request, response)
5.脱离了XHR,是ES规范里新的实现方式

==总结:
axios既提供了并发的封装,也没有fetch的各种问题,而且体积也较小,当之无愧现在最应该选用的请求的方式。==
深拷贝,浅拷贝
       引用类型直接复制  浅拷贝
	
	引用类型的内部的值的复制,与地址无关    深拷贝
var a=10;
var b=a
// 更换值,a,b互不影响
引用类型拷贝:

var a=[10];
var b=a;
b=[20]//这里是给b一个新的地址
console.log(a)//打印结果为10

var a=[10];
var b=a;
b.push(20)//这里在b原有的地址上加了20
console.log(a)//打印结果为[10],[20]

引用类型直接复制 浅拷贝

    引用类型直接复制(或赋值)称为浅拷贝。 引用类型内部的值的赋值,与地址无关,称为深拷贝
    
    【补充: 假设B复制了A,修改A的时候,看B是否发生变化:
    
    如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)
    
    如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)
    
    浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,
    
    深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,
    
    使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。
    
    浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。
    
    深复制:在计算机中开辟一块新的内存地址用于存放复制的对象。】
    
    Object.assign()//将一个或多个原对象的属性复制给目标对象。
    
    只能实现一维数组的深拷贝
    
    用法:
var obj1={a:1,b:2};
var obj={};
Object.assign(obj,obj1);
console.log(obj)//打印值为{a:1,b:2}
obj.a=10;
console.log(obj1)//打印值为{a:1,b:2}
 var obj1={a:[1],b:2};
var obj={};
Object.assign(obj,obj1);
console.log(obj)//打印值为{a:1,b:2}
obj.a.push(2);
console.log(obj,obj1)//打印值为{a:[1,2],b:2}{a:[1,2],b:2}
var obj1={a:[1],b:2};
var obj2={c:3,d:4};
var obj={}
object.assign(obj,obj1,obj2)
console.log(obj)//打印值为:{a:[1],b:2,c:3,d:4}
var obj1={a:[1],b:2};
var obj2={a:3,d:4};
var obj={}
object.assign(obj,obj1,obj2)
console.log(obj)//打印值为:{a:3,b:2,d:4}证明如果有重复的值名,后面会覆盖前面的。
Objext.defineProperty()定义一个对象的属性,这些属性具有可配置性。

var obj={}
Objext.defineProperty(obj,'a',{
    value:1
})
console.log(obj)//打印结果{a:1}
var obj={}
Objext.defineProperty(obj,'a',{
   value:1
   enumerable:true//默认不可遍历,加上 enumerable:true允许遍历
})
console.log(obj)//打印结果{a:1}
for(var i in obj){
   console.log(i)//打印结果为a
}
//Writable:true可修改,false不可修改
//Configurable:false  不可删除,true可删除

深拷贝方法封装:

            function deepCopy(obj){
				//Array.isArray(obj)判断小括号里的参数是不是一个数组
				if(Array.isArray(obj)){
					var newObj=[]
				}else{
					var newObj={}
				}
				for(var i in obj){
					if(typeof obj[i]=="object"){
						newObj[i]=deepCopy(obj[i])
					}else{
						 newObj[i]=obj[i]
					}
				}
				
				return newObj;
			}
			var arr=[[1],2,3]
			var arr1=deepCopy(arr)
			arr1[0].push(2)
			console.log(arr,arr1)
			console.log(deepCopy([[1],2,3]))

深拷贝的第二种方法:

可以实现多维数组的深拷贝

            var obj={a:[1,2,3]}
			var obj1=JSON.parse(JSON.stringify(obj))
			obj1.a.push(2)
			console.log(obj,obj1)

常用数组方法,数组-字符串转换

https://www.cnblogs.com/jinzhou/p/9072614.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值