<script>
// 七:对象
// 一、对象
var obj = {} // 字面量创建
var obj1 = new Object() // 构造函数创建
//二、构造函数
Car.prototype.run = function() {
this.height --
console.log('height', this.height);
}
// Car.prototype = {
// constructor: Car,
// run: function() {},
// start: function() {}
// }
function Car() {
this.name = 'BMW'
this.color = 'red'
this.height = 100
// this.run = function() {
// this.height --
// console.log('height', this.height);
// }
}
const car1 = new Car()
console.log('__proto__', car1.__proto__);
console.log('prototype', Car.prototype);
car1.run()
const car2 = new Car()
car2.run()
/*
实例原型 prototype
实例对象 __proto__
一、内存浪费?
如果调用两次new就会单独开辟两个空间来存放this.run ,如果创建100个呢,那么就容易内存浪费。
this.run = function() {
this.height --
console.log('height', this.height);
}
二、如何解决?
一般情况下,我们公共的属性定义到构造函数中,公共方法放在原型对象上(prototype)
Car.prototype.run = function() {
this.height --
console.log('height', this.height);
}
三、每个实例对象都有一个 __proto__ 、指向构造函数的 prototype 原型对象,实例对象中的
car1.__proto__ === Car.prototype
四、如果有多个原型对象,改为对象形式,那么constructor就会丢失,这时候就需要我们修改constructor
Car.prototype = {
constructor: Car,
run: function() {},
start: function() {}
}
const car1 = new Car()
console.log(car1.__proto__); // constructor丢失
console.log(Car.prototype); // constructor丢失
*/
// 三、原型链
let that = null
Person.prototype.run = function() {
that = this
}
Object.prototype.age = 15
// Person.prototype.age = 14
function Person() {}
const person1 = new Person()
// person1.age = 13
person1.run()
console.log('age', person1.age);
console.log('this指向实例对象', person1 === that);
/*
原型链: 访问age,实例对象上没有,向Person.prototype中查找,还没有,向Object.prototype中查找,如果都没有就没有
*/
// 原型链 ,最后直到访问 null,就是最顶级的。Person.prototype指向Person原型对象,在向上访问到__proto__指向Object原型对象,在向上访问为null
console.log('person.proto指向Person原型对象', person1.__proto__);
console.log('Person.prototype指向Person原型对象', Person.prototype);
console.log('Person.prototype.__proto__指向Object原型对象', Person.prototype.__proto__);
console.log('Object原型对象.__proto__指向 null 万物皆是空 null', Person.prototype.__proto__.__proto__);
// 四、es5中使用实例对象继承、es6中使用class 类继承, 如何实现?
// 1、如何让孩子继承父亲的属性
// 2、如何让孩子继承父亲的方法,(存在问题?) 自己来一遍吧
Father.prototype.run = function() { console.log('都需要运动')}
function Father(name, age) {
this.name = name
this.age = age
}
const father = new Father()
function Son(name, age) {
//1、 继承属性
Father.call(this, name, age)
this.study = '学习'
}
/*
// 2、继承方法 存在的问题,给孩子添加方法时,父级也会添加,不可取
Son.prototype = Father.prototype
Son.prototype.start = function() { console.log('开始运动')}
*/
Son.prototype = father // 相当于 son.prototype = {},重新修改了原型对象,需要执行constructor
Son.prototype.constructor = Son
const son = new Son('孩子', 10)
console.log('实例对象', son);
console.log('原型对象', Son.prototype);
son.run()
console.log(Father.prototype);
console.log(Son.prototype.constructor);
</script>
/*
// 第一种, 直接改变原型中的属性,原来的属性值也会受到影响
Person.prototype.name = '小一'
function Person() {
}
Son.prototype = Person.prototype
function Son() {}
Person.prototype.name = '小二'
const son = new Son()
console.log('son.name: ', son.name); // 观察Person.prototype 赋值之后打印的name
Person.prototype.name = '小三'
*/
/*
// 第二种 引用赋值,直接将Person.prototype 赋值给 Son.prototype,会开辟新的空间,不会影响原来的值
Person.prototype.name = '小一' //let obj = { name: 'a'}
function Person() {
// this = {
// __proto__ : Person.prototype // 隐士调用
// }
}
Son.prototype = Person.prototype // let obj1 = obj
function Son() {}
Person.prototype = { // obj = {name: 'b'}
name: '小二'
}
const son = new Son()
console.log('son.name: ', son.name); // 会影响原来 Son。prototype 指向的name 吗?
let obj = { name: 'a'}
let obj1 = obj
obj = {name: 'b'}
console.log(obj1.name);
*/
/*
一、...args剩余参数(展开运算符) 返回一个数组,可以使用数组原型中的方法
允许一个表达式在某处展开。展开运算法 在 多个参数(函数调用)、多个元素(用于数组和字面量)和多个变量(用于解构赋值) 地方使用。剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
如果函数的最后一个命名参数以 ... 为前缀,则它会将所有后面剩余的是实参个数包裹成一个数组。
// 例子
function test(a, b, ...args) {
console.log(args)
}
test(1,2,3,4) // [3, 4]
二、arguments对象 返回一个 类数组对象,不具有数据的方法
在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们。arguments对象并不是一个数组,是一个类数组对象,在调用时请注意。
arguments 中包含了函数传递的参数、length、和 callee 属性。
length 属性表示的是实参的长度,即调用函数的时候传入的参数个数。
callee 属性则指向的函数自身,我们可以通过它来调用自身函数。
arguments 是一个经典的类数组对象,我们可以通过Function.call 或者 Function.apply 方法来间接调用数组的方法,也可以直接通过 Array.prototype.slice 或 Array.prototype.splice 等方法把类数组对象转换成真正的数组。
*/
/*
// new实现过程
function myNew(_constructor, ...args) {
debugger
// 1. 创建一个空对象
const obj = {};
// 2. 将obj的_proto_属性指向构造函数的原型对象
obj.__proto__ = _constructor.prototype;
// 3.将_constructor执行的上下文this绑定到obj上,并执行
const result = _constructor.apply(obj, args);
//4. 如果构造函数返回的是对象,则使用构造函数执行的结果。否则,返回新创建的对象
return result instanceof Object ? result : obj; // 如果使用自己函数的对象,那么原型中的函数将无法使用
}
function Person(name, age){
this.name = name;
this.age = age;
return { name: 123}
}
Person.prototype.sayHello = function(){
console.log("hello" + this.name)
}
const person1 = myNew(Person, 'Tom', 20)
const person2 = new Person('Tom', 20)
console.log(person1) //Person {name: "Tom", age: 20}
console.log(person2) //Person {name: "Tom", age: 20}
// person1.sayHello() //helloTom
// person2.sayHello() //helloTom
function myNew1(_construtor, ...args) {
}
*/
// 注意
Object.create() //在括号里面只能放 null 或者 Object,其余会报错
7种继承的方式
参考链接:https://blog.csdn.net/wuliyouMaozhi/article/details/125905733