js的错误分类
语法错误,代码未执行系统就发现错误,出现报错
function() {
}
// Function statements require a function
引用错误,访问一个还未定义的变量会导致这样的错误
var b="ws"
alert(b) // ws
alert(a) // b is not difiend
类型错误,定义的是一个变量,却当作函数调用
var m=234;
m(); //m is not a function
范围错误,范围指定不当
js异常处理
异常不是错误,异常是指可能会出现错误的代码
try{
//可能出错的代码
}catch(e){
// 如果上面代码错误了,就在这里进行错误处理,其中e表示错误对象
// 它里面包含了错误信息,通过查看e,可以知道出现了什么错误
// 代码在此处停止,不会向下执行
}finally{
// 代码作用:无论对错代码都会执行到此处
}
js中的逻辑与(&&)和逻辑或(||)
// 逻辑与(&&),双元运算符 有两个操作数
// 只有两个操作符都为真,整体结果才为真
console.log(true && true); //true
console.log(true && false); //false
console.log(false && true); //false
console.log(false && false); //false
//左结合性,左侧为true时,确定不了整体的结果,遍历到右侧值时,方能确定整体结果
// 左侧为false时,可以直接返回结果为false,代码不再继续执行此行代码
// 逻辑或(||),双元运算符 有两个操作数
// 只要有一个操作数为真,整体的值就为真,两个操作数都为假时,整体结果才为假
console.log(true || true); //true
console.log(true || false); //true
console.log(false || true); //true
console.log(false || false); //true
// || 为左结合性,左侧为true时,直接返回整体结果为true,代码不会继续向下执行
// 左侧为false时,不能直接确定整体的值,需要继续获取第二个操作数,为true时整体结果为true,为false时整体结果为false
// 逻辑非(!),单元(单目)操作符 1个操作符
如果操作符为真,整体为假,如果操作符为假,整体为真
console.log(!true); // false
console.log(!false); // true
//逻辑运算符的操作数数据类型是布尔值,如果不是布尔值,系统会发生隐式类型转换,将其转换为布尔值
// 0,underfind,空格.. 转换为false
// 第一个操作符能决定整体的值,js就会停止对第二个操作数的运算
let a = 10;
let b = 0;
let c = b && a++; //b为false,确定整体值,a++不执行
let d = a++ && b;
console.log(a); // 11
console.log(b); // 0
console.log(c); // 0
console.log(d); // 0
var a = 0;
var b = 2;
var c = a || b++;
console.log(a); // 0
console.log(b); // 3
console.log(c); // 2
var m = 1;
var n = "";
var q = m || n;
console.log(m); // 1
console.log(n); //
console.log(q); // 1
==用与判断是否相等,===判断是否绝等(也会比较类型)
&&和||的优先级
let x = 1 || 2 && 3 || 4 && 0 || 5;
//------------- 3 ----- 0 ------
console.log(x); //1
// &&的优先级大于||的优先级
同步代码与异步代码
同步:代码的书写顺序和代码的执行顺序一样。
异步:代码的书写顺序和代码的执行顺序不一样。
98%代码都是同步代码。
在JS中,异步代码仅仅是个别:
1)事件绑定
2)定时器
3)ajax
....
// 页面上每一个盒子本质都是对象
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
let btns = document.getElementsByTagName("button");
console.log(btns)
// 打印出btr的元素,此为同步代码,书写顺序与代码执行顺序一致
// 异步代码执行顺序与代码书写顺序不一致,需要在特定情况下才会执行,如下代码:只有在浏览器上点击,触发onclick事件代码才会执行。
btns[0].onclick = function() {
console.log(0)
};
btns[1].onclick = function() {
console.log(1);
};
btns[2].onclick = function() {
console.log(2)
};
</script>
this总结
如果this出现在普通的函数中,this表示window,如果通过window打点调用一个函数,这个函数中的this也是window。
事件绑定,事件处理程序,事件发生时浏览器帮助我们调用这个函数,函数中的this事件源
在一个对象中,如果有方法(函数),如果通过这个对象调用方法,方法中的this表示这个对象
在IIFE(立即执行函数)中,this表示window
call / apply /bind 的使用
call / apply /bind 都可以修改this的指向
为什么要修改this的指向,如下代码:
下面两个对象中有两个同样的方法,占用了两个堆空间
var obj1 = {name:"wc", say:function (){alert("我是"+this.name)}}
var obj2 = {name:"zs", say:function (){alert("我是"+this.name)}}
obj1.say();
obj2.say();
//改进方法1
let abc = function (){alert("我是"+this.name)}
var obj1 = {name:"wc",say:abc}
var obj2 = {name:"zs",say:abc}
obj1.say();
obj2.say();
//改进方法2
let abc = function (){alert("我是"+this.name)}
var obj1 = {name:"wc", say:abc}
var obj2 = {name:"zs", say:abc}
abc.call(obj1);
abc.call(obj2)
更精确的检测数据类型
用typeof检测基本数据类型时没有问题,但是检测引用数据类型时,会出现小差错
console.log(typeof 1) // number
console.log(typeof "hello") // string
console.log(typeof true) // boolean
var a;
console.log(typeof a) // undefined
console.log(typeof [1,2,3]) // object
console.log(typeof {a:1}) // object
let d = new Date();
console.log(typeof d) // object
let r = new RegExp()
console.log(typeof r) // object
function f(){}
console.log(typeof f) // function
利用Object.prototype.toString.call可以非常精确地检测一个数据的数据类型
function getType(abc) {
var rs = Object.prototype.toString.call(abc);
rs = rs.substr(8) // substr(数据的截取),substr(number,length),开始位置,截取数据的长度,如果不写的话,后面截取完
var len = rs.length
return rs.substr(0,len-1).toLowerCase() //转小写
}
console.log(getType(123)); //number
console.log(getType([])); // object
console.log(getType({})); //function
console.log(getType(new Date)); //date
console.log(getType(new RegExp)); // regexp
var f = function(){}
console.log(getType(f)); // function
字符串翻转
方法1
var str = "123456"
var newStr = "";
for(var i = str.length-1;i>0;i--){
newStr += str[i];
}
方法2
//reverse数组中翻转属性
ver arr = [1, 2, 3]
alert(arr.reverse()); // [3, 2, 1]
// 字符串翻转,让字符串变成数组
var str = "123";
alert(str.split("")); // ["1", "2", "3"]
alert(str.split("").reverse()); //["3", "2", "1"]
alert(str.split("").reverse().join("")) // 321
// call指向
alert(Array.prototype.reverse.call(str.split("")).join("")); // 321
call / apply /bind 的区别
bind:绑定的意思,改变了this的指向,函数不执行
function F(a, b) {
console.log("F...")
return a+b;
}
var obj = {};
let k = F.bind(obj)
console.log(k(1, 2));;
call: 改变了this的指向,并让函数执行,传递参数一个一个传递
function F(a,b) {
console.log("F..."); // F..
return a+b;
}
var obj = {};
console.log(F.call(obj,1,2)); // 让obj借用函数F 3
apply: 改变了this的指向,并让函数立即执行,传递参数必须为数组
function F(a, b) {
console.log("F..."); // F...
return a+b;
}
var obj = {};
console.log(F.apply(obj, [1, 2])); //让obj借用函数F 3
伪数组
长的像数组 但不是真正的数组
真正的数组:[“a”,“b”,“c”]
伪数组 {0:“a”,1:“b”,2:“c”} 本质是对象
伪数组中有没有数组原型对象上的方法?
答:没有 本质是对象
常见的伪数组:
- 通过document.getElementsByTagName获取的元素集合就是伪数组
- 函数内部的arguments
初识面向对象
常见思想
面向过程:C语言
面向对象:JAVA,C++,JS(基于对象)
面向切面:Spring,IOC,AOP
面向对象特征:
抽象:具体问题抽象化
封装:把属性和方法封装到类中
继承:父对象中的成员,子对象无需重复创建,就可以直接访问。
多态:
对象
对象是属性的无序集合
访问对象中属性的方法, 1)打点调用;2)通过[]来调用
var obj = {
name:"wc"; //前面为属性名(键),后面为属性值(键值)
age:16;
"1+1":2;
}
console.log(obj.name);
console.log(obj.age);
console.log(obj["1+1"]);
//如果键是一个变量,我们需要通过变量去访问 ,必须使用[].
操作对象中的属性之遍历对象
通常使用for-in来遍历对象
var obj = {
name:"wangcai";
age:12;
say:function(){
console.log("say...")
}
}
for(var a in obj){
console.log(a+":"+obj[a]);
}
对象中属性的四大特征
- configurable :表示能否通过delete删除属性,true表示可以删除
- writable :表示能否修改属性的值,true表示能修改
- enumerable :是否能通过for-in循环返回属性,true表示可以
- value :包含这个属性的数据值
通过Object.getOwnPropertyDescriptor获取修改属性的特征
let obj = {
name:"wc"
}
console.log(Obj.getOwnPropertyDescriptor(obj,"name"))
// configurable: false;
// enumerable :true;
// writable :true;
//value :wc
给一个对象添加属性时,也可以设置这四个特征;此方法接受三个参数,属性所在对象,属性名,描述符对象
var obj = {};
Object.defineProperty(obj,"name",{
configurable:false,
writable:false,
enmerable:true,
value:"wangcai"
})
属性的分类
对象上的属性分两类
- 私有属性
- 公有属性
通过hasOwnProperty()可以查看一个属性是否有私有属性
in是一个运算符,用于判断一个属性是否属于某个对象(“c” in obj)
var obj = {
name:"wangc"
age:89;
}
console.log(obj.hasOwnProperty("toString")); // false
//delete只能删除私有属性,不能删除公有属性
//如果一个私有属性和公有属性重名了 会把公有属性盖掉
对象是由函数创造的
在JS中函数有多个角色
- 普通函数
- 类 构造器
- 对象
- 对象中的一个方法
构造器的本质是函数
任何对象中都有一个属性__proto__, 此属性也是一个对象
对象中都有一个属性叫 constructor 是构造器
对象是由函数创建的/对象是由构造器构成的
构造器的本质是函数
原型和原型链
每一个对象上都有一个属性叫__proto__ 为隐式原型
每一个构造器(函数)上都有一个属性叫prototype 它叫原型是一个对象,这个对象我们叫做原型对象
JS中的继承
继承:子类可以去继承父类的公有属性和私有属性
将子类原型对象地址指向父类
特点:可以继承父类的公有属性和私有属性
普通函数继承
//主要代码: Child.prototype = new Parent;
function Parent() {
this = 100;
}
Parent.prototype.getX = function (){ //Parent的公有属性
return this.x;
}
function Chid(){
this.y = 200
}
Chid.prototype = new Parent; //将Chid的原型对象地址更换为Parent子类对象的地址
Chid.prototype.getY = function(){
return this.y // 向Chid的原型对象中加入方法
}
var c1 = new Chid;
console.log(c1.x); //100,继承了父类的x;
console.log(c1.getX());//100,继承了父类的getX方法;
console.log(c1.y); //200,创建对象时this赋值;
console.log(c1.getY);//200,引用父类Chid的getY方法;
call继承
特点:只能继承父类的私有属性
主要代码:Parent.call(this) – 将Parent中的this指针指向子类新建对象的地址
function Parent(){ //创建一个构造器
this.x = 100;
}
Parent.prototype.getX = function(){ //向构造器的公有属性中加入一个方法
return this.x;
}
function Chid(){ //创建一个新的构造器;
Parent.call(this);//让上一个构造器的this指针,指向这个新的构造器的this指针指向的地址
this.y = 200;
}
var c1 = new Chid; //以Chid构造器创建一个对象,
console.log(c1.x); //100, 此对象中有x,y私有属性,一个继承自Parent,一个继承自Chid
组合式继承
// 1)Parent.call(this);继承父类的私有属性
// 2)Chid.protype = Object.create(Parent.prototype);继承父类的公有属性
function Parent(){
this.x = 100;
}
Parent.prototype.getX = function () {
return this.x;
}
function Child() {
Parent.call(this);
this.y = 200;
}
//Child.prototype = Parent.prototype//用此代码也可以继承Parent的公有属性,但是改变了Child.prototype的地址指向了Parent.prototype,向Child添加公有属性时,也会影响到Parent公有属性的内容
Child.prototype = Object.create(Parent.prototype);
var c = new Child();
console.log(c.x);
console.log(c.getX())
ES6中的继承
super(); //类似前面的call继承,继承私有属性
extends //类似于原型对象,继承公有属性
class Parent{
constructor(){
this.x = 100;
}
getX(){
return this.x;
}
}
class Child extends Parent{
constructor(){
super();
this.y = 200;
}
getY(){
return this.y
}
}
var chid = new Child();
console.log(child.x);
console.log(child.get());
创建对象的方法
字面量创建对象
var rect = {
width:10;
height:20;
getS(){
return this.width+this.height;
}
}
//需要一个矩形对象还要手动添加进去;
rect.getC = function(){
return 2*this.width + 2*this.height;
}
console.log(rect.getS());//200
console.log(rect.getC());//60
工厂模式创建对象
function creatRect(w,h){
var obj = {};
obj.width = w;
obj.height = h;
obj.getS = function(){
return this.width*this.height;
}
return obj
}
var rect1 =creatRect(2,4);
console.log(rect1.getS());
var rect2 = creatRect(2,2);
console.log(rect2.getS());
构造器创建对象
构造器+原型创建对象
ES6创建对象
return this.width+this.height;
}
}
//需要一个矩形对象还要手动添加进去;
rect.getC = function(){
return 2this.width + 2this.height;
}
console.log(rect.getS());//200
console.log(rect.getC());//60
**工厂模式创建对象**
```java script
function creatRect(w,h){
var obj = {};
obj.width = w;
obj.height = h;
obj.getS = function(){
return this.width*this.height;
}
return obj
}
var rect1 =creatRect(2,4);
console.log(rect1.getS());
var rect2 = creatRect(2,2);
console.log(rect2.getS());
构造器创建对象
构造器+原型创建对象
ES6创建对象