创建对象
字面量: var obj = {}
实例创建对象:var obj = new Object()
工程模式创建对象:在函数内部创建对象,且return出来。(解构不明确)
好处:外部无需关注工程函数里面具体怎么实现的【隐藏细节】
function createObject = {
var obj = new Object
}
createObject()
构造函数创建对象
<script>
// 构造函数 -> 类
function Play(phone, brank, type, screen) {
// 在构造函数中不要用this,用普通的函数和变量创建就是私有的
let myPhone = phone;
let myBrank = brank;
// 在构造函数中用this点出来的属性和方法都是public的【公开】
this.myType = type;
this.myScreen = screen;
this.fun = function (call, text, photo, Internet, GPS) {
// 一般参数都写在外部函数中
this.myCall = call;
this.myText = text;
this.myPhoto = phone;
this.myInternet = Internet;
this.myGPS = GPS;
console.log("大叫好");
return 123;
fun2(); // 外部无法获取
};
// 私有的方法虽然写在Play里面,但是它是属于window的,本质上与Play无关
function fun2() {
console.log(this);
}
}
//创建Play实例
let Phone = new Play("智能机", "苹果", 1, 4.7); // 有new就相当于改变了this的指向,把他由window改为了Play
Phone.fun("打电话", "发短信", "拍照", "上网", "GPS");
console.log(Phone); // Play {myType: 1, myScreen: 4.7} phone, brank为私有的外部无法调用
console.log(Phone.fun());
</script>
构造函数的原型对象:ProtoType
<script>
// 每个对象都有__prototype__属性
function Student(){}
// 给构造函数挂在一个原型propoType,目的是减少某些函数的调用
Student.propotype.style = function(){}
</script>
<script>
// 每个对象都有__proto__属性
function Person(name) {
this.myName = name;
}
var p = new Person("张三");
console.log(p); // Person {myName: "张三"}
console.log(p.__proto__); // {constructor: ƒ}
var arr = new Array()
console.log(arr.__proto__); // [constructor: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, find: ƒ, …]
</script>
<script>
// prototype原型的好处:
// 给构造函数挂挂载一个原型prototype,目的是减少某些函数的调用
// 只需在原型上创建一次,以后不论创建出来多少个对象,大家都共用
function Student(name) {
this.name = name;
}
//构造函数名.prototype(共享)
Student.prototype.school = function () {
console.log("蜗牛");
console.log(this); // Student {name: "XX"}
this.age = 18;
};
Student.prototype.home = "天涯海角";
//给Student设置一个原型,就是{},{}的原型是Object
Student.prototype.obj = {
school: function () {},
home: function () {},
};
var name1 = new Student("小王");
var name2 = new Student("老王");
// name1.school();
console.log(name1);
console.log(name2);
// 调用prototype【调取的时候不需要__proto__】
name2.school(); // 蜗牛
// 修改prototype【想要修改时才需要通过__proto__】
name1.__proto__.home = "中华大饭店"; // 虽然是在name1上修改,但是因为proto为公用的,所以大家都变
Student.prototype.home = "超级大酒店";
console.log(name1.__proto === Student.prototype); // true 两个方法效果相同
// 对象的默认原型Object,Object是根
console.log({ name: "张三" });
// 创建一个没有原型的对象
let obj = Object.create(null);
console.log(obj);
// 创建一个带有原型【run: function () {}】的对象
let obj2 = Object.create({ run: function () {} });
console.log(obj2);
</script>
原型模型的优先级(就近原则)
当构造函数内部的成员与原型上的内容重名了,寻找规则:就近原则
hasOwnProperty
hasOwnProperty()方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
<script>
let obj = {
name: "张三",
age: 18,
};
for (let i in obj) {
console.log(i, obj[i], obj.hasOwnProperty(i)); // 检查i对应的属性是否是在obj构造函数中定义的
}
let liList = document.querySelectorAll("li");
for (let i in liList) {
console.log(i, liList.hasOwnProperty(i));
}
</script>
constructor(构造函数)
constructor:构造函数
对象.constructor【对象所在的类(构造函数)】
p1.constructor【对象所在的类(构造函数)】
构造函数.prototype.constructor
p1.prototype.constructor
<script>
function Person(){}
// Person.prototype.name="jack"
Person.prototype = {
constructor:Person,
name:"Nicholas",
age:29,
job:"Software Engineer",
sayName:function(){}
}
var p1 = new Person();
var p2 = new Person();
console.log(p1)
console.log(p1.constructor);//对象.constructor 【对象所在的类(构造函数)】
console.log(Person.prototype.constructor);//构造函数名.prototype.constructor 【构造函数】
</script>
原型链继承
原型与原型之间多层次之间的继承形成的链条称之为原型链。
子元素.prototype = new 父元素
<script>
function father(name){
this.myName=name;
}
function son(age){
this.myAge=age;
}
son.prototype = new father('张三');
let gogo = new son(13);
console.log(gogo)
//输出
// son {myAge: 13}
// myAge: 13
// [[Prototype]]: father
// myName: "张三"
// [[Prototype]]: Object
</script>
对象冒充继承
好处:
- 提取了多个类的共性做成一个父类,把共性的属性和方法都放父类里面
- 子类里面只设计属于自己的属性
单继承
<script>
function father(name){
this.myName=name;
}
function son(name,age){
father.call(this,name); // 创建子类之前,先调用父类,将父类里的this改成son,给son添加年龄属性
this.myAge = age;
}
let gogo = new son('张三',13);
console.log(gogo); // son {myName: '张三', myAge: 13}
</script>
混合继承
原型链继承:无法传参
对象冒充继承:没有原型链
extends:扩展 super:超级
混合继承
- 对象冒充:构造函数的动态参数
- 原型链:把父元素的方法放到原型中
<script>
// 手机(父类)
class Phone {
constructor(pName, pMoney) {
this.name = pName;
this.money = pMoney;
}
}
class SmartPhone extends Phone {
constructor(pName, pMoney, pColor) {
// 调用父级的构造函数并传参
// 用super.xxx可以获取父类的成员
super(pName, pMoney);
this.color = pColor;
}
}
let p = new SmartPhone("苹果", "8888", "red");
console.log(p);
</script>
ES6中的类
- set必须有形参
- get必须没有形参
<script>
calss Father{
constructor(name){
this.Myname = name
}
work(){
console.log('工作~~')
}
set name(name){}
get name(){
this Myname = name;
}
}
</script>
ES6面向对象
super:用于访问和调用一个对象的父对象上的函数。
super.prop
和super[expr]
表达式在类和对象字面量任何方法定义中都是有效的。
super必须放到第一行
<script>
class Father {
constructor(name) {
this.Myname = name;
}
work() {
console.log("工作~~");
}
set name(name) {
// set必须有形参
}
get name() {
// get不可以有形参
console.log("♪(^∇^*)~~");
}
}
// 子类
class Son extends Father {
constructor(name, age) {
super(name);
this.myAge = age;
}
work() {
super.work(); // 解决同名情况下,子元素覆盖父元素的问题
console.log("不想工作~~");
}
}
var son = new Son("张三", 20);
son.work(); // 输出不想工作~~ , 父元素的work被覆盖
</script>
static
<script>
class People {
constructor(name) {
this.Myname = name;
}
static rolr = "kid";
static getMyName() {
return this.name; // name是自带的,表示类名
}
}
let people = new People("张三");
console.log(people);
console.log(People.name);
//1.被static修饰的成员,通过类名调用的,不是对象调用
People.getMyName();
//2.被static修饰的成员归属于类的,不归属于对象
//3.被static修饰的成员是该类创建时也一起创建的
//平时用过的静态成员(大多是工具函数)
console.log(Date.now());
console.log(Math.PI);
</script>
面试题
ES5 定义私有属性 (有问题,还需修改)
<script>
class Animal {
constructor(a,b){
this.A = a;
let B = b;
}
}
let letter = new Animal(123,456)
console.log(letter.A)
console.log(letter.B)
</script>
ES6 定义私有属性(由于IE兼容问题,大多数情况下依然使用ES5的写法)
<script>
class Animal {
// 私有成员:在名称前加#,访问范围仅限于class大括号以内
// 私有属性必须在constructor之前定义
// 普通属性不用预先定义
a;
#b;
constructor(a, b) {
this.a = a;
this.#b = b;
}
run() {
console.log(this.#b);
}
#stop() {
console.log("私有函数");
}
}
var x = new Animal(123, 456);
console.log(x.a); // 123
x.run(); // 456
// console.log(x.#b);
// console.log(x.#stop());
// 报错:Private field '#b' must be declared in an enclosing class(私有字段'#b'必须在封闭类中声明)
</script>
异常
- 语法错误
- 逻辑错误
- 难以预料(try(试试)-catch(buhuo(捕获))
用了try-catch后即使报错也不会影响后续代码的运行
<script>
try{
// 试一试
}
catch(error){
// 如果出错执行此行代码
// error 出错信息
}
// 主动报错
function play(){
throw '主动报错'
}
</script>
练习
<script>
try {
// 不适用于语法错误
alertn(123);
} catch (error) {
console.log(error);
}
console.log("大家好");
</script>