一、hasOwnProperty
(1)、遍历
-
for in 遍历对象和数组,返回的是下标索引和属性名
-
for of遍历对象,返回的是值,不能直接遍历对象
<script>
var obj = {
name: 'jack',
age: 33
}
//遍历对象
//for in 返回的是对象的属性名
//for of 不能直接遍历对象
for (i in obj) {
console.log(i);
}
// for (i of obj) {
// console.log(i);
// }
var arr = ['a', 'b', 'c', 'd'];
//遍历数组
//for in :返回的是索引下标
//for of : 返回的是值
for (var i in arr) {
console.log(i);
}
for (var i of arr) {
console.log(i);
}
</script>
(2)、hasOwnProperty
如何判断属性是在构造函数里的实例里,还是在原型里
语法:对象名.hasOwnProperty('属性名')
实例返回true,否则返回属性
-
如果返回true,则表示这个属性是构造函数里面定义的
-
如果返回false,则表示这个属性是原型里面的,或者未被定义
<script>
var obj = {
name: '东东',
age: 17
}
for (var i in obj) {
console.log(i, obj[i], obj.hasOwnProperty(i));
}
var person = function(name, age) {
this.name = name;
this.age = age
}
person.prototype.sex = '女'
var p = new person('东东', 16)
console.log(p.hasOwnProperty('name')); //true表示name是构造函数里面定义的
console.log(p.hasOwnProperty('age')); //true表示age是Person构造函数里定义的
console.log(p.hasOwnProperty('sex')); //false表示sex是原型上面定义的
console.log(p.hasOwnProperty('hight')) //false表示未定义的
</script>
二、constructor
在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性(是一个指针)指向prototype属性所在的函数
-
constructor返回构造函数,如果不是构造函数返回object
person.prototype.constructor===person //返回true
(1)、prototype与constructor的关系
(2)、返回构造函数
-
通过字面量创建的对象,返回Object
<script>
function boy(name) {
this.name = name;
}
var b = new boy('东东')
console.log(b);//返回对象实例
console.log(b.constructor);//返回构造函数
console.log(boy.prototype.constructor)//返回构造函数
</script>
<script>
var obj = {
name: '东东',
age: 18
}
console.log(obj);
function p(name) {
this.name = name;
}
var a = new p('小网')
console.log(a);
</script>
三、原型链继承
(1)、含义:
-
原型和原型之间进行继承,形成一个链条,称为原型链
(2)、语法:
-
子元素.prototype=父元素实例
Student.prototype = new Person();
SmallStudent.prototype = new Student();
<!-- 原型链继承 -->
<script>
//类:人、学生、小学生、一年级学生、一年级一班学生
//人
function person() {
this.name = '人'
}
//学生
function student(school) {
this.school = school
}
//小学生
function smallstudent(name, age, school) {
this.age = age;
}
//原型与原型之间进行继承,形成一个链条,称为原型链
student.prototype = new person();
smallstudent.prototype = new student('向阳小学')
var s = new smallstudent('小明', 12, '花园小学')
console.log(s);
console.log(s.name); //人
console.log(s.school); //向阳小学
// 给原型上添加constructor属性,形成双向链条
student.prototype.constructor = student;
smallstudent.prototype.constructor = smallstudent;
</script>
四、对象冒充继承
(1)、对象冒充的使用
-
通过改变this指向来调用另外一个对象和自身对象相同的属性和方法,当然值是不一样的,传递的参数还是自身对象去传递
-
语法:写在本构造函数里面,
-
引用的构造函数名.call(this,参数1,参数2……)
-
call动态修改this指向,将引用的类改为本对象指向的类,后面跟的是属性值的形参
-
-
对象冒充继承的对象不能继承它父类原型中的属性和方法
(2)、对象冒充的原理
-
调用父类函数时改变this指向,定义子类的属性和方法
-
在子类中:父类型.call(this,参数1,参数2,……);
-
可以解决传参的问题,但是不能继承父类原型中的属性和方法
<!-- 对象冒充继承 -->
<script>
function person(name) {
this.name = name;
}
function student(name, school) {
//将person的this指向动态改变为student
person.call(this, name)
this.school = school;
}
function smallstudent(name, age, school) {
//为什么要这么设计?
//创建子类之前,先调用父类,将父类里面的this改为smallstudent,给smallstudent添加学校
student.call(this, name, school);
this.age = age;
}
//好处;提取多个类的共性做成一个父类,把共性的属性和方法都放父类里面
//子类里面只设置属于自己的属性
function highstudent(name, height, school) {
student.call(this, name, school)
this.height = height;
}
var s = new smallstudent('小明', 2, '蜗牛')
var h = new highstudent('大名', 11, '阳光小学')
console.log(s);
console.log(h);
</script>
五、混合继承
原型链继承+对象冒充继承
原型链继承:把父类的方法放进原型中
对象冒充继承:构造函数的动态参数
<script>
//混合继承
// 对象冒充:构造函数的动态参数
// 原型链:把父类的方法放进原型中
function person(name, age) {
this.name = name;
this.age = age;
this.eat = function() {
console.log('吃饭');
}
}
function student(name, age, grade) {
//对象冒充继承
person.call(this, name, age)
this.grade = grade
}
//原型继承
student.prototype = new person();
student.prototype.constructor = student;
var s = new student('班长', 223, '3班')
console.log(s);
s.eat();
</script>
六、ES6中的类
-
/get和set访问器中,访问属性时要加下划线,防止出现无限递归问题
-
get和set一个是取值,一个是存值/设置值,设置传参过去的值显示的样式
-
new Animal("x",2).name;//当获取name值的时候,实际上是调用了 get name()
-
new Animal("x",2).name="j"//当给name赋值的时候,实际上调用了set name()
(一)
<script>
//创建类
class Anima {
//通过new运算符在创建对象时才会调用的构造函数
constructor(name, age) {
this.name = name;
this.age = age;
};
//原型里面的方法
hunter() {
console.log('捕猎');
}
}
var a = new Anima('老虎', 12)
console.log(a); //l老虎
console.log(a.name); //捕猎
a.hunter()
</script>
(二)、动物类案例
class Animal{
//通过new运算符在创建对象时才会调用的构造函数
constructor(name,age){
this.name=name;
this.age=age;
}
hunter(){
console.log(捕猎);
}
//get和set访问器中,访问属性时要加下划线,防止出现无限递归问题
//得到值,取值
get name(){
return this._name;
}
//设置值,存值
set name(value){
this._name=value;
}
}
new Animal("x",2).name;//当获取name值的时候,实际上是调用了 get name()
new Animal("x",2).name="j"//当给name赋值的时候,实际上调用了set name()
<script>
class Animal {
//通过new运算符在创建对象时才会调用的构造函数
constructor(name, age) {
this.name = name;
this.age = age;
}
hunter() {
console.log(捕猎);
}
}
// get和set一个是取值,一个是存值,设置传参过去的值显示的样式
var a = new Animal("x", 2);
console.log(a) //Animal {_name: "x", age: 2}
a.name; //相当于get,获取值
a.name = '东东'; //相当于set, 存储值
console.log(a); //Animal {_name: "东东", age: 2}
a.gender = '男';
console.log(a); //Animal {_name: "东东", age: 2, gender: "男"}
</script>
语法糖
<script>
//语法糖
class Phone {
constructor(brand, price, contact) {
this.brand = brand;
this.price = price;
this._contact = contact;
}
//属性访问器:set、get
set contact(newContact) {
console.log("set contact", newContact)
if (newContact.length > 0) {
this._contact = newContact;
}
}
get contact() {
this._contact = this._contact.map(item => {
//substr(从哪里开始截2取,截取几个) substring(从哪开始截取,截取的结束位置-1)
return "**" + item.tel.substring(2)
})
return this._contact;
}
}
//创建一个实例对象
var p = new Phone("MI", 2999, [{
name: "小明",
tel: "12312"
}, {
name: "小红",
tel: "678"
}]);
p.contact = [];
console.log(p.contact);
p.contact = [{
name: "小王",
tel: "998282"
}, {
name: "小绿",
tel: "736338"
}];
console.log(p.contact);
</script>
案例:
<script>
class person {
constructor(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
// 设置年龄
set age(value) {
if (value > 18) {
this._age = value
} else {
// console('年龄不能小于18')
this._age = '年龄不能小于18'
}
};
//得到获取年龄
get age() {
return this._age
}
//设置姓别
set sex(gender) {
if (gender == '男' || gender == '女') {
this._sex = gender
} else {
this._sex = '只能是男和女'
}
};
//获取值
get sex() {
return this._sex
}
}
var p = new person('东东', 1, '2')
var d = new person('小黄', 44, '男')
console.log(d);
console.log(p);
</script>
ES6类的继承
-
继承:类 extend 被继承的类
-
调用父类构造函数:super(被继承的行参)
<!-- <script>
//手机(父类)
class Phone {
constructor(brand, price, contact) {
this.brand = brand;
this.price = price;
this.contact = contact;
}
}
//智能手机(子类)
class SmartPhone extends Phone {
constructor(brand, price, contact, OS) {
//调用父类构造函数
super(brand, price, contact)
this.OS = OS;
}
}
var p = new SmartPhone("MI", 2999, [{
name: "小明",
tel: "12312"
}, {
name: "小红",
tel: "678"
}], 'Android');
console.log(p);
</script> -->
super:调用继承
ES6中的继承,用extends定义,用super调用,需要放在最前面
<script>
class person {
constructor(name, age) {
this.name = name;
this.age = age;
}
//在外面写的是属于原型里面的方法和属性
work() {
console.log('原型里的方法');
}
}
class student extends person {
constructor(name, age, major) {
//调用父类的构造函数,并传参数
super(name, age)
this.major = major;
}
// 子类重写(覆盖)了父类函数:父类函数内容太广泛,笼统,不具体,不能完成体现子类的特点
work() {
//用super.xxx可以获取父类的成员
super.work();
console.log('学生的工作就是学习');
}
}
var s = new student('东东', 11, 'Web前端开发')
console.log(s);
s.work(); //原型里的方法,学生的工作就是学习
</script>
ES6中的静态方法
-
被stastic修饰的成员,不属于对象
-
静态成员,属于类,通过类名调用,不再是对象调用
-
被stastic修饰的成员属于类的,不在归属对象
-
被stastic修饰的成员是该类创建的时候一起创建的
-
平时用过的静态成员,大多数是工具函数
<!-- ES6中的静态方法 -->
<!-- <script>
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
class Student extends Person {
constructor(name, age, major) {
super(name, age);
this.major = major;
}
static role = 'kid'
static getMyName() {
console.log('getmyname:' + this.name); //返回当前类名
}
}
var s = new Student('东东', 11, 'Web前端')
console.log(s);
//1、被static修饰的成员,不属于对象
//2、静态成员,属于类,通过类名调用,不再是对象调用
console.log(Student.role);
Student.getMyName() //得到的是Student类名
//3、被static修饰的成员属于类的,不再归属对象
//4、被static修饰的成员是该类创建的时候一起创建的
//5、平时用过的静态成员,大多数是工具函数
console.log(Date.now());
console.log(Math.PI);
</script> -->
ES6私有属性
-
私有成员:在名称前面加#,访问范围仅限于class大括号以内
-
私有属性,必须先在constructor之前定义一下,普通属性不用先定义
<script>
class Animal {
a;
#b;
constructor(a, b) {
this.a = a;
this.#b = b;
}
run() {
console.log("this.#b : " + this.#b)
}
#stop() {
console.log("stop")
}
}
var x = new Animal("123", "456")
console.log(x.a)
x.run();
</script>
七、代码错误
-
语法错误:字母单词拼错等
-
逻辑错误:通过调试找到错误,并解决
-
难以预料的错误,即不确定错不错的代码:通过try(试试)——catch(捕获)来解决
-
普通情况下,有一行代码报错,它后面的代码就都执行不了了
-
try-catch解决了这个问题,用了try-catch之后,即使报错也不会影响后续的代码
-
//try-catch语法 try{ //代码块(不确定对不对的代码) //如果在这个大括号里面有错误代码,它前面的代码是好的,好的代码会执行,错的代码后面的代码就都不执行了,直接跳过去执行catch里面的代码以及后面的代码 }catch(error){ //如果上面的代码块有错误的话就会执行,如果没有错误的话就不执行 }
-
-
主动抛出异常(主动报错)
一
<!-- <script>
var a = '你好吗?';
console.log(a);
//如果try里面的代码是正确的,就会直接输出,而catch里面的代码不执行
//如果try里面的代码是错误的,就不会输出它,就会去输出catch里面的代码
try {
console.log(a); //正常输出
console.lo('你好');
console.log(a); //不会输出
} catch (error) {
console.log('错误原因:' + error);
}
console.log(a);
</script> -->
二
<!-- <script>
//1、语法错误
//was s=123;
//2、逻辑错误:调试找到错误
//3、难以预料的错误:try(试试)——catch(获取,捕获)
try {
//1、将有可能报错的代码放在try里面
//2、如果try里面的代码是正确的,则正常运行
//3、如果里面的代码是错的,则执行catch里面的执行,里面正确的还是会执行
console.log('试试');
} catch (error) {
//4、如果出错了,才会进入catch里面,执行这里的代码
console.log(error);
}
//5、用了try-catch之后,即使报错也不会影响后续的代码执行
console.log('执行完毕');
</script> -->
<!-- <script>
//主动抛出异常(主动报错)
/* function play() {
throw '当前函数不可用'
}
try {
play()
} catch (error) {
console.log('nihao1');
} */
/* function play() {
throw '当前函数不可用'
}
play() */
</script> -->