一、new关键字的底层原理
1、new关键字的作用
- 实例化一个对象返回一个新对象
- 让构造函数中的this指向实例化对象
2、new关键字的底层原型
- var p1 = {} 创建了新对象,开辟内存空间
Person.call(p1)
通过call方法改变函数Person中的this指向,指向实例兑现p1p1.__proto__==Person.prototype
p1的指针指向构造函数原型,地址相同,属性和方法都能继承
二、原型的指向是否可以改变
function Animal() { }
Animal.prototype.name = "小狗"
function Dog() { }
Dog.prototype.color = "金毛"
Dog.prototype = new Animal()
console.log(Animal.prototype.constructor == Animal)//true
console.log(Dog.prototype.constructor == Dog);//false
console.log(Dog.prototype.constructor == Animal);//true
三、3种继承
- 原型继承、构造方法继承(call方法继承)、拷贝继承
1、原型继承
- 目的:让学生对象(子类)继承人对象(父类)的属性和方法,相当于继承人的构造函数和原型中的属性和方法
//1、人的构造函数
function Person(name){
this.name = name
this.work = function () {
console.log(this.name + "热爱工作")
}
}
//2、人的原型
Person.prototype.age = 26
Person.prototype.playCode = function (){
console.log(this.name + "喜欢敲代码")
}
//3、学生的构造函数
function Student(sex) {
this.sex = sex
this.eat = function () {
console.log(this.name + "喜欢吃零食")
}
}
//----------------必须要写在子类的原型的上面-----------------
Student.prototype = new Person("小明")
//4、学生的原型
Student.prototype.className = "web前端"
Student.prototype.learn = function () {
console.log(this.name + "喜欢学习")
}
//
console.log(Student.prototype.constructor == Preson)//true
var stu = new Student("男生")
//1、学生构造函数中的属性和方法
console.log(stu.sex)//男生
stu.eat()//小明喜欢吃零食
//2、学生原型中的属性和方法
console.log(stu.className)//web前端
stu.learn()//小明喜欢学习
// 3、人构造函数中的属性和方法
console.log(stu.name)//小明
stu.work()//小明热爱工作
// 4、人原型中的属性和方法
console.log(stu.age)//26
stu.playCode()//小明喜欢敲代码
2、构造继承(call方法继承)
//1、人的构造函数
function Person(name, age) {
this.name = name
this.age = age
this.work = function () {
console.log(this.name + "热爱工作")
}
}
//2、人的原型
Person.prototype.sex = "男生"
Person.prototype.basketball = function () {
console.log(this.name + "喜欢打篮球")
}
//3、学生的构造函数
//---------注意----------------
function Student(score, x, y) {
this.score = score
this.study = function () {
console.log(this.name + "喜欢学习")
}
//Student构造函数中的this指向实例化对象stu,stu对象有Student属性--------------
//stu==this
Person.call(this, x, y)
}
Student.prototype = new Person()
//4、学生的原型
Student.prototype.className = "web31"
Student.prototype.playCode = function () {
console.log(this.name + "喜欢敲代码");
}
//---------注意----------------
var stu = new Student(100, "小花", 18)
// var p1 = new Person("小花",18)
// 1、学生构造函数中的属性和方法
console.log(stu.score)
stu.study(
// 2、学生原型中的属性和方法
console.log(stu.className)
stu.playCode()
// 3、人员构造函数中的属性和方法
console.log(stu.name)
console.log(stu.age)
stu.work()
// 4、人员原型中的属性和方法
console.log(stu.sex)
stu.basketball()
3、拷贝继承
//人的构造函数
function Person(name) {
this.name = name
this.work = function () {
console.log(this.name + "热爱工作");
}
}
//人的原型
Person.prototype.age = 26
Person.prototype.code = function () {
console.log(this.name + "喜欢敲代码");
}
//学生的构造函数
function Student(sex) {
this.sex = sex
this.eat = function () {
console.log(this.name + "喜欢吃零食")
}
}
//学生的原型
Student.prototype.className = "web前端"
Student.prototype.study = function () {
console.log(this.name + "喜欢学习");
}
var stu = new Student("男生")
var p = new Person("小明")
//-------------主要代码主要代码----------
for (x in p) {//循环父类
stu[x] = p[x]
}
// 1、学生构造函数中的属性和方法
console.log(stu.sex)//男生
stu.eat()//小明喜欢吃零食
// 2、学生原型中的属性和方法
console.log(stu.className)//web前端
stu.study()//小明喜欢学习
// 3、人员构造函数中的属性和方法
console.log(p.name);//小明
p.work()//小明热爱工作
// 4、人员原型中的属性和方法
console.log(p.age);//26
p.code()//小明喜欢敲代码
四、堆栈
JavaScript的变量存储方式:栈(stack)和堆(heap)
-
1、栈:自动分配内存空间,系统自动释放,里面存放的是基本类型和引用类型的地址
-
2、堆:动态分配的内存,大小也不定,也不会自动释放。里面存放引用类型的值
五、深拷贝与浅拷贝(引用类型)
- 基本类型:简单的数据段—栈 传值
- 引用类型:可能有多个值 传址
地址(引用、指针)—栈
值—堆
栈中的地址指向堆中的值
1、浅拷贝
- 会影响原来的值
数组的浅拷贝
var arr1 = [1,2,3]
var arr2 = arr1
console.log(arr2)//[1,2,3]
arr2.push(4)
console.log(arr2)//[1,2,3,4]
console.log(arr1)//[1,2,3,4]

对象的浅拷贝
var obj1 = {
name: "小明",
age: 18,
}
var obj2 = obj1
obj2.sex = "男生"
console.log(obj2);//{name: '小明', age: 18, sex: '男生'}
console.log(obj1);//{name: '小明', age: 18, sex: '男生'}
2、深拷贝
- 不会影响原来的值
数组的深拷贝
// 1、for循环
var arr3 = [1,2,3]
var arr4 = []
for(var i = 0;i < arr3.length; i++){
arr4.push(arr3[i])
}
console.log(arr4)//[1,2,3]
arr4.push(4)
console.log(arr4)//[1,2,3,4]
console.log(arr3)//[1,2,3]
//2、slice
var arr1 = [1,2,3]
var arr2 = arr1.slice(0)
arr2.push(5)
console.log(arr2);//[1,2,3,5]
console.log(arr1);//[1,2,3]
//3、concat()
var arr1 = [1,2,3]
var arr2 = arr1.concat()
console.log(arr2)//[1,2,3]
arr2.push(6)
console.log(arr2)[1,2,3,6]
console.log(arr1)[1,2,3]
对象的深拷贝
//1、for循环
var obj1 = {
x: 1,
y: 2,
}
var obj2 ={ }
for(x in obj1) {
obj2[x] = obj1[x]
}
console.log(obj2);//{x: 1, y: 2}
obj2.z = 3
console.log(obj2);//{x: 1, y: 2, z: 3}
console.log(obj1)//{x: 1, y: 2}
六、练习
var fun = function () { }
fun.prototype = {
name: 'peter',
age: 25
}
var a = new fun();
var b = new fun();
console.log(a.name, b.name);//peter peter
fun.prototype.name = 'jack';
console.log(a.name, b.name);//jack jack
// console.log(a.__proto__ == fun.prototype); true
fun.prototype = {};
// console.log(a.__proto__ == fun.prototype); false 因为fun的原型为空 a的原型指针不变
fun.prototype.name = 'tom';console.log(a.name, b.name);//jack jack
b.constructor.prototype.name = 'kitty';
function A() {}
function B(a) {
this.a = a;
}
function C(a) {
if (a) {
this.a = a;
}
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
console.log(new A().a);//1
console.log(new B().a);//undefined
console.log(new C(2).a);//2
console.log(new C(0).a);//1
//方法没有会报错 属性没有 undefined
var F = function () {
}
Object.prototype.a = function () {
console.log('a()')
}
Function.prototype.b = function () {
console.log('b()')
}
var f = new F()
f.a()//a() 构造函数没有 F没有原型 Object有
f.b()//报错 构造函数没有 F没有原型 Object没有.b 会报错
F.a()//a() 没构造函数 有原型 Object有
F.b()//b()
var P = function () { }
P.prototype.aaa = function () {
alert("ddd")
}
var a = new P();
var num = 10;//v ar num = new Number(10)
console.log(P.__proto__ == Function.prototype);//true
console.log(P == a.constructor);//true
console.log(a.__proto__ == P.prototype);//true
console.log(P.prototype.__proto__ == Object.prototype);//true
console.log(a.prototype);//undefined
console.log(Number.__proto__ == Function.prototype);//true
console.log(Number.prototype == num.__proto__);//true
console.log(Function.__proto__ == Function.prototype);//true
console.log(Function.prototype == P.__proto__);//true
console.log(Function.prototype.__proto__ == Object.prototype);//true
console.log(Object.__proto__ == Function.prototype);//true
console.log(Object.prototype.__proto__ == null);//true