异常处理:
针对js运行过程中 可能出现的一些不正常情况做一个预处理
举个栗子:
刘轩准备骑行去爬山
1.骑行到一半 发现车胎没气了 (应该是出发前就做好预处理的)
2.骑在路上很开心 看到路边有小石子 非得过去压一下 嘭... (自我脑残行为)
3.骑行到半山腰 遇到山体滑坡 只能原路返回(无法做处理 不可抗力因素
程序对应这三种情况:
1. 代码运行前(编写代码过程中) 对于可能出现的情况做一个预处理
2. 代码运行过程中可能出现的 空值 undefined 做一个处理
3.程序运行遇到 不能处理的情况(比如 内存不足 内存泄露)
只能改代码
js中的异常处理有两种手段:
1.throw 异常对象; 抛出异常
2.try... catch 代码块 处理异常
所谓抛出异常就像:
感冒了 自己不会治病 把病抛给医生
将问题抛给下一个调用者 出现问题 直接报错终止
所有try...catch 代码块 就是针对异常的捕获和处理
try... catch
try{
尝试执行的代码
}catch(e){ //捕获到的异常对象
针对出现的异常做处理
}
后续代码继续执行
执行步骤:
1.先尝试着从try代码块里面第一行往后执行
2.如果代码块都执行完 程序没有报错 那么久跳过catch代码 直接执行后面顺序代码
3.如果try里面报错了 立马终止try的代码执行
4.立即跳入catch代码块执行
5.catch执行完后 继续执行后续代码
catch里面的代码到底该如何处理错误 不同错误做不同处理
例如: 对象undefined了 那么catch里面尝试 赋其他值
数字出现了0 赋其他值
对象创建失败 尝试其他创建对象方式
注意:
try catch代码块 平时实际开发用不到 但是封装必须用!!!!!!!!!!!!!!!!!
try catch无法捕获 代码语法错误!!!!
try{
var str;
console.log(str.length);
}catch(e){
// console.error("我假装处理错误了!");
// console.error(e);
// console.log(e);
// 做针对性处理了
str="错误以后赋的新值";
console.log("重新打印字符串的长度:"+str.length);
}
alert("后面十万行功能代码!");
try catch中的finally 语句
在try或者catch代码块中 如果存在返回值 那么try catch之后代码很有可能执行不到
如果有必须执行的代码 那么就要小心了 一定要加finally语句
try{
尝试执行的代码
}catch(){
报错执行我
}finally{
无论如何都会执行的代码
}
finally代码块什么时候必须使用:
如果方法有返回值 并且在tyr或者catch或者两者里面 有return时 finally必须写
function show() {
try {
var str;
console.log(str.length);
console.log("如果try没问题执行我!")
return true;
}catch(e){
console.log("出现错误了,我来处理了");
return false;
}finally{
console.log("我是后续的功能代码 必须执行!!!");
}
}
show();
throw 抛出错误
常用在 出现错误 后续代码不能继续执行
var str;
if(str==undefined){
throw new Error("你的str都没赋值,你玩啥呢?"); //手动抛出错误! 程序报错终止
}
alert("后面其他代码");
throw如果是放到方法中 那么存在异常传递机制
throw是抛出给下一个调用者 一旦报错 连锁反应 全都报错
function show1() {
var str;
if(str==undefined){
throw new Error("你的str都没赋值,你玩啥呢?"); //手动抛出错误! 程序报错终止
}
}
function show2() {
show1();
}
function show3() {
show2()
}
show3();
面向对象有三大特征:
封装性 继承性 多态性
js是基于对象的编程语言
系统内置号很多对象供我们使用
无法创建自定义类型的对象
面向对象是可以创建自定义类型的 编程思想
原型
传统构造函数存在的弊端:
* 每new出来一个对象都会多存储一份函数
* 但是每个函数却是一模一样的
* 没必要存储那么多份
*
* 把函数写成有名字的函数也不行 会造成大量的全局污染
* 所以我们要用原型去解决:
*
*
* 什么是原型:
* 每创建出来一个构造函数 系统就会自动分配(自动关联上)一个神秘而且强大的对象
*
* 这个对象就是原型
*
* 原型本身是一个对象,既然是对象 那么就能绑定属性跟方法
*
* 原型上面绑定的属性跟方法 是当前原型关联的那个构造函数new出来的所有对象共有
* 都可以使用
*
* 原型对象默认是空的(除了constructor属性)
*
*
* 原型的访问:
* 构造函数.prototype
function Person(name,age) {
this.name=name;
this.age=age;
/* this.show=function () {
console.log("构造函数里面的show");
}*/
}
/*function Person(name,age,country) {
this.name=name;
this.age=age;
this.country=country;
}*/
// 返回原型对象
console.log(Person.prototype);
Person.prototype.show=function () {
console.log("原型里面的show");
}
Person.prototype.sayHi=function () {
console.log("原型里面的你好");
}
Person.prototype.country="原型的中国";
var per1=new Person("小砌墙",16);
var per2=new Person("小白",26);
调用原型里面的方法
per1.show();
per1.sayHi();
per2.show();
per2.sayHi();
调用原型里面的属性
一般不推荐在原型里面绑定属性
原因是 属性就是一个值 很少有所有对象共用同一个值的情况
所以不推荐把属性绑定给原型
对象的属性跟方法的查找顺序:
当一个对象调用属性或者方法时,首先会在当前对象的构造函数里面去找
如果有就直接使用 如果没有则继续去原型里面找
如果是对象本身特有的属性 千万不要绑定到原型里面
function Person() {
}
Person.prototype.name = '张三';
var p1 = new Person();
var p2 = new Person();
p1.name = '李四';//给当前对象本身绑定name属性
console.log( p1.name );//访问当前对象本身的name属性
console.log( p2.name );//自己当前没有name属性 所以去原型里面访问的原型的name属性
原型替换
function Person(name) {
this.name=name;
}
// console.log(Person.prototype);
Person.prototype.show=function () {
console.log("原型里面的show");
}
//原型替换
Person.prototype={
sayHi:function () {
console.log("新原型对象的你好方法");
}
}
var per=new Person("小强");
// per.show(); //报错 原因是 原型对象呗替换 原来原型里面所有的属性跟方法都将无法调用
per.sayHi();
原型替换带来的问题:
一旦原型对象替换成新对象
那么原型.contructor(构造函数属性) 就变成了新对象对应的构造函数
原型对象内部发生了切换
要想保证完整性 就需要再把 constructor切换回来
// 要想保证完整性 就需要再把 constructor切换回来
Person.prototype.constructor=Person;
* 在原型对象替换之前创建的对象
* 无法使用新原型对象里面的属性跟方法
function Person(name) {
this.name=name;
}
// console.log(Person.prototype);
Person.prototype.show=function () {
console.log("原来原型的show");
}
var per=new Person("小强");
// per.show();
Person.prototype={
newShow:function () {
console.log("新原型对象的show");
}
}
var newper=new Person("小白");
// newper.newShow();
/*
* 在原型对象替换之前创建的对象
* 无法使用新原型对象里面的属性跟方法
*
*
* */
// per.newShow();
newper.newShow();
Person.prototype.haha=function () {
console.log("特背开心");
}
newper.haha();
原型的访问方式有两种:
1.构造函数.prototype(ECMAScript推荐使用的)
2.对象.__proto__(非标准)
为什么不推荐使用对象直接访问原型呢?
如果是偷懒行为 访问一下原型获取数据还好
但是如果通过对象访问原型 并且把原型里面的一些属性跟方法更改了
那么程序非常不方便维护 会导致程序混乱
function Person(name) {
this.name=name;
}
// console.log(Person.prototype);
var per=new Person("小强");
// console.log(per);
// console.log(per.__proto__);
console.log(per.__proto__===Person.prototype);//true