JS中的对象、函数以及作用域

JS中的对象、函数以及作用域

一、对象

1、对象的创建方法

  • 构造函数创建法

var o=new Object();

  • 字面量创建法

var o={a:1};

2、对象中的值是以键值对的形式存在,每个键对应唯一的值。
      键必须是字符串或者Symbol,如果不是则会隐式转换为字符串

key value 键 值

3、对象的存储一共有两种情况,一种是存储数据,一种是存储函数
      存储数据的叫做对象的属性,存储函数叫做对象的方法

var o = {a: 1,b: true,c: {d: 10},e: function (){}}

4、对象的引用

console.log(o.a);//用点语法不加双引号
console.log(o[“a”]);
注意:o.a相当于o[“a”]
var o={};
o.a=1;
o[“b”]=2; //往对象o中添加属性和属性值
delete o.c; //删除对象o中的属性,删除属性 ,如果删除的属性不存在,也不会报错

如果键是一个变量,不能使用.语法,必须使用[ ]带入变量

5、遍历对象的属性

console.log(“a” in o);
for(var prop in o){
console.log(prop,o[prop]);
}
// 对象中存储的内容 相互之间是没有关联的
// 如果需要在对象中查找是否有某个键 (“a” in o);
// 如果需要在对象中查找是否有某个值,只能通过for in遍历对象查看每个值是否满足

6、对象存储在堆中,栈中的是对象存储在堆中的引用地址

7、对象赋值

这种方式是赋值了引用地址,因此o和o1是同一个引用地址,同一个对象
修改任何一个,另外变量看到的也是被修改后的结果
var o={a:1};
var o1=o;
o1.a=10;
console.log(o.a);
通过for in遍历对象复制	//浅复制
var o={a:1,b:2};
var o1={};
for(var prop in o){
	o1[prop]=o[prop];
}
在对象复制时,对象里面的属性也是一个对象,那么会把这个对象属性的引用地址存到属性值中
只有深复制才可以真正将一个对象的每个属性都复制没有引用关系(深复制查看文章递归)

https://blog.csdn.net/m0_52634705/article/details/115453765

8、练习

//String.fromCharCode() ascii码函数		97-122能输出小写字母a-z
利用这个函数创建一个对象,属性为a,b,c...z  属性值分别为1,2,3,...26

var o=new Object();
for(var i=1;i<27;i++){
	o[String.fromCharCode(i+96)]=i;
}

二、垃圾回收机制

    // var o={a:1};

    // 将栈中变量o设置为null,表示不再引用对象,然后将堆中这个对象的引用列表中这个变量去除
    // o=null;
    // 如果说一个对象被多个变量引用,只有将所有引用该对象的变量全部设置为null,才可以被垃圾回收
    //只有存储引用地址的变量才需要设置null来做垃圾标识
    //内存泄漏   大量的不使用的引用对象,没有被标识为null,并且还在不断生成和丢弃

	例如:删除堆中的内容,必须先把引用关系设置标识为null
	 var div=document.getElementById("div1");
 	div.remove();
	div=null;
	console.log(div);

三、函数

1、函数的结构形态

function fns(a,b){ }
function    定义函数
fns    函数名,可以自己起,与变量命名相同,且它本身就是一个变量
(a,b)     可以向函数中注入的数据,a,b叫做形参,注入几个数据就要声明几个参数
{}    就是函数执行的语句块

2、函数的执行

fns(4,5)   执行函数就是将函数中的语句块全部运行一遍
fns   函数名
(4,5)   4,5是实参,4将会赋值给a,5将会赋值给b,完全按照参数的顺序赋值

3、函数的参数

  1. 如果实参数量小于形参数量 那么最后没有赋值形参则是undefined;如果形参属性小于实参数量,那么多出来的实参无法从形参上获取。
  2. 形参初始值,当实参没有传入对应的值(实参是undefined),默认是形参初始值,当实参传入了值,则为实参的值。
    必要的形参定义在函数的前面,非必要的形参定义在后面,大多数的初始值都是针对非必要形参。
    形参中ES5不能设置形参初始值,ES6中形参可以设置初始值。

function fn(a,b,c,d=10){console.log(a,b,c,d)}

  1. ES6中,传入不定数量的参数时都会被放在arg这个数组中,
    如果还有其他形参,…arg必须放在形参的最后一个。

function fn(…arg){console.log(arg)}
function fn(a,…arg){console.log(arg)}

4、arguments

  1. 所有通过执行函数时输入的实参(实参列表)
  2. arguements.length    表示当前函数内传入的实参数量
  3. console.log(fn1.length);   通过获取函数的length可以获取到函数的形参数量
  4. arguments[索引] 可以通过索引值查看对象的数据,索引值从0开始递增,所以最后一个数据的索引值一定是length-1
  5. arguments.callee   表示当前函数 (ES6中不再使用)
    arguments.callee.name   表示当前函数的名字
    arguments.callee.caller   调用当前函数的上下文函数 (ES6中不再使用)
function fn1(){
	console.log(arguments.callee);
	console.log(arguments.callee.name);
	console.log(arguments.callee.caller);
}
function fn2(){
	fn1();
 }
fn2();
fn1();

拓展:匿名递归
function fn1(fn){
	fn(0);
}
fn1(function(a){
	a++;
	console.log(a);
	if(a>4) return;
	arguments.callee(a);
})

5、return

return作用

  1. 跳出当前函数,不会执行return后的语句
  2. 使用return返回一个运行结果,或者一个值,仅能返回一个

当函数执行完成后,如果使用return返回了一个值,将会把返回值赋值给a,如果函数中没有return或者直接return没有返回数据,则a的值为undefined
function fns(a,b){
    return 10;
}
var a=fns(4,5)

return用法拓展

  1. 限制函数传入的参数类型或者其值得范围,来判断是否执行函数还是跳出。
function fn1(a){
	if(!a) return;
	var s=a+5;
	console.log(s);
}
fn1(5);
fn1();
  1. break跳出循环,执行函数中循环后的语句,
    return跳出函数,直接从循环中跳出函数。
function fn(){
	var s=0;
	for(var i=0;i<10;i++){
		s+=i;
		if(i===7) return s;
	}
	console.log("aaa");
}
  1. 点击运行
var bool=false;
var div1=document.getElementById("div1");
var x=0;
var bool=false;
div1.onclick=function(){
	bool=!bool;
}
setInterval(function(){
	if(!bool) return;
	x++;
	div1.style.left=x+"px";
},16)
  1. 单例模式
var o;
function fn1(){
	return o|| (o={});
}
写法二:
function fn1(){
	if(!o) o={};
	return o;
}

var a=fn1();
var b=fn1();
console.log(a==b);
对象a和b相等!!!
  1. 工厂模式…批量创建不同的对象
function fn1(name,age,sex){
	return {name,age,sex};		//对象的属性名如果和值的变量名相同,可以直接带入
}
var o=fn1("张三",30,"男");
var o1=fn1("李四",20,"男")
  1. return返回多个数据的两种方法
方法1:返回数组
function fn1(a,b){
	a++;
	b*=2;
	return [a,b];
}
方法2:返回对象
function fn1(a,b){
	a++;
	b*=2;
	return {a,b};
}

var o=fn1(2,4);
console.log(o);
  1. 闭包(函数里面返回一个函数)
function fn1(a){
	return function(b){
			console.log(a,b);
		}
}
var f=fn1;
f(1)(2);
  1. 对象中的函数
    写在对象方法中的this一般指向对象,写在对象属性中的this是指当前所在的上下文环境中this指向
var a=10;
var obj={
	a:1,
	b:function(){
		console.log(this.a);
	}
	c:this.a
}
var o=obj;
obj={c:10};
o.b();
console.log(o);

可以通过return this,来让对象中的方法实现连缀
var obj={
	a:1,
	run:function(){
		console.log("run");
		return this;
	},
	play:function(){
		console.log("play");
		return this;
	},
}
obj.run().play();

四、函数的三种创建方式

1、函数创建–命名函数法

命名函数法(声明式函数)

function fn(){}

ES6 类中函数创建

class Box{
    play(){
    
    }
}

ES6 对象中函数创建

var obj={
    play(){
    
    }
}

注意点1
命名函数法创建的函数,可以在函数所在的script标签的任意位置执行,或者当前函数所在的script标签后面的所有标签中执行。
原因:函数被存储在堆中,在创建script标签时,将命名函数存储在堆中,并且在栈中以函数名做引用。

注意点2
当定义全局变量名且与函数名相同时,如果仅定义没有赋值,函数已经先定义过,所以不覆盖,如果定义并且赋值了,那么变量就会被新的赋值覆盖,原函数无法找到

console.log(fn);        fn函数
var fn;    没有赋值,此时fn还是函数
var fn=3;
console.log(fn);    //3 原函数会被覆盖
function fn(){}

2、函数创建–匿名函数法

匿名函数法(赋值式函数)

var fn=function(){}
fn()
div.οnclick=function(){}

匿名函数自执行函数,只能执行一次

(function(){
    console.log(“aaa”);
})();
    
~function(){
    
}();
    
+function(){
    
}();

注意点
匿名函数法创建的函数,只能在函数被定义后执行。

3、函数创建–构造函数法

构造函数法

var fn=new Function(“a”,“b”,“var s=a+b;return s”);
相当于
function fn(a,b){
    var s=a+b;
    return s;
}

缺点:在调用时,浏览器会将这个函数对象内的所有内容转换为代码,这需要消耗大量性能
优点:可以动态生成函数

五、JSON

JSON详细介绍跳转链接

json 是一种字符串格式,{}中属性名是用双引号引起来的

1、JSON.stringify(对象) 把对象转换成json字符串格式
JSON字符串在转换时会丢弃对象中方法

var obj={
	a:1,
	b:2,
	c:"abc",
	e:{
		f:10
	},
	h:function(){
		console.log("aaa")}
}
var str=JSON.stringify(obj);
console.log(str);

2、JSON.parse(json格式的字符串) 将json格式的字符串转换为对象

var str1='{"name":"chang","age":30,"man":true}';
JSON.parse(str1)

六、作用域

1、全局变量

  • 全局作用域window
  • 函数外使用var定义的变量都是全局变量
  • 在任何位置都可以调用全局变量

2、局部变量

  • 局部作用域function
  • 在函数内使用var定义的变量都是局部变量,就是该函数内的局部变量
  • 只能在函数内部调用,不能在函数外或者别的函数中调用
  • 局部函数只能在当前函数内定义,并且函数执行完毕后会自动销毁该局部变量

3、作用域的三个机制

变量的定义机制

  • 在哪个作用域定义的变量,就是这个作用域的私有变量
  • 只能在这个作用域及所有后代作用域中使用

变量的赋值机制

  • 如果在函数中给一个变量赋值,而这个变量在全局和局部都没有定义过,会把这个变量定义为全局变量,再次进行赋值

变量的使用机制

  • 当访问一个变量时,如果自己的作用域内有,则使用自己的,如果没有则去父级查找,直到全局作用域都没有,就会报错:xxx is not defined

4、注意点

  • 只要在函数内任何位置定义了局部变量(使用var在函数内定义的变量),在这个函数中就不能找到同名的全局变量,在局部变量定义之前调用这个局部变量都是undefined
var a=5;
function fn(){
	if(a===undefined){
		var a=6;
	}else{
		a=7;
	}
	console.log(a);
}
fn()
console.log(a);
  • 因为全局变量是建立在window中,所以通过window调用
var a=5;
function fn(){
	var a=10;
	console.log(a+window.a);
}
fn();

七、回调函数

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值