原型
- Person.prototype -- 原型
Person.prototype.lastName = 'Lee'; function Person(params) { this.lastName = "Zhang"; } var person = new Person(); console.log(person.lastName); // Zhang 就近原则
function Person(){
this.name = 'Lee'}
function Car(){
this.name = 'Car' }
var car = new Car()
console.log(car.constructor); // ƒ Car(){ this.name = 'Car' } 访问构造car的构造函数
car.constructor = Person; // 修改constructor构造函数
console.log(car.constructor); // ƒ Person(){ this.name = 'Lee'}
__proto__
Person.prototype.name = 'Lee';
function Person(){
}
var person = new Person();
// 下面这种写法相当于创建了一个prototype对象,而实际的原型在 __proto__ 上,即
// function Person(){ /* var this = {__proto__: Person.prototype */ }}
Person.prototype = {
name: 'ProsperLee'
}
console.log(person.name); // Lee
// ===>
// Person.prototype = { name: 'Lee' }
// __proto__ = Person.prototype;
// Person.prototype = { name: 'ProsperLee' };
// Person.prototype.name = 'Lee';
function Person(){
}
Person.prototype = {
// 还没new就做了修改
name: 'ProsperLee'
}
var person = new Person();
console.log(person.name); // ProsperLee
- 绝大多数对象的原型链的终点:
Object.prototype
(Object.create(null)、undefined、null没有原型)console.log(Object.prototype); // {...} 原型对象 console.log(Object.prototype.__proto__); // null
toString重写
- 系统在 Number、Boolean、String、Array、Function 的原型上重写了本应该在 Object 原型上的 toString 方法
Object.prototype.toString Number.prototype.toString Boolean.prototype.toString String.prototype.toString Array.prototype.toString Function.prototype.toString // 函数的源码是什么就返回什么 // 要访问原型上的toString而不是自身重写的同String方法 // Object.prototype.toString.call(要访问的对象)
改变this指向:
- call(指向,传参,传参,···)
A.call(B,x,y,z,···) 将A的方法植入到B中
- apply(指向,[传参,传参,···])
A.apply(B,[x,y,z,···]) 将A的方法植入到B中
function Person(name,age){ this.name = name; this.age = age; } var obj = { name: "Prosper" } Person.call(obj); // ==> // function Person(name,age){ // // var this = obj // this.name = name; // this.age = age; // } console.log(obj); // {name: undefined, age: undefined} 覆盖 Person.call(obj,'Lee',23); console.log(obj); // {name: "Lee", age: 23}
- 练习01:B所要实现的功能涵盖了A要实现的功能,但是B的功能比A的功能强大,B要怎么写
// A: function A(name, age, sex) { this.name = name; this.age = age; this.sex = sex; } // B: // function B(name, age, sex, tel, grade) { // this.name = name; // this.age = age; // this.sex = sex; // this.tel = tel; // this.grade = grade; // }
- 答案:
function B(name, age, sex, tel, grade) { var that = this; console.log(that); A.call(that, name, age, sex); A.apply(that, [name, age, sex]); this.tel = tel; this.grade = grade; } var b = new B('Lee', 23, '男', '182*******32', 'grade'); // new的时候就执行了一次了 console.log(b); // B {name: "Lee", age: 23, sex: "男", tel: "182*******32", grade: "grade"}
- 练习02:通过call和apply返回数组最大最小值
var arr = [3, 6, 1, 66, 0, 98]; // null 因为没有规定要放到哪个对象中,所以随便写 var minCall = Math.min.call(null,arr[0],arr[1],arr[2],arr[3],arr[4],arr[5]); var maxCall = Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4],arr[5]); console.log(minCall,maxCall); // 0 98 var minApply = Math.min.apply(null,arr); var maxApply = Math.max.apply(null,arr); console.log(minApply,maxApply); // 0 98 console.log(Math.min(arr[0],arr[1],arr[2],arr[3],arr[4],arr[5])); console.log(Math.max(arr[0],arr[1],arr[2],arr[3],arr[4],arr[5]));
- 练习03: test() 和 new test() 结果
var a = 5; function test(){ a = 0; console.log(a); console.log(this); console.log(this.a); var a; console.log(a); } test(); // 0 window 5 0 --> 没人调用,this指向window new test(); // 0 test{} undefined 0 --> 自己调用的,this指向自己的构造成的对象,相当于在函数内 var this = Object.create(test.prototype)
继承发展史
- 1.传统形式 --> 原型链
过多的继承了没用的属性
- 2.构造函数法
不能继承借用构造函数的原型
每次构造函数都要多走一个函数 - 3.共享原型
不能随便改动自己的原型
- 4.圣杯模式
// 3.共享原型 Father.prototype.lastName = 'Lee'; function Father(){ } function Son(){ } function inherit(Target, Origin){ Target.prototype = Origin.prototype; } inherit(Son,Father) var son = new Son(); var father = new Father(); console.log(son.lastName, father.lastName); // Lee Lee // Father.prototype为Father和Son的共享原型,(不足:当Son.prototype.xxx改变Father.prototype.xxx跟着变动) // +++++++++++++++++++++++++++++ // 4.圣杯模式 Father.prototype.lastName = 'Lee'; function Father(){ } function Son(){ } function inherit(Target, Origin){ function S(){ }; // 中介 S.prototype = Origin.prototype; // Origin.prototype为Origin和S的共享原型 Target.prototype = new S(); // 将S的构造函数赋值给Target.prototype Target.prototype.constuctor = Target; // Target继承Origin,Target构造方法归位 Target.prototype.uber = Origin.prototype; // uber为Target的超类(超级父级) } inherit(Son,Father); var son = new Son(); var father = new Father(); console.log(son.lastName, father.lastName); // Lee Lee Son.prototype.age = 18; console.log(son.age, father.age); // 18 undefined // ==> 圣杯模式变式 ==> // var inherit = (function (){ // var S = function (){}; // 中介 // return function(Target, Origin){ // S.prototype = Origin.prototype; // Origin.prototype为Origin和S的共享原型 // Target.prototype = new S(); // 将S的构造函数赋值给Target.prototype // Target.prototype.constuctor = Target; // Target继承Origin,Target构造方法归位 // Target.prototype.uber = Origin.prototype; // uber为Target的超类(超级父级) // } // }())
连续.fun()
var obj = { a: function (){ console.log(arguments.callee.name); return this; }, b: function (){ console.log(arguments.callee.name); return this; }, c: function (){ console.log(arguments.callee.name); return this; } } obj.a().b().c()
var obj = { name: 'ProsperLee', age: 23, __proto__:{ lastName: 'Lee', name: 'PL' } } for(var key in obj){ if(obj.hasOwnProperty(key)){ // 检测key是不是obj自己的属性 console.log(obj[key]); // ProsperLee 23 } console.log(obj[key]); // 结果 ProsperLee 23 Lee 将__proto__里的内容当成了自己的属性 } // 检测 key 是否存在在 obj 中: key in obj (key为字符串) console.log('lastName' in obj); // true console.log('abc' in obj); // false
// A instanceof B --> A对象的原型链上有没有B的原型 console.log({ } instanceof Object); // true console.log([] instanceof Object); // true Object.prototype.toString.call({ }) // [object Object]
function foo() { bar.apply(null, arguments) } function bar(x) { console.log(arguments); } foo(1, 2, 3, 4, 5) // [1, 2, 3, 4, 5]
this
- 1.函数预编译过程 this --> window
- 2.全局作用域里 this --> window
- 3.call/apply 可以改变函数运行时 this 的指向
- 4.obj.func(); func() 里面的 this --> obj
练习
// 练习01: var name = 1; var a = { name: 2, say: function(){ console.log(this.name); } } var fun = a.say; fun(); // 1 a.say(); // 2 var b = { name: 3, say: function(fun){ fun(); } } b.say(a.say); // 1 // var b = { // name: 3, // say: function(fun){ // // this --> b // fun(); // } // } // 相当于把 a.say 的方法拿到外边来了 // function fun(){ // console.log(this.name); // } // var b = { // name: 3, // say: function(){ // // this --> b // fun() // } // } // 没人调用 fun() ,故 fun 中 this 指向全局 b.say = a.say; b.say(); // 3
arguments.callee
function test(){
console.log(arguments.callee); // function test(){
/* CODE */}
}
// function.caller
function funA(){
funB();
}
function funB(){
console.log(funB.caller); // function funA(){ funB(); }
}
funA();
var bar = {
a: '002'};
function print(){
bar.a = 'a';
Object.prototype.b = 'b';
return function inner(){
console.log(bar.a);
console.log(bar.b);
}
}
print()(); // 'a' 'b'