js笔记二

提示:从46节开始记录,地址https://www.bilibili.com/video/BV1p4411u7TT

一、对象

js中的6种数据类型:

  • String 字符串
  • Number 数值
  • Boolean 布尔值
  • Null 空值
  • Undefined 未定义
  • 以上5种类型属于基本数据类型,以后我们看到的值,只要不是上面的5种,全都是对象
  • Object 对象
    基本数据类型都是单一的值”hello“ 123 true ,值和值之间没有任何的联系
在js中表示一个人的信息(name gender age)
var name="大明";
var gender="男";
var age=18;
如果使用基本的数据类型,我们所创建的变量都是独立的,不能成为一个整体。
  • 对象属于一种复合的数据类型,在对象中可以保存多个数据类型不同的属性。

对象的分类:

  1. 内建对象
    由ES标准中定义的对象,在任何的ES的实现中都可以使用,比如:Math String Number Boolean Function Object…
  2. 宿主对象
    由js的运行环境提供的对象,目前来讲主要指由浏览器提供的对象,比如:BOM(浏览器对象模型) DOM(文档对象模型)
  3. 自定义对象
    由开发人员自己创建的对象
//创建对象
/*
使用 new关键字调用的函数,是构造函数constructor
构造函数是专门用来创建对象的函数
使用typeof检查一个对象时,会返回object
*/
var obj=new Object();
console.log(obj);//[object Object]
console.log(typeof obj);//object

/*在对象中保存的值称为属性
在对象添加属性:
	语法:对象.属性名=属性值
*/
obj.name="大明";
console.log(obj.name);//大明
console.log(obj.hello);//undefined
delete obj.name;//删除对象的name属性

对象的操作

  • 在对象中保存的值称为属性
  • 在对象中添加属性
       语法:对象.属性名=属性值
  • 读取对象中的属性
       语法:对象.属性名
       如果读取对象中没有的属性,不会报错,会返回undefined
  • 修改对象的属性值
       语法:对象.属性名=属性值
       和添加一样,即覆盖了。
  • 删除对象属性
       语法:delete 对象.属性名
  • 使用 new关键字调用的函数,是构造函数constructor
    构造函数是专门用来创建对象的函数
    使用typeof检查一个对象时,会返回object

属性名和属性值

(1)属性名

  • 对象的属性名不强制要求遵守标识符的命名规范,什么名字都可以使用,但是在使用时尽量按照标识符的规范去做。
  • 如果要使用特殊的属性名,不能采用.的方式来操作,需要另一种方式:
        语法:对象[“属性名”]=属性值
  • 使用[]这种形式去操作属性,更加的灵活,在[]中可以直接传递一个变量,这样变量值是多少就会读取那个属性。
  • []里面可以传变量,而.一定是写死的
let n="123";
obj["123"]=789;
console.log(obj.123);//错误!特殊的属性名,不能这么用
//特殊属性名的正确调用如下(怎么赋值的怎么调用)
console.log(obj["123"]);//789
console.log(obj[n]);//789

(2)属性值

  • JS对象的属性值,可以是任意的数据类型(也可以是一个函数)
  • 函数也可以作为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法,调用这个函数就说是调用对象的方法。但是它只是名称上的区别,没有其他区别。
    //调方法
    obj.sayName();
    //调函数
    fun();
  • 判断一个属性中是否含有某属性
       in 运算符:通过该运算符可以检查一个对象中是否含有指定的属性。如果有则返回true,没有返回false
       语法:“属性名” in 对象
//检查obj中是否含所有test2属性
console.log("test2" in obj);//有test2属性就返回true,否就返回false

重要

var obj={
	name:"大明",
	age:"18"
}
obj.sayName=function(){
	console.log(obj.name);
}
console.log(obj.sayName);//输出结果如下:
//function(){
//	console.log(obj.name);
//}
sole.log(obj.sayName());//大明
var obj={
	name:"大明",
	age:"18"
	sayName:function(){
		console.log(obj.name);
	}
}
console.log(obj.sayName);//输出结果如下:
//function(){
//	console.log(obj.name);
//}
sole.log(obj.sayName());//大明

1.对象的进阶

//创建多个对象,笨办法
var obj={
	name:"孙悟空",
	age:18,
	gender:"男",
	sayName:function(){
		alert(this.name);
	}
}
var obj2={
	name:"猪八戒",
	age:24,
	gender:"男",
	sayName:function(){
		alert(this.name);
	}
}
var obj3={
	name:"沙和尚",
	age:45,
	gender:"男",
	sayName:function(){
		alert(this.name);
	}
}
obj.sayName();
obj2.sayName();
obj3.sayName();

使用工厂方法创建对象

//创建一个对象
var obj={
	name:"孙悟空",
	age:18,
	gender:"男",
	sayName:function(){
		alert(this.name);
	}
};
/*
使用工厂方法创建对象
通过该方法可以大批量的创建对象
*/
function createPerson(){
	//创建一个新的对象
	var obj=new Object();
    //将新的对象返回
    return obj;
}
var obj2=createPerson();

二、基本和引用数据类型

1.基本数据类型

  • String Number Boolean Null Undefined 5种基本数据类型

2.引用类型

  • Object

3.区别

  • 基本数据类型保存的是值
  • 引用数据类型(对象)保存的是地址
var a=123;
var b=a;
a++;
console.log("a="+a);//124
console.log("b="+b);//123
//可见,这里的a和b是独立的(修改一个数据,不会影响另一个)
var obj=new Object();
obj.name="孙悟空";
var obj2=obj;//没有new,所以没有创建新对象
obj.name="猪八戒";
console.log(obj.name);//猪八戒
console.log(obj2.name);//猪八戒
//可见,修改了一个影响力另一个。引用类型的地址相同,所以指向的地址是相同的。

4.解析

  • JS种的变量都是保存在栈结构内的

  • 基本数据类型的值:直接在栈内存中存储,值与值之间是独立存在的,修改一个变量并不会影响其它变量。
    栈内存

  • 引用数据类型(对象)是保存在堆内存中的,每创建一个新对象,就会在堆内存中开辟出一个新的空间,而变量保存的是对象的内存地址(对象的引用)。如果两个变量保存的是同一个对象的引用,当一个通过一个变量修改属性时,另一个也会受到影响。
    堆内存
    在这里插入图片描述

5.总结

对象的地址存放在栈内存中,而对象的内容存在堆内存。修改对象的属性值,修改的是堆内存的内容。
对对象的名字进行操作就是对对象的地址进行操作。
每次new一个对象,就是在堆内存中开辟一个新的内存空间和在栈内存开辟一个空间。只声明,不new,旨在栈内存开辟空间。
两个对象赋值问题
当比较两个基本数据类型时,就是比较值。
而比较两个引用数据类型时,比较的是对象的内存地址。

如果两个对象一模一样,但是地址不同,比较时也会返回false。

代码如下(示例):

三、对象字面量

创建对象的一种方式,有两种方式,本质上是 一摸一样的,用对象字面量({})的形式更加省事

  • 语法:{属性名:属性值,属性名:属性值,…}
  • 对象字面量的属性名可以加引号也可以不加引号,建议不加(属性名本质上就是一个字符串)
  • 如果使用一些特殊的符号,则必须加引号
方式一
//用构造函数创建一个对象
var obj=new Object();

方式二
//使用对象字面量创建一个对象,{}就是一个对象字面量
var obj={};
console.log(typeof obj);//object

var obj2={name:"猪八戒”};
console.log(typeof obj);//object

var obj2={"name":"猪八戒”};
console.log(typeof obj);//object

四、函数

(1)函数参数

  • 函数也是个对象,除了基本数据类型,一切都是对象。
  • 函数可以封装一些功能,在需要时调用。存东西了,是一个容器
  • 使用typeof检查一个函数对象时,会返回function
  • 函数对象具有所有普通对象的功能,但是比普通对象更加强大
  • 函数声明的形参,就相当于在函数内部声明了对应的变量,但是并不赋值
  • 在调用函数时,可以在()中指定实参(实际参数),实参将会在赋值中对应形参
  • 调用函数解析器不会检查实参的类型,所以要注意,是否可能会接收到非法的参数,如果有可能需要对参数的类型进行检查。
  • 调用函数时,解析器也不会检查实参的数量 ,多余的实参不会被赋值。
  • 如果实参的数量少于形参的数量,则没有对应实参的形参将会是undefined
  • 函数的实参可以是任意数据类型,当我们的参数过多时,可以将参数封装到一个对象,然后通过对象传递(这样,就不用担心因为参数过多,还要对应参数顺序的问题了)
  • 实参也可以是一个函数(因为函数也是个对象,所以可以做为实参,对象能干的事情函数都能干)
  •  eg: fun()
      fun和fun()的区别
      fun为函数对象,相当于直接使用函数对象
      fun()为调用函数,相当于函数的返回值

  fun相当于机器,是做冰激凌的机器,可以用来做冰激凌
  fun()相当于冰激凌,是个结果

var obj="晴天";
function sayHello(a){
console.log("今天是"+a)
}
function fun(a){
console.log("a="+a);
a(obj);
}
fun(sayHello);//写的时候没有加括号
//console.log("a="+a);   这是sayHello函数的打印
//今天是晴天

(2)返回值

  • 返回值可以是任意的数据类型,也可以是对象、函数
  • 可以使用return来设置函数返回值,return手的值作为函数执行结果返回,可定义一个变量来接收这个结果
  • 在函数中return后的语句都不会执行
  • 如果return语句后不跟任何值就相当于返回一个undefined
  • 如果函数中不写return,则也会返回undefined
  • return后可以跟任意类型的值
  • eg: alert()没有返回值

(3)break、continue、return的区别

  1. break
    退出当前的循环
  2. continue
    跳过当次循环
  3. return
    结束整个循环
方式一:用构造函数创建对象
..创建一个函数对象
var fun=new Function();
console.log(typeof fun);//function
//可以将要封装的代码以字符串的形式传递给构造函数
//但是我们在实际开发过程中很少使用构造函数创建对象
var fun=new Function("console.log('hello world!');");
console.log(fun);//console.log('hello world!');

//封装到函数中的代码不会立即被执行
//函数中的代码会在函数调用的时候执行
//调用函数:函数对象()
//当调用函数时,函数中的代码会按照顺序执行
fun();//console.log('hello world!');
方式二:使用函数声明创建一个对象
语法:
	function 函数名([形参1,形参2.....形参n]{
		语句...
	}
function fun2(){console.log("这是第二个函数");}
console.log(fun2);//function fun2(){console.log("这是第二个函数");}
//调用fun,函数里面的方法才会执行
fun2();
方式三:使用函数表达式来创建一个函数
var 函数名 =function([形参1,形参2...形参3]){//创建一个匿名函数,将匿名函数对象赋值给变量
	语句....
}

(4)函数内部声明函数

function fun3(){
	//在函数内部再声明一个函数
	function fun4(){
		console.log("我是fun4");
	}
	fun4();
}
fun3();//我是fun4

重要

function fun3(){
	//在函数内部再声明一个函数
	function fun4(){
		console.log("我是fun4");
	}
	return fun4;
}
a=fun3();//a为函数fun4
console.log(a);//打印结果如下:
//function fun4(){
//		console.log("我是fun4");
//	}

a();//打印结果如下:
//function fun4(){
//		console.log("我是fun4");
//	}

fun3()();//打印结果如下:
//function fun4(){
//		console.log("我是fun4");
//	}

function fun3(){
	//在函数内部再声明一个函数
	function fun4(){
		console.log("我是fun4");
	}
	return fun4();
}
a=fun3();//a为函数fun4
console.log(a);//打印结果如下:
//我是fun4

(5)枚举对象中的属性

  • 枚举中的属性使用for…in 语句
  • 语法:
    for(var 变量 in 对象){//n为属性名
    语句…
    }
  • for…in 语句 对象中有几个属性,循环体就会执行几次,每次执行时,会将对象中的一个属性名字赋值给变量
  • 中括号[]可以传变量
  • eg: obj.n和obj[n],其中[]中可以传递变量,而点不可以
//枚举中的属性使用for...in 语句
语法:
for(var 变量 in 对象){ //n为属性名
	语句1...
}

var obj={
	name:"大明",
	age:18,
	gender:"男"
}
for(var n in obj){
	console.log("hello");
}
//会输出三次hello

for(var n in obj){
	console.log(n);
}
//name
//age
//gender

for(var n in obj){
	//console.log(obj.n);	//这样输出三个undefined,说明obj中并没有n属性
}
for(var n in obj){
	console.log("属性名="+n);
	console.log("属性值="+obj[n]);	//这样输出三个属性值,调用正确
}

五、立即执行函数

  • 函数定义完毕,立即被执行,往往只执行一次
    想要作图个函数,立即执行,执行完了再也没用了,如果创建一个对象接收这个函数,就有点不值当,怎么办呢?
function(){//若在js中直接这么写,会报错(哟弄个一个变量接收的话,才不会报错,有什么方法不用定义一个变量接收,还不报错呢?)
//为什么值么会报错:js中把{}当作了一个代码块,{前的不能识别了,所以会报错
	console.log("hello);
}

//用一个括号把匿名函数圈起来表示一个整体(表示一个函数对象),就不会报错了function(){
	console.log("hello);
}//那这个匿名函数怎么调用呢? 因为圈起来表示一个函数对象了,所以在后面加()就可以直接调用了function(){
	console.log("hello);
}();
//(立即执行函数)匿名函数如何接收实参呢?
(function(){
	console.log("a="+a);
	console.log("b=)+b;
})(123,456);
//执行结果:
//a=123
//b=456

六、作用域

作用域,指一个变量作用的范围
在js中有两种作用域

(1) 全局作用域

直接编写在script标签中的代码,都在全局作用域中

  • 全局作用域在页面打开时创建,在页面关闭时销毁
  • 在全局作用域中,有一个全局对象window,我们可以直接使用,它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用。
  • 在全局作用域中,我们创建的变量都会作window对象的属性值保存
  • 创建的函数,都会作为window的方法
  • 全局作用域中的变量都是全局变量,在页面中的任意部分都可以访问的到
var a = 10;
console.log(a);//10
console.log(window.a);//10

function fun(){
   console.log("我是fun函数");
}
fun();//我是fun函数
window.fun();//我是fun函数

(2)函数作用域——比较重要

  • 调用函数时创建函数作用域,函数执行完毕后,函数作用域销毁
  • 每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的、
  • 在函数作用域中可以访问全局作用域,反过来不可
  • 当在函数作用域操作一个变量时,它会在自身作用域中寻找,如果有就直接使用,如果没有则向上一级作用域中寻找(注意,是上一级作用域,而不是直接去全局)。如果全局作用域依然没有找到,则会报错ReferenceError
  • 在函数中想要访问全局变量,可以使用window对象
  • 在函数作用域中也有声明提前的特性,使用var关键声明的变量,会在函数中所有的代码执行之前被声明(注意:当在函数作用域操作一个变量时,它会在自身作用域中寻找,注意声明提前的特性)。
  • 函数声明 也会在函数中所有的代码执行之前执行。
  • 在函数中,不使用var声明的变量都会成为全局变量
  • 形参定义就相当于在函数作用域中声明了变量
var c=33;
function fun(){
	console.log("c="+c);
	var c=10;
}
fun();
//输出:undefined
var c=33;
function fun(){
	console.log("c="+c);
	c=10;
}
fun();
//输出:33
var c=33;
function fun(){
	console.log("c="+c);
	c=10;
}
fun();
console.log("c="+c);
//输出:33和10

//因为:在函数中,不使用var声明的变量都会成为全局变量
var c=33;
function fun(){
	d=10;//d没有使用关键字var,则会设置为全局变量。这里的d相当于window.d
}
fun();
console.log("d="+d);

//输出:d=10
//因为:在函数中,不使用var声明的变量都会成为全局变量
var c=33;
function fun(c){
	alert(c);//形参定义就相当于在函数作用域中声明了变量
}
fun();//没有声明形参。但是,形参定义就相当于在函数作用域中声明了变量。这里相当于 var c;alert(c);
//输出:undefined
//因为:在函数中,不使用var声明的变量都会成为全局变量

(3)补充

  • 输出对象中不存在的属性,会打印undefined
  • 输出不存在的变量,会报错

七、变量的声明提前

a=123;
console.log(a);//123,可以看出,不用var声明变量,也可以使用。默认存在window中

一个奇怪的现象

console.log(a);
var a=123;

浏览器竟然不报错!!!!输出结果为undefined!!!
console.log(a);
a=123;

浏览器报错了!!!!

这个奇怪的现象就是”变量的声明提前“:使用var关键字声明的变量,会在所有代码执行之前被声明(被声明,不是被声明且赋值,只想到该行代码才会被赋值),但是如果声明变量时不使用var关键字,则变量不会被声明提前。

又一个奇怪的现象

function fun(){
	console.log("我是一个fun函数");
}
var fun2=function(){
	console.log("我是fun2函数");
}
fun();//我是一个fun函数
fun2();//我是fun2函数
fun();//我是一个fun函数。竟然不报错!!!!!!!
fun2();//报错了!!!!!!!!!!!undefined is not a function
console.log(fun2);//undefined.不报错,因为是用var声明的
function fun(){
	console.log("我是一个fun函数");
}
var fun2=function(){
	console.log("我是fun2函数");
}

这个怪异的现象为”函数的声明提前“:使用函数声明形式创建的函数function 函数(){},它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数。
而var fun2是一个变量,他只会提前声明,但是不会被提前赋值。智慧执行到改行时,才会被赋值。所以不能再声明之前被调用。(使用函数表达式创建的函数,不会被声明提前,所以不会在声明之前调用。)

  • 函数声明,会被提前创建
  • 函数表达式,不会被提前创建

八、debug

在浏览器中的source中可以看到源码

九、this

  • 解析器(浏览器)在调用函数每次都会向函数内部传递一个隐含的参数,这个隐含的参数就是this
  • this指向的是一个对象。这个对象我们称为函数执行的上下文对象
  • 根据函数调用的方式不同,this会指向不同的对象

调用方式:

this是由浏览器传过来的,不是固定的,根据调用情况的不同会发生变化

  1. 以函数形式调用时,this永远都是window
  2. 以方法的形式调用时,this就是调用方法的那个对象。(以函数形式调用时,谁调用this,this就是谁)
function fun(){
	console.log(this);
}
fun();//object Window
var obj={
	 name:"孙悟空",
	 sayName:fun;
}
//obj.sayName和fun是一个东西
console.log(obj.sayName==fun);//true

//但是打印的结果不同
obj.sayName();//object object。打印的是下方的内容:
//Object{
//	 name:"孙悟空",
//	 sayName:fun;
//}
obj对象
fun();//object window
function fun(){
	console.log(this.name);
}
var obj={
	 name:"孙悟空",
	 sayName:fun;
}
var name="全局的name属性";
fun();//打印结果为:全局的name属性

//解析:
/*
————————以函数形式调用,this是window。
所以window下的name属性为 var name="全局的name属性";
*/
function fun(){
	console.log(this.name);
}
var obj={
	 name:"孙悟空",
	 sayName:fun;
}
var name="全局的name属性";
obj.sayName();//打印结果为:孙悟空
//解析:
/*
——————以方法的形式调用,this是调用方法的对象。
所以obj.sayName()方法中的this为调用的是方法中的name
*/

十、this的例子

//创建一个name变量
var name="全局";

//创建一个fun()函数
function fun(){
	console.log(name);
}
//创建两个函数
var obj={
	name:"孙悟空",
	sayName:fun
}
var obj2={
	name:"沙和尚",
	sayName:fun
}
obj.sayName();//全局
//我们希望调用obj.sayName()时可以输出obj的name

//创建一个name变量
var name="全局";

//创建一个fun()函数
function fun(){
	console.log(this.name);
}
//创建两个函数
var obj={
	name:"孙悟空",
	sayName:fun
}
var obj2={
	name:"沙和尚",
	sayName:fun
}
obj.sayName();//孙悟空
obj.sayName2();//沙和尚
//体现了this的好处,谁调用this,this就是谁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值