1、原型、原型链
1.1 原型的定义:原型是function对象的一个属性,原型定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象, 可以继承该原型的属性和方法。原型也是对象。
原型是该构造函数构造出对象的公有祖先
Person.prototype --> 原型是函数的一个属性
//Person.prototype = {} 它就是公共祖先,是一个对象,在函数刚刚被创建时,就已经被定义好了
Person.prototype.LastName = "Liu";
Person.prototype.say = function () {
console.log('hehe');
}
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
var person = new Person("zhangsan", 20, "male");
//person能够继承Person原型上的属性和方法,person继承了Person原型的LastName 属性和say 方法
当构造函数自身与原型上有同一个属性或方法,构造出新对象时,取构造函数自身的属性或方法
利用原型的特点和概念,可以提取公有属性
Car.prototype = {
height: 1400,
lang: 4900,
carName: "BMW"
}
function Car(color, owner) {
this.owner = owner;
this.color = color;
//下面三个属性在每次构造出对象时都要执行,造成代码的冗余,通过继承解决(放到原型中)
// this.height = 1400;
// this.lang = 4900;
// this.carName = "BMW";
}
var car = new Car("red", "Liu");
var car1 = new Car("yellow", "Wang");
1.2 原型的增删改查
Person.prototype.LastName = "Zhang";
function Person(name) {
this.name = name;
}
var person = new Person("San");
(1)查:执行person.LastName
(2)改:Person.prototype.LastName = "Wang";
(3)增:Person.prototype.Sex = "male";
(4)删:delete关键字
1.3 constructor(构造器)
constructor属性会返回构造该对象的构造函数
function Fn(){}
var test = new Fn();
//执行test.constructor会返回function Fn(){}
1.4 __proto__
1.4.1 每个对象都具有一个名为__proto__的属性
1.4.2 每个构造函数(系统自带的和自定义的)都有一个prototype方法,也就是说,prototype同样有__proto__属性
Person.prototype.name = "abc";
function Person(){
//var this = {
// __proto__ : Person.prototype __proto__将person与Person.prototype连接起来
//};
}
var person = new Person();
如果我们要访问person.name,它会先在自身的属性中找有没有name属性,如果没有,它就会沿着__proto__的指向,到Person.prototype里面去找
举例
Person.prototype.name = "sunny";
function Person() {}
var person = new Person();
Person.prototype.name = "cherry";//更改了Person.prototype的属性
访问person.name,结果为cherry
举例
Person.prototype.name = "sunny";
function Person() {
//在new Person时 var this = { __proto__ : Person.prototype}
}
var person = new Person();
Person.prototype = {
name : "cherry"
}
访问person.name,结果为sunny
分析:引用值的互相赋值
Person.prototype = {name : "sunny"}
__proto__ = Person.prototype;
Person.prototype = {name : "cherry"}
2、原型链
构成原型链
//Grand.prototype.__proto__ = Object.prototype
Grand.prototype.LastName = 'Zhang';
function Grand() { }
var grand = new Grand();
Father.prototype = grand;
function Father() { this.name = 'San'; }
var father = new Father();
Son.prototype = father;
function Son() { this.habbit = 'somke'; }
var son = new Son();
son可以访问son.LastName属性
Person.prototype = {
name: 'a',
sayName: function () { console.log(this.name);}
}
function Person() { this.name = 'b'; }
var person = new Person();
//sayName里面的this的指向,谁调用的这个方法,this指向谁
2.1 Object.create(原型)
var obj = {
name: "sunny",
age: 20
};
var obj1 = Object.create(obj);
2.2 绝大多数对象的最终都会继承自Object.prototype
特殊情况:Object.create(null),创建的对象没有原型
3、call/apply
作用:改变this的指向
区别:call和apply的传参列表不同
3.1 call
function Person(name, age) {
//this == obj
this.name = name;//this.name = name ==>obj.name = name
this.age = age;//this.age = age ==>obj.age = age
}
var person = new Person('Zhang', 20);
var obj = {};
Person.call(obj, "wang", 22);
call的第一个参数会改变this的指向,第二位以后的参数当作实参传递到形参去。
这里把obj传到this去了,执行时this变成了obj。
this举例:
借用别人的函数,实现自己的功能
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name, age, sex, tel, grade) {
//var this = {} 这里的this和call的第一个this是同一个this
Person.call(this, name, age, sex);
this.tel = tel;
this.grade = grade;
}
var student = new Student('sunny', 123, 'male', 139, 2015);
this举例:
function Wheel(wheelSize, style) {
this.wheelSize = wheelSize;
this.style = style;
}
function Sit(c, sitColor) {
this.c = c; this.sitColor = sitColor;
}
function Model(height, width, len) {
this.height = height;
this.width = width;
this.len = len;
}
function Car(wheelSize, style, c, sitColor, height, width, len) {
//利用其他的函数实现功能
Wheel.call(this, wheelSize, style);
Sit.call(this, c, sitColor);
Model.call(this, height, width, len)
}
var car = new Car(100, "花哨", "真皮", "red", 1800, 1900, 4900);
3.2 apply
传参时需要传一个arguments(数组的形式)——实参列表,其他方面和call没有任何区别
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name, age, sex, tel, grade) {
//var this = {} 这里的this和call的第一个this是同一个this
Person.call(this, [name, age, sex]);
this.tel = tel;
this.grade = grade;
}
var student = new Student('sunny', 123, 'male', 139, 2015);
4、继承
4.1 传统形式——>原型链:过多的继承了没用的属性
Grand.prototype.lastName = "Liu"
function Grand() { }
var grand = new Grand();
Father.prototype = grand;
function Father() {
this.name = 'hehe';
}
var father = new Father();
Son.prototype = father;
function Son() { }
var son = new Son();
4.2 借用构造函数:不能继承借用构造函数的原型、每次构造函数都要多走一个函数
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name, age, sex, grade) {
Person.call(this, name, age, sex);
this.grade = grade;
}
var student = new Student();
4.3 共享原型:不能随便改动自己的原型
Father.prototype.lastName = 'Liu';
function Father() {}
function Son() {}
function extend(Target, Origin) {
Target.prototype = Origin.prototype;
}
extend(Son, Father);
var son = new Son();
//不能给Son加一个独立的属性
4.4 圣杯模式 最完美的继承模式
//C继承A
// function B() { }
// B.prototype = A.prototype
// C.prototype = new B();
function extend(Target, Origin) {
function F() {};
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constuctor = Target;//把a的constuctor指向自己
Target.prototype.uber = Origin.prototype;//Target真正继承自Origin
}
function A() {}
function B() {}
extend(A, B);
var A = new A();
var b = new B();
//现在给a增加独立的属性不会影响b
//a.__proto__--> new F().__proto__-->b.prototype a的构造器指向的是b