js基础 继承模式,this
继承模式
继承发展史
传统形式 —> 原型链
过多的继承了没用的属性 借用构造函数
不能继承借用构造函数的原型 每次构造函数都要多走一个函数 共享原型
不能随便改动自己的原型 圣杯模式
// 1 传统形式 ---> 原型链
Grand.prototype.lastName = "Li";
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()
// 我们只想son继承顶端的lastName
// 但是现在因为连成了原型链所以son会继承father的东西和father原型链上的东西、grand的东西和grand原型链上的东西
// 这种继承方法就会过多的继承没用的属性
// 发生一些矛盾,不想继承的东西也被继承过来了
// 所以这种方法很快就被废弃了;
// 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();
// 这种方法不好的地方就是只能借用构造函数的方法不能继承借用构造函数的原型
// 并且每次构造函数都要多走一个函数
// 每次构造方法至少要走两个函数,比较浪费效率
// 3 共有原型
Father.prototype.lastName = "Li";
function Father() {
}
function Son(){
}
// 我们想让son继承Father.prototype
// 按我们之前的写法就要形成原型链
// 现在我们简单粗暴的这么写:
Son.prototype = Father.prototype;
/*
Father.prototype
Father Son
现在他俩就有了一个共用的原型
*/
// 我们封装一个方法来把这种写法封装一下
function inherit (Target, Origin) {
// 我们传入两个构造函数
Target.prototype = Origin.prototype;
}
inherit(Son, Father);
var son = new Son();
// 这样的话就又引发出了另一个问题
/*
我们想给Son.prototype加东西
Son.prototype.sex = "male";
但是这样写了之后Father.prototype就也加上了 sex = "male"
所以Son不能个性化的修改自己的东西
那么我们就想实现让Son可以个性化的随意给自己增加属性又不想影响Father怎么来实现呢?
只有实现让Son可以个性化的随意给自己增加属性又不想影响Father才算是真正意义上的继承
这样就引申出最后一种方法:圣杯模式
*/
// 4 圣杯模式
// 方法还是共有原型,但是有一点小的区别
Father.prototype.lastName = "Li";
function Father() {
}
function Son(){
}
function F() {}
F.prototype = Father.prototype
Son.prototype = new F();
// 使用构造函数F作为中间层
// 让F和Father共用一个原型
// 现在Son的prototype是 new F()
// 通过原型链的方式又实现了继承
// 这样的话Son既能继承Father的东西又可以在自己身上做操作而不影响Father
// 我们再提取这个方法封装一下
function inherit(Target, Origin) {
function F() {}
F.prototype = Origin.prototype
Target.prototype = new F();
// Target.__proto__ --> new F().__proto__ --> Father.prototype
// 所以
Target.prototype.constuctor = Target;
// 我们希望我们的构造出的对象可以找到自己的超类(超级父级)
Target.prototype.uber = Origin.prototype;
// 这样就已经实现出了圣杯模式
}
// 我们再看一个比较高大尚的写法
// Yahoo 的YUI3库里的inherit
var inherit = (function () {
var F = function(){};
return function (Target, Origin) {
F.prototype = Origin.prototype
Target.prototype = new F();
Target.prototype.constuctor = Target;
Target.prototype.uber = Origin.prototype;
}
}())
// 这里使用了闭包的第三点应用(可以实现封装)
// 因为 F 只是为了过渡一下,完了之后并没有什么用处所以把F变成私有化变量
1. 实现共有变量
2. 可以做缓存
3. 可以实现封装
4. 模块化开发,防止污染全局变量
this
函数预编译过程 this —> window 全局作用域里 this —> window call/apply 可以改变函数运行时this指向 obj.func(); func()里面的this指向obj
默认绑定:当作为普通函数被调用时,就会发生默认绑定。this指向全局对象(window),不过要注意,在严格模式中,this的值回你变成undefined,如下所示:
function func() {
console.log(this) // window
}
func();
function finc2() {
"use strict";
console.log(this) // undefined
}
func2();
隐式绑定:当作为对象方法被调用时,就会发生饮食绑定,this指向调用该方法的对象。
var obj = {
name : '罡赫',
getName: function () {
console.log(this.name) // "罡赫"
}
};
obj.getName()
硬绑定:当调用函数的方法apply()、call()或bind()时,就能制定this要绑定的对象,她们一个参数就是一个对象,就是那个要绑定的对象。如果传入null或undefined,就会被替换成全局对象(window);如果传入其他原始值(数字、字符串或者布尔值),就会被自动转化为相对应的包装对象(Number、String、Boolean.
var obj = {
name:'罡赫',
getName : function () {
console.log(this.name);
},
getThis: function() {
console.log(this);
}
}
var name = '泽煜';
obj.getName.apply(null);
obj.getName.apply(undefined);
obj.getThis.apply(true);
构造函数绑定:当用new运算符来调用构造函数时,会创建一个新的对象,构造函数中的this会与这个新对象绑定在一起。
var name = '泽煜';
function Func() {
this.name = '罡赫';
this.getName = function () {
console.log(this.name);
}
};
var obj = new Func()
obj.getName(); // '罡赫'
面试题
$('div').css('background-color','red').width(100).height(100);
jquery实现点链接方法
var Yuqian = {
smoke : function() {
console.log('抽烟 !!!');
return this;
},
dink : function() {
console.log('喝酒 !!!');
return this;
},
perm : function() {
console.log('烫头 !!!');
return this;
}
}