组成部分 说明 ECMAScript 基础的语法 DOM(Document Object Modle) 文档对象模型 BOM(Browser Object Modle) 浏览器对象模型
typeof
instanceof
Object.prototype.toString.call()
1、一个具体的看得见摸得着的称作为对象
2、对象是一个容器,封装了属性(property)和方法(method)
3、ECMAScript-262 把对象定义为:无序属性的集合,其属性可以包含基本值、对象或者函数。
面向对象的特性:
- 封装性
- 继承性
- [多态性]
面向过程:所有的事情都是亲力亲为,注重的是过程
面向对象:提出需求,找对象,对象解决,注重的是结果
js不是一门面向对象的语言,是基于面向对象的语言,js来模拟面向对象
面向对象的特征:封装、继承、多态(抽象性)
封装:就是包装,把一些重用的内容进行包装,在需要的时候,直接使用 把一个值,存在一个变量中,把一些重用的代码放在函数中,好多相同功能的函数放在一个对象中,把好多功能的对象,放在一个文件中,把一些相同的内容放在一个对象中
继承:类与类之间的关系,js中没有类的概念,js中有构造函数的概念,是可以有继承的,是基于原型
多态:同一个行为,针对不同的对象,产生不同的效果
第一种:字面量创建
var per1 = {}
第二种:调用系统的构造函数
var per2 =new Object();
第三种:自定义构造函数
function Person () {}
var per3 = new Person();
1、开辟空间存储对象
2、把this设置为当前的对象
3、设置属性和方法值
4、返回这个对象
console.dir()
- 总结
- 实例对象和构造函数之间的关系:
- 1、实例对象是通过构造函数来创建的–创建的过程叫做实例化
- 2、如何通过判断判断对象是不是这个数据类型
- 1、通过构造器的方式 实力对象.构造器(constructor)==(构造函数)
- 2、对象 instanceof 构造器函数名字
- 尽可能的使用第二种方式来识别
通过自定义构造函数、来创建对象,对象调用的方法不是同一个方法,
它是自己开辟了一块空间指向了自己那块空间的的方法
由于每一个对象开辟了自己的空间指向了自己的方法,占用系统内存
解决办法:通过原型来解决----->数据共享,节省内存空间,作用之一
- 通过原型添加方法,解决数据共享,节省内存空间
- 语法:
构造函数名字.prototype.方法名/属性 = fn () {};
实例对象中有__proto__这个属性,叫原型,也是一个对象,这个属性是给浏览器使用,不是标准的属性——>__proto__——>可以叫做原型对象
构造函数中有prototype这个属性,叫原型,也是一个对象,这个属性是给程序员使用,是标准的属性——>prototype——>可以叫原型对象
- 构造函数可以实例化对象
- 构造函数中有一个属性叫prototype,是构造函数的原型对象
- 构造函数的原型( prototype )中有一个constructor构造器,这个构造器指向的就是自己所在的原型对象所在的构造函数
- 实例对象的原型对象( __proto__)指向的是该构造函数的原型对象
- 构造函数的原型对象( prototype )中的方法是可以被实例对象直接访问的
- 需要共享的数据可以写在原型中
- 原型的作用之一:资源共享
- 属性需要共享,方法也需要共享
- 不需要共享的数据写在构造函数中,需要共享的数据写在原型中需要共享的数据可以写在原型中原型的作用之一:资源共享属性需要共享,方法也需要共享不需要共享的数据写在构造函数中,需要共享的数据写在原型中
14、简单原型语法
- 构造函数名.prototype = { }
- 注意事项:需要手动修改构造器的指向
15、原型中的方法,是可以互相访问的
原型对象中的方法,可以相互调用的
- 如果实例方法没有,去创建实例对象的构造函数的原型对象中去找
- 实例对象使用的属性或者方法,先从实例中查找,找到了则直接使用,找不到则,去实例对象的 __proto__ 指向的原型对象 prototype 中去找,找到了则使用,找不到报错
- 如何把局部变量变成全局变量?
- 使用自调用函数把局部变量给window就可以了
面向过程和面向对象都是编程的思想,方式不一样
面向过程:凡是都是亲力亲为,所有代码都要自己写,每一步都要很清楚,注重的是过程
面向对象:执行者成为指挥者,只要找到对象,然后然对象做相关的事情,注重的是结果
面向对象的特征:封装、继承、多态
封装:就是代码的封装,把一些特征和行为封装在对象中
面向对象的编程思想:根据需求,抽象出相关的对象,总结对象的特征和行为,把特征变成属性,行为变成方法,然后定义(
js
)构造函数,实例化对象,通过对象调用属性和方法,完成相应的需求.——编程的思想对象:具体特指的某个事物,有特征(属性)和行为(方法),对象可以看成是一坨无序属性的集合
如何创建对象?
通过调用new Object(),还有{},自定义函数创建对象的方式
1、调用系统Object()——>创建出来的对象都是Object类型的,不能很明确的指出这个对象是属于什么类型2、字面量方式{}——>只能创建一个对象(一次只能创建一个)
3、工厂模式创建对象——>推论——>自定义构造函数的方式
自定义构造函数(优化后的工厂模式)自定义构造函数创建对象:4件事
1、在内存中申请一块空闲的空间,存储创建的对象
2、this就是当前实例化的对象
3、设置对象中的属性和方法(为对象添加属性和方法,为属性和方法赋值)
4、把创建后的对象返回
都是需要通过new的方式
构造函数中有一个属性prototype,是原型,程序员使用的
实例对象中有一个属性__proto__,是原型,浏览器使用的,不是很标准的,
实例对象中的__proto__指向的就是该实例对象中的构造函数中的prototype
构造函数中的prototype里面的属性或者方法,可以直接通过实例对象调用
正常的写法:实例对象.__proto__才能访问到构造函数中的prototype中的属性或者方法
per.__proto__.eat();
//__proto__不是标准的属性
per.eat();
原型就是属性,而这个属性也是一个对象
Person.prototype
—>是属性
Person.prototype.属性
或者Person.ptototype.方法()
本身在构造函数中定义的属性和方法,当实例化对象的时候,实例对象中的属性和方法都是在自己的空间中存在的,如果是多个对象。这些属性和方法都会在单独的空间中存在,浪费内存空间,所以,为了数据共享,把想要节省空间的属性或者方法写在原型对象中,达到了数据共享,实现了节点内存空间
原型的作用之一:数据共享,节省内存空间
原型的写法:
构造函数.prototype.属性=值
构造函数.prototype.方法=值---->函数.prototype,函数也是对象,所以,里面也有__proto__实例对象.prototype-------->实例对象中没有这个属性,只有】__proto__(暂时的)
简单的原型的写法
缺陷:—>新的知识点---->原型直接指向{}---->就是一个对象,没有构造器
构造函数.prototype={
切记:如果这这种写法,要把构造器加上通过原型为内置对象添加原型的属性或者方法----->原因:
系统的内置对象的属性和方法可能不满足现在需求,所以,可以通过原型的方式加入属性或者方法,为了方便开发为内置对象的原型中添加属性和方法,那么这个内置对象的实例对象就可以直接使用了
String.prototype.方法=匿名函数;
var str="哈哈";
str.方法();
---->实例对象可以直接调用原型中的属性或者方法
funciton(){
//那么这里的this就是that当前的对象
}.bind(that)
window.变量=值;把这个局部变量的值暴露给window,成为了全局变量
根据需求,分析对象,找到对象有什么特征和行为,通过代码的方式来实现需求,要想实现这个需求,就要创建对象,要想创建对象,就应该先有构造函数,然后通过构造函数来创建对象,通过对象调用属性和方法来实现相应的功能及需求,即可
- 没有
- 而真正的实例对象和原型对象有关系,实例对象和原型对象之间的关系叫原型链,这种关系通过__proto__
- 原型链:是一种关系,实例对象和原型对象之间的关系,关系是通过原型(__proto__)来联系的
- 如果想要使用一些属性和方法,并且属性的值在每个对象中都是一样的,方法在每个对象中的操作都是一样,那么,为了共享数据,节省内存空间,是可以把每个属性和方法通过原型的方式赋值
- 实例对象中有__proto__原型
- 构造函数中有prototype原型
- prototype是对象
- 所以,prototype这个对象中也有__proto__,那么指向了哪里
- 实例对象中的__proto__指向的是构造函数的prototype
- 所以,prototype这个对象中的__proto__指向的应该是某个构造函数的原型prototype
改变了原型对象的指向:构造函数.prototype = new Person(10);
- 如果原型指向改变了,那么就应该在原型改变之后添加原型方法
7、实例对象对象的属性和原型对象属性重名问题
- 实例对象访问这个属性,应该先从实例对象中去找,找到了就直接使用,找不到就去指向的原型对象中去找,找到了就使用,找不到呢?——>undefined
- 通过实例对象能否改变原型对象中的属性值?不能
就想改变原型不过对象中属性的值,怎么办?直接通过原型对象.属性=值;可以改变- 原型链:实例对象和原型对象之间的关系,通过__proto__
继承的目的:解决代码重复,造成了代码的冗余
改变构造函数的原型的指向即可
语法:
构造函数.prototype = new 对象();
因为任何实例对象中都会__proto__原型对象,指向的是该实例对象中的构造函数中的prototype
- 为了数据共享,改变原型指向,做带了继承——>通过改变原型指向实现的继承
- 缺陷:因为改变原型指向的同时实现继承,直接初始化了属性,继承过来的属性的值都是一样的了,所以,这就是问题,只能重新调用对象的属性进行重新赋值
- 解决方案:继承的时候,不用改变原型的指向,直接调用父级的构造函数的方式来为属性赋值就可以了——>借用构造函数:把要继承的父级的构造函数拿过来,使用一下就可以了
- 借用构造函数:构造函数名字.call(当前对象,属性,属性,属性…)
- 解决了属性继承,并且值不重复的问题
- 缺陷:父级类别的方法不能继承
- 浅拷贝:被没有把原型对象中__proto__指向的原型对象继承过来
- 拷贝继承:把一个对象中的属性或者方法直接复制到另一个对象中
- 遍历prototype对象的属性或者方法
- 继承:类与类之间的关系,面向对象的语言的继承是为了多态服务的
- js不是一门面向对象语言,但是可以模拟面向对象,模拟继承,为了节省内存空间
- 继承:
- 原型作用之一:数据共享 目的是:为了节省内存空间
- 原型作用之二:继承 目的是:为了节省内存空间
- 原型继承:改变原型指向 缺陷:属性值直接被初始化
- 借用构造函数继承:主要解决属性的问题 缺陷:父类中的方法不能被继承
- 组合继承:原型继承(不传值)+借用构造函数继承
既能解决属性问题,又能解决方法的问题- 拷贝继承:就是把对象中需要共享的属性或者方法,直接遍历的方式复制到另一个对象中
调用方式 非严格模式 备注 普通函数调用 window 严格模式下是 undefined 构造函数调用 实例对象 原型中方法中this也是实力对象 对象方法调用 该方法所属的对象 紧挨着的对象 事件绑定方法 绑定事件对象 定时器函数 window
开启严格模式:
"use strict";
function f1() { console.log(this); } f1();//开启严格模式输出的是undefined,除非加window
函数的声明:
function f1(){ console.log("我是函数"); } f1();
函数表达式:
var ff= function () { console.log("我也是一个函数哟"); } ff();
函数声明如果在if-else的语句中,在IE8浏览器中会出现问题问题:IE8中:会预解析,把函数提升,后面的函数把前面同名函数替换了以后宁愿用函数表达式,都不用函数声明
- 函数是对象,对象不一定是函数
- 对象中__proto__原型,是对象
- 函数中有prototype原型,是对象
- 如果一个东西里面有prototype,又有__proto__,说明是函数,也是对象
- 所有的函数实际上都是Function的构造函数创建出来的实例对象
回调函数:函数作为参数使用
Array.forEach(function(ele){
ele就是数组中每个元素
});
作用:改变函数中或方法中的this的指向
apply和call方法中如果没有传入参数,或者是传入的是null,那么调用该方法的函数对象中的this就是默认的window
apply的使用语法:
参数详解:
第一个参数: 要让函数中this指向谁,就写谁
第二个参数: 要去传入一个数组,里面存放被调用函数需要的实参
函数名字.apply(对象,[参数1,参数2,…]);
方法名字.apply(对象,[参数1,参数2,…]);call的使用语法:
参数详解:
第一个参数: 要让函数中this指向谁,就写谁
后面的参数: 被调用函数要传入的实参,以逗号分隔
函数名字.call(对象,参数1,参数2,…);
方法名字.call(对象,参数1,参数2,…);
- 作用:改变this的指向
不同的地方:参数传递的方式是不一样的- 使用场景:只要是想使用别的对象的方法,并且希望这个方法是当前对象的,那么使用apply或者call的方法改变this的指向
所有的函数都是Function的实例对象--------------(因为(函数也是对象)实例对象的__proto__指向的是Function构造函数中的prototype原型)
apply和call方法实际上并不在函数这个实例对象中,而是在Function和prototype中
实例对象调用方法,方法要么在实例对象存在中,要么在原型对象中存在
- bind使用语法:
- 函数名字.bind(对象,参数1,参数2,…)——>返回值是复制之后的这个函数
- 方法名字.bind(对象,参数1,参数2…)——>返回值是复制之后的这个方法
- 作用:bind是复制的意思,参数可以在复制的时候传进去,也可以在复制之后传入进入
- call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,apply和call是调用的时候改变了this指向
bind方法,是复制一份的时候,改变了this的指向
aruguments
实参集合
caller
- 函数的调用者
length
- 形参的个数
name
- 函数的名称
function fn(x, y, z) { console.log(fn.length) // => 形参的个数 console.log(arguments) // 伪数组实参参数集合 console.log(arguments.callee === fn) // 函数本身 console.log(fn.caller) // 函数的调用者 console.log(fn.name) // => 函数的名字 } function f() { fn(10, 20, 30) } f()
- 1、
typeof 变量
返回值:数据类型- 2、
对象 instanceof 数据类型
返回值:true,false- 3、
Object.prototype.toString.call(对象)
获取某个对象的数据类型
- 1、作用域:就是变量的使用范围,js中没有块级作用域,一对括号中定义的变量,这个变量可以在大括号外面使用访问
- 2、作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了
- 3、预解析:就是浏览器在解析代码之前,把声明的函数的声明和函数提升到该作用域的最上面
- 闭包的概念:
- 函数中有另一个函数,或者是一个函数中有另一个对象,里面的函数或者是对象都可以使用外面函数中定义的变量或者数据,此时形成了闭包
- 闭包的模式:函数模式的闭包和对象模式的闭包
- 闭包的优点和缺点:缓存数据
- 总结:如果想要缓存数据,就把这个数据放在外层的函数和里层的函数的中间位置
- 闭包的作用:缓存数据,延长作用域链,同时也是缺点,函数中的变量不能及时的释放
- 局部变量在函数中,函数使用结束后,局部变量就会被自动的释放
闭包后,里面的局部变量的使用作用域链就会被延长案例:
//函数模式的闭包,有缓存数据,只调用了一次外部的数据 function f1() { var num = 10; return function () { num++; return num; } } var ff = f1();//返回的是函数 console.log(ff());//11 console.log(ff());//12 console.log(ff());//13
沙箱:
- 环境,黑盒,在一个虚拟的环境中模拟真实世界,做实验,实验结果和真实世界的结果是一样,但是不会影响真实世界,说白了就是一个自己的环境,不会影响其他环境
在自己的环境中(自己的作用域中),函数和变量的声明会被提升到自己的作用域到最上面
(function () { //在自己的环境中(自己的作用域中),函数和变量的声明会被提升 var str = "小白喜欢小黑"; str = str.substr(2); console.log(str); }()); (function () { var str = "小李喜欢小白"; str = str.substr(2); console.log(str); }());
递归:函数中调用函数自己,此时就是递归,递归一定要有结束的条件
注意事项:在函数中调用自己,一定要有个判断条件不在调用,要不然就是死循环