首页 > 编程语言 >javascript1

javascript1

时间:2023-08-14 15:34:28浏览次数:42  
标签:函数 对象 let log javascript1 拷贝 name

执行环境-作用域-函数进阶-闭包

1.回顾map的使用和与for/forEach的区别

map的使用-只能用于数组,返回一个新数组,map内部必须return

forEach原数组上进行遍历(本质是for循环),要改变原数组第一层值,必须配合索引

当遍历数组为数组对象用forEach可以直接改变第二层的值

例1 
var arr=[1.1,2,3];
var arr1=arr.map(Math.round) //得到一个新数组,每一个值四舍五入

例2
var arr=[1,2,3];
let newArr=arr.map(function(item,index,arr){
  return item //遍历得到的新数组,和原数组相同。
})

map和for/forEach的区别:map返回的是新数组,map和forEach不能用break打断,for循环可以。

forEach不能循环执行异步,for可以!!!!!!

2.什么是执行环境

在编写js代码和执行的时候就会产生相应的执行环境 和变量对象(保存设置的变量和对象);

在全局下定义变量和对象都属于全局执行环境,在函数内定义的属于函数执行环境,他们在运行的时候都会加载到环境执行域(执行栈)中---先入后出(执行完后环境会被销毁)

3.作用域和作用域链

1.什么是作用域--面试题

"标识符"能被访问的的范围,称之为作用域

标识符--var 声明的变量、function声明的函数、函数中的形参

访问的范围--自己的作用域和子作用域

2.什么是作用域链

在执行环境中有多层嵌套关系的执行环境就是作用域链。

3.作用域链的作用

确保对执行环境中变量和函数的有序访问。

4.作用域分类

全局作用域(window)、局部作用域(函数)、块级作用域(es6新增)

块级作用域:let 声明的变量只能在块级作用域里内访问//只在声明的块级作用域{}内有效。

{
	let a=1
}
//外面访问不到a ,换成var 就可以访问

   重新定义 var let const的区别:

var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。

    let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。

    const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。

 

 

 

 

函数进阶

4.箭头函数

let 变量=(形参)=>{};

【注意】:

1)如果只有一个形参,小括号可以省略。

2)如果函数体内只有一句执行代码,花括号可以省略,但是花括号省略后,函数体内如果有return也必须省略。

3)箭头函数没有arguments对象。

4)箭头函数中的this指向定义它时的作用域。

 

5.形参和实参

形参:定义函数时,传入的参数

实参:调用函数时传入的参数

6.arguments对象(实际是一个伪数组,es5语法中的)

什么是arguments?

arguments是函数中的内置对象,是一个伪数组,接收函数调用时传进来的实参。可以用索引访问参数,也可以用.length来查询参数的个数。--arguments原型指针指向构造函数Object

【注意】箭头函数中没有arguments对象

var fn=function(){
	console.log(arguments) //得到一个伪数组
  console.log(arguments[0]) //得到1
  console.log(arguments.length) //得到3
}
fn(1,3,4)

7.rest参数(实际就是一个数组,es6语法中的)

rest参数指代所有的形式参数,如果前面有定义好名字的形参,那么它就代表除了那个参数以外的其他所有参数。(它必须是最后一个形参) 只能写在函数形参中

语法:let 变量名=(...变量名)=>{} //在函数中可以直接使用定义的rest参数

例:
let fn=(...val)=>{
	console.log(val)  //打印得到调用函数时传入参数的集合,一个数组
}
fn(1,3,4)

8.函数的返回值

任何函数都有返回值。如果没有定义return ,默认返回undefined

9.函数的调用

1)普通的调用

2)作为对象中的函数调用

3)作为回调函数调用

4)作为构造函数调用

5)使用bind()/call()/apply()方法调用

6)立即执行函数表达式(IIFE)调用

10.IIFE立即执行函数表达式(常用于插件开发)

语法:;(function(){})() //必须在括号前写上分号,防止报错

什么是立即执行函数??---面试题

1)专业术语:立即执行函数表达式

2)写法:;(function(){})() //第一个()将函数 变成表达式,第二个()调用了这个函数。

3)IIFE的作用,通过形成函数局部作用域 ,避免外界直接访问变量,实现简单的模块化,和let作用一样。

4)一般优先使用let。

 

11.闭包

什么是闭包??--面试题

闭包是一个环境。【函数】和【函数内部跨作用域能访问到的变量】的之和就是闭包。狭义上来说:函数套函数,内部函数调用了父函数内部的变量并返回执行就形成了闭包。广义上来说:全局函数和全局变量也形成了闭包。

本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包的作用使得函数内部可以访问该函数【声明】时所处作用域的变量。让这些变量的值始终保持在内存中。

闭包的特点??

1)变量私有化,避免全局污染

2)内部变量会常驻内存,不会被释放,垃圾回收机制不会将其回收掉,甚至造成内存溢出。

常见的闭包两种写法:

1) 父函数嵌套子函数,把子函数返回

function fn(){
  let a=1;
  return function(){
    return a++;
  }
}
let fn1=fn()
console.log(fn1()) //1
console.log(fn1()) //2 a没有被释放

2)父函数嵌套子函数,把子函数挂载到全局

//闭包可以实现隐藏变量的操作,需要时可以暴露(挂载到全局)来让全局获取,没有暴露就无法访问到隐藏的变量。
;(function(){
	let a=200;
  let b=300;
  window.$key={ //将$key对象挂载到全局,从而可以调用对象下的属性和方法
  	consoleA:function(){
    	console.log(a) 
    }
    senda:function(num){
    	a-=num;
      console.log(a); 
    }
  }
})()
console.log($key.consoleA()) //得到200
console.log($key.senda(10)) //得到190
console.log(b) //会报错 因为没有将他挂载到全局,所以得不到它的值

12.for...of遍历数组

var arr=[1,2,3,4];
for(let val of arr){
	console.log(val) //arr中的每一个值
}

 

面向对象-原型和原型链-this指向

金桔:要做什么找对象-调用对象的函数

面向对象特点:

1)封装

     函数封装

     对象封装

     模块封装

2)继承

 原型链继承

 类继承

 组合寄生(非常推荐)

 。。。

3)多态

 JS函数对类型没有要求,不同函数得到不同结果,导致多态

 严格说,JS的面向对象不存在多态,或者很难实现多态

1.面向对象和面向过程的区别(面试题)

面向过程(pop)

针对程序的运行流程进行编程的思维。

优势:精细把控每一个细节。劣势:代码冗余

理解:小兵思维--什么都亲历亲为。

面向对象(oop)

针对参与程序运行的个体对象进行编程。

优势:可以实现更加复杂的大型项目。

理解:将军思维--什么都安排别人去做。

 

面向对象创建-本地存储对象--用的时候import ...from...引入

//如果有就取出来,没有就等于空数组。

2.类和实例化对象

1)认识

1.类指拥有相同特征的一类事物的抽象。

2.实例化对象指拥有各自特征,能执行某些动作的个体。

3.通过类可以创建任意多个具有相同属性和方法的对象。

2)创建对象的方法

1.内置对象创建(new字符实例化)

2.字面量创建

3.工厂函数创建--该模式没解决对象识别的问题(都是Object),为了解决这个问题,我们又有了新的模式来实现对象的实例化----构造函数模式

function creatplayer(name,sex,skill){
	var obj={};
  obj.name=name;
  obj.sex=sex;
  obj.skill=skill;
  obj.sayname=function(){
  	console.log(obj.name)
  }
  return obj;
}
var player=creatplayer(参数1,参数2,参数3)//调用工厂函数,实现个体创建。
console.log(player)

3.构造函数模式(存在弊端方法过载)

1) 什么是构造函数

构造函数是一种特殊的方法,主要用来创建对象时初始化对象。即为对象成员变量赋值,总与new字符一起使用在创建对象的语句中。通常用来批量化创建对象

2)构造函数的创建和使用

1.设置函数体

2.将传入的参数挂载到this上。

3.通过new字符实例化成不同的对象。

function CreatPlayer(name,age,skill){
  //把参数通过this挂载到函数上
	this.name=name;
  this.age=age;
  this.skill=skill;
  this.fun=function(){console.log(111)}
}
//实例化构造函数创建对象
let obj1=new CreatPlayer(参数1,参数2,参数3)
let obj2=new CeatPlayer(参数1,参数2,参数3)

3)构造函数和普通函数的区别

1.首字母大写,大驼峰命名

2.将属性和方法挂载到this上,this指向最终创建的实例化对象。

3.不需要return语句,默认返回新创建的实例化对象。

4)使用new字符创建对象,中间发生了什么?---面试题

1.创建一个新对象。

2.让this指向这个空对象。(即将构造函数的作用域赋给新对象)。

3.执行构造函数中的代码,为这个对象添加属性和方法。

4.将对象返回。

 

4.原型和原型链【重点】--必考面试题

先了解方法过载概念:

构造函数中有一个缺陷叫方法过载,我们在通过构造函数实例化对象的时候,每个对象都会独立产生一个构造函数中有的函数方法。这样就重复了这个方法,导致内存和运行弊端。

1)什么是原型??---必考面试题

1.构造函数被创建时都会有一个prototype属性,它就是原型对象。里面包含了实例化共享的属性和方法。

2.原型对象中有一个constructor属性,它指向=>构造函数。(实例化出来的对象也会拥有)

3.创建出来的实例化对象,有一个内置的_proto_属性(原型指针),指向=>实例化对应的的原型对象(object)所以通过该属性建立了实例化与原型之间的关系。

通过原型解决方法过载:

function CreatPlayer(name,age,skill){
	//将输入内容挂载到this上
  this.name=name;
  this.age=age;
  this.skill=skill;
  //这里不写方法,通过函数的原型添加方法。
}
//通过构造函数的原型添加方法,实例化出来的对象都会拥有这个方法
CreatPlayer.prototype.fun=function(){console.log(1111)};
let obj1=new CreatPlayer(参数1,参数2,参数3);
let obj2=new CreatPlayer(参数1,参数2,参数3);

通过原型给数组内置方法中拓展一个求和方法:

Array.prototype.sun=function(){
	let res=0;
  this.forEach((item)=>{
  	res+=item;
  })
  return res
}
let arr=[1,2,3,4];
console.log(arr.sun()) //调用自己定义的求和方法

2)什么是原型链---必考面试题

1.一个构造函数拥有对应的原型对象,而这个原型对象又可以是另一个构造函数所创建的实例对象(它也有对应的原型对象),这种关系层层渐进,所构成的链式结构,就是原型链。

2.万物皆对象,万物皆空。

3.一个对象中查找标识符时,会从自身开始,没找到就会沿原型链开始逐层向上找,知道找到为止。

5.this指向

1)全局中的this ---指向window

2)普通函数中的this --谁调用指向谁

3)对象中函数的this ---谁调用指向谁

4)事件处理函数中的this ---指向事件源

5)构造函数中的this ---指向实例化的对象

6)定时器中的this ---指向widow

7)箭头函数中的this ---总是指向声明这个箭头函数的作用域

(箭头函数根本没有自己的this,导致内部的this就是外层代码块的this)

//箭头函数中this的使用
var id=20;
function logId(){
	window.setTimeout(()=>{
  	console.log(this.id)
  },1000)
}
logId.call({id:43}) 
 //此箭头函数绑定了定义时所在的作用域,logId的函数作用域下,所以this才指向了{id:42}

8)bind call 和apply 修改this指向

区别:bind是绑定操作,非立即执行。call和apply都是立即执行,只是传入参数的方式不同(面试题);

1.call改变this指向

对象1.属性名(属性值是函数).call(对象2,参数1,参数2);

2.apply改变this指向

对象1.属性名(属性值是函数).apply(对象2,[参数1,参数2]);

3.bind绑定来改变this指向

let 变量名=对象1.属性名(属性值是函数).bind(对象2,参数1,参数2);

变量名() //调用这个新函数

let obj1={
	name:"小胖",
  say:function(text){
  	console.log(`${name}说${text}`)
  }
}
let obj2={
	name:"大胖"
}
//利用call改变this指向
obj1.say.call(obj2,"我说啥了?11")
//利用apply改变this指向
obj1.say.apply(obj2,["我说啥了?222"]);
//利用bind来改变this指向
let saywhat=obj1.say.bind(obj2,"我说啥了?333");
saywhat(); //调用这个新函数,bind的时候参数可以不写,调用的时候传入参数

 

变量进阶,深浅拷贝

1.基本数据类型和引用数据类型

1)基本数据类型:字符串,数字,布尔,null,undefined,symbol()

2)引用数据类型:object(对象,数组,函数)

数据在内存上的分布----面试题

1)基本数据类型:临时保存它的变量和它的具体数据都存放在栈里面。

2)引用数据类型:临时保存它的变量和指引路径存在栈里,它的真实数据放在堆里面。

2.变量的拷贝

1)基本数据类型的拷贝:拷贝的是具体的值。

2)引用数据类型的拷贝:拷贝的是路径。

1.新的变量拷贝的是旧变量的路径指引,他们会共享一个真实数据,只要其中一个变量对数据做了修改,那么另一个变量使用的也会是更改后的数据。

2.如果在拷贝以后,再给新变量定义一个对象,那么它将拥有一个新的路径指向新的真实数据。整体就和旧变量没有任何关系了。所以再改变新的变量下的属性值,旧的变量始终不会变。

例:

var obj1={
	name:"张三",
  age:20
}
var obj2=obj1;//仅仅只是拷贝了引用地址
obj2={name:"王五",age:10} //重新定义了obj2,它更新了地址,指向了新的真实数据。和obj1没有任何关系了。
obj2.name="马六"
consle.log(obj1) //obj1不再收obj2的影响

3.形式参数的拷贝

1)形参传入基本类型:拷贝的是实际的值。

2)形参传入引用类型:拷贝的是路径。

var obj={
	name:"张三",
  age:20
}
function run(num){
	num.name="王五"
}
run(obj) //将obj作为参数传入函数,就是拷贝了obj的路径,调用函数后改变了name值,obj也会改变。
console.log(obj) //王五  20

4.对象的深浅拷贝---面试题

1)深浅拷贝只能出现在对象上面

2)什么是浅拷贝??

书面:只是拷贝一层属性的值,如果遇到多层属性(引用数据类型)拷贝的是它的路径。

白话:就是把一个对象中属性的值为基本数据类型的数据直接拷贝过去。把属性名对应的值为引用数据类型的路径做一个拷贝。

3)什么是深拷贝??

书面:无限层级拷贝。拷贝后,新旧对象不共享引用数据类型属性的值,新旧对象变更互不影响。

白话:深拷贝可以这样理解,如果属性名对应的值为引用数据类型的时候,用深拷贝方法相当于把这个引用数据的值新开一个路径来保存,所以拷贝以后的变量再修改属性数据的时候,不会影响原来对象的数据(因为路径不同了)。

5.实现对象拷贝的方法

1)浅拷贝--(只能拷贝一层,如果遇到拷贝的对象属性有引用类型,拷贝的是地址)

1.for...in方式

2.Object.assign //原生对象下的内置方法

语法:let 新对象=Object.assign({},源对象1,源对象2...) //源对象可以有多个 如果有相同属性,合并后取后者

例1
var obj={name:"王五",skill:"玩"}
var obj1={name:"张三",age:20}
let obj2=Object.assign({},obj,obj1) //得到新对象 张三  20  玩  
例2
//Object.assign为原型对象添加方法
Object.assign(person.prototype,{
	getNum:function(){},
  getNum2:function(){}
})

3.es6语法:let newobj={...oldobj}

2)深拷贝--拷贝多层

JSON.stringify()和JSON.parse()的组合使用

var obj1={name:"张三",age:20,child:{name:"小强",age:6}}
let obj2=JSON.parse(JSON.stringify(obj1));

6.变量类型检测

1)typeof ---检测基本数据类型

语法:typeOf(检测体)

2)instanceOf ---检测类型为Object的话都是true 因为万物皆对象

语法:检测体 instanceof 预测类型 //返回true 或false

3)isArray ---预判是不是数组,属于Array下的内置方法 和isNaN类似

语法:Array.isArray(数组) //返回true

4)Object.prototype.toString.call() 主流检测方法

语法:Object.prototype.toString.call(检测体)

var obj={};
var arr=[];
Object.prototype.toString.call(obj);//object Object
Object.prototype.toString.call(arr);//object Array

7.Array.from()

 Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组。浅拷贝-拷贝一层。

拷贝数组:循环/slice/运算符/from/concat

function f3(){
  console.log(Array.from(arguments))
}
f3(1,2,3) // [1,2,3]

ES6语法-解构赋值-展开运算符-class类-ES6模块化

 

1.解构赋值

按照一定模式,从数组和对象中提取值,对变量进行赋值。

以=分割,左边变量和右边赋值结构相同,按照顺序一一对应。

1)数组解构赋值--位置不可变,根据【索引】赋值

语法:let [变量1,变量2,变量3=值3]=[值1,值2...] //左边可以提前赋值,右边对应的值可写可不写

2)对象解构赋值--位置可变,根据【属性名】赋值

2.展开运算符

就是把一个对象展开

【注意】因为展开运算符就是三个点,所以要和rest参数区别。(后者只能在函数的形参中使用)

用法举例:

例1
let a=[1,2,3]
let b=[4,5,6]
let c=[...a,...b] //合并数组
例2
function f(a,b,c){
	console.log(a,b,c)
}
let arr=[1,2,3]
f(...arr)
例3
Array.prototype.push.apply(a,b) // a=[1,2,3,4,5,6]
a.push(...b) // a=[1,2,3,4,5,6]

 

可以使用展运算符做数组或对象的拷贝 ---浅拷贝

用扩展运算符对数组或对象进行拷贝时,只能扩展和深拷贝第一层的值,对于第二层及其以后的值,扩展运算符将不能对其进行打散扩展,也不能对其进行深拷贝,即拷贝后和拷贝前第二层中的对象或数组仍然引用的时同一个地址,其中一方改变,另一方也跟着改变。

var obj1={name:"张三",age:20}
var obj2={...obj1}

3.  set 不重复的集合

//数组去重

Let arr=[1,2,2,3,3,5,6]

Console.log([…new Set(arr)])

4.class类--es6

什么是类?基于原型的面向对象语言。可以认为类就是构造函数的另一种写法。

class关键字定义类

class person {
  //构造器,传参使用,没有参数可以不写
 	constructor(name, age) {
    this.name = name,
    this.age = age
  }
  sex = 200
Show() { console.log(123) }//原型方法,实例化对象共享
static show1() { console.log(456) } //静态方法,类独有
}
let obj = new person("张三",20) //实例化

 

class 类的继承

class Father{ //父类--鱼类
   constructor(name,age){ //构造器 不传参可以不写
     this.name=name
     this.age=age
   }
   skills=["游泳","睡觉","吃食"]
getFatherSkill(){ //原型方法
  console.log(this.skills)
}
}
class Son extends Father{ //子类--花鲢--拥有父类所有属性方法
  constructor(name,age){
    //ES6 要求,子类的构造函数必须执行一次super函数,为了拿父类的this
    super(name,age) //调用父类构造函数 拿父类this
  }
  color="blure" //定义类的私有属性
}
const lian1=new Son("花鲢1",4)
lian1.skills.push("装死")
console.log(lian1) //添加了装死
const lian2=new Son("花鲢2",6)
console.log(lian2) //没有装死  ,所以继承的子类实例化出来的对象互不影响

5.ES6模块化

方式1

导出:

export 变量;

多个变量可用export{变量1,变量2...}

推荐:export {arr,fn}

引入:

import{变量}from "路径"; //.js文件名后缀可以省略

方式2

导出:

export default xxx(变量,函数...) //一个js文件只能使用一次

export default sayHi

引入:

import xxx from "路径";//xxx可以是自己命名的名字

import hello from "./js/login"
hello()

 

 

 

标签:函数,对象,let,log,javascript1,拷贝,name
From: https://www.cnblogs.com/sclweb/p/17628780.html

相关文章

  • 【JavaScript19】解构赋值
    JavaScriptES6新增解构赋值,可以快读从数组或对象中取出成员。解构:将对象或者数组中的某个成员取出来;赋值:取出来的成员按顺序赋值给变量。数组的解构赋值使用中括号[]来进行解构数组,需注意变量名称和数组的值一一对应;或者把数组设置为一个变量,再解构let[a,......
  • 【JavaScript17】eval函数
    eval本身在js里面正常情况下使用的并不多.但是很多网站会利用eval的特性来完成反爬操作.我们来看看eval是个什么鬼?从功能上讲,eval非常简单.它和python里面的eval是一样的.它可以动态的把字符串当成js代码进行运行.vars="1+2+3+4+5+6+7+8";varc=eval(s);//帮你......
  • 【JavaScript16】定时器
    在JS中,有两种设置定时器的方案1、setTimeout//语法规则t=setTimeout(函数,时间)//经过xxx时间后,执行xxx函数//m是第几个定时器varm=setTimeout(function(){console.log("我叫xwl");},5000);//单位是毫秒console.log("正常执行的....");......
  • 【JavaScript15】闭包
    什么是闭包闭包(closure)是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰,即形成一个不销毁的栈环境。闭包的特性:函数嵌套函数内部函数可以访问外部函数的变量参数和变量不会被回收。为什么要有闭包?1、先来看一段代码发现没有......
  • 【JavaScript14】函数基础
    函数定义函数定义的方法有多种,主要分为函数声明和函数表达式//函数声明functionfunc(arg1,arg2){console.log("arg1=",arg1);console.log("arg2=",arg2);return"返回一些东西"}varret=func("苹果","鸭梨");console.log(......
  • 【JavaScript11】正则表达式 RegExp对象
    定义正则表达式(英语:RegularExpression,在代码中常简写为regex、regexp或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。搜索模式可用于文本搜索和文本替换。创建RexExp对象有两种方式创建RexExp对象第一种:使用字面量创建RegExp对象的语法:第......
  • 【JavaScript10】Date日期对象
    获取当前系统时间vard=newDate();//当前系统时间console.log(d);//SunAug06202314:49:43GMT+0800(中国标准时间)手动获取时间并且格式化vard=newDate();//当前系统时间console.log(d);//SunAug06202314:49:43GMT+0800(中国标准时间)var......
  • JavaScript1.8.5新特性系列Object.keys
    以前在js-object这个分类里面也写过keys相关的api 在JavaScript1.8.5中,加入了原生的Object.keys这个api  Object.keys(obj);/*简单举例*/Object.keys({"A":"a","B":"b"});//["A","B"]兼容性写法:  if(!Object.keys){Object.keys=......
  • 巨蟒python全栈开发数据库前端5:JavaScript1
     1.js介绍&变量&基础数据类型2.类型查询&运算符&if判断&for循环3.while循环&三元运算符4.函数5.今日总结 1.js介绍&变量&基础数据类型js介绍(1)什么是JavaScript&一些历史......