路漫漫其修远兮,吾将上下而求索!
js面向对象博大精深,深究内部,将无往而不利,终成一代宗师.
开胃菜
变量的重复声明是否有影响?
var a = {};
var a;
a;
一点启发?
数组 对象 函数
[] {} function X(){}
new Array() new Object() new X()
前面的小问题
(1)函数没有指定返回值,默认返回什么? //undefined
(2)js有块作用域吗? //只有函数体有作用域
(3)function a(){} a 和 a() 和 new a() 的区别吗? // a是引用, a()是方法调用, new a()是使用a当构造器来实例出a对象
//传说中的自修改函数
function a(){
console.log(‘A‘);
a = function (){
console.log(‘B‘);
};
}
a();
a();
(4)私有方法和变量?
function a(){
private b;
private c;
function privateD(){}
}
(5)静态方法和变量?
var a = {};
function b(){};
a.aa=‘aa‘;
b.bb=‘bb‘
console.log(a.aa);
console.log(b.bb);
console.log(new b().bb);
(6)实例的方法和变量?
function A(){}
var a = new A();
a.b=‘bbb‘;
console.log(a.b);
console.log(A.b);
(4)(5)(6)总结 Array 举例???
Array.length --->静态变量
Array.isArray() --->静态方法
[1,2,3].push(4) --->实例方法
(7)一句话解释闭包? 将function函数内部的作用域开放出来(将一个变量指向外面), 可以访问里面的私有方法和变量.
var getValue,setValue;
(function(){
var num = 0;
getValue = function(){
return num;
}
setValue = function(n){
num = n;
}
})();
(8) function a(){ this.aa=‘aa‘; return {aa:‘aaaa‘} }; a().aa; //返回值???
function a(){ this.aa=‘aa‘; return {aa:‘aaaa‘} }; new a().aa; //返回值???
//切记,谨记,务必记住, 当函数返回值是对象的时候, 返回该对象, new还是直接调用都是返回该对象.
正题:
var a = {}; //这样写,隐式调用了Object构造器;
var arr = []; //这样写,隐式调用了Array构造器;
var b = {
bb:‘bb‘,
bbb:function(){
return this.bb;
}
};
function c(){
this.cc=‘cc‘;
this.ccc=function(){
return this.cc;
}
}
试问上面, b和c功能基本一样, 写法的差异各自优缺点??
b优点:
(1) b简单直观,直接创建
b缺点:
(1) b不够灵活
c优点
(1) c可以写私有方法和变量
(2) c只有new的时候才会创建实例
(3) c在new实例的时候可以传入参数
(4) c可以return
(5) c可以在写法上有等多的自由,比如上面的自修改函数
......优点太多.......
c缺点
(1) c的缺点是需要new,好麻烦,容易误用.例如下面的例子:
function a(){
this.b = ‘b‘;
return {c:‘c‘};
}
var aa = new a();
console.log(aa.b); //undefined
//-----------------------------------构造器----------------------------------------//
构造器属性(该属性实际上是指向用于创建该对象构造器函数的引用)
function a(){}
a.constructor //function Function() { [native code] }
var aa = new a();
aa.constructor; //function a(){}
var b= {};
b.constructor; //function Object() { [native code] }
JavaScript的都有哪些内建构造器?
Object
Array
Boolean
Number
String
Date
RegExp
Error
Function
因为Object是javascript中所有对象的父对象,所以?
var a = {}; //即使一个空对象, 也有toString(), valueOf()方法;
function a(){};
a.valueOf(); //function a(){}
a.toString(); //"function a(){}"
//-----------------------------------原型----------------------------------------//
每个"函数"都有一个prototype属性, 该属性所存储的就是原型对象.
(1)在函数定义的时候就创建了,声明的时候就创建了
(2)prototype的初始值是"空对象"
(3)prototype属性"构造器函数"的属性
function a(){} a.prototype;//{};
function a(){} typeof a.prototype; //"object"
自身属性的优先级高于原型属性(在原型链上查找,先找自己的,再找父亲的)
function a(){
this.b=‘xx‘;
};
a.prototype = {
b:‘bb‘,
c:‘cc‘
};
var aa =new a();
aa; //{b: "xx", c: "cc"}
__proto__???
var parent = {
b:‘bb‘,
c:‘cc‘
}
function child(){};
child.prototype = parent;
var ren = new child();
console.log(ren);
提问? 怎么从ren这个实例对象上获取原型对象???
console.log(ren.prototype); //undefined; 为什么undefiend???
(1)找到构造器
ren.constructor
(2)再找到构造器的原型
ren.constructor.prototype
console.log(ren.constructor.prototype === parent ); //true ?? 妈的,我没测出来
也可以这样
console.log(ren.__proto__ === parent); //true
提问: __proto__ 和 prototype 一样吗??? 完全不一样啦
__proto__ 是对象实例查找原型的属性, prototype是构造器函数的属性,
//-----------------------------------继承(最复杂,最博大精深)-----------------------------------//
原型坑
(1) 当我们对原型完全替换,可能会触发原型链的某种异常
(2) prototype.constructor 属性是不可靠的
function Dog(){
this.tail = true;
}
var tom = new Dog();
Dog.prototype.say = function(){
return ‘Woof‘;
}
console.log( tom.say() ); //Woof
console.log( tom.constructor ); //Dog()
console.log( tom.constructor.prototype.constructor ); //Dog();
console.log( typeof tom.constructor.prototype.tail ); //undefined;
Dog.prototype = {paws:4,hair:true};
console.log( tom.say() ); //出问题了!!!! 因为__proto__
继承的写法
(1) 只继承原型, 说缺点??
function a(){};
a.prototype.name=‘shape‘;
function b(){};
b.prototype = a.prototype;
b.prototype.constructor=b;
function c(){};
c.prototype = b.prototype;
c.prototype.constructor=c;
(2) 临时构造器, new F() 第一种相对不错的继承写法
function a(){};
a.prototype.name=‘shape‘;
function f(){};
f.prototype = a.prototype;
var ff = new f();
console.log(ff.name); //shape
//人类发明了这个方法, 成熟的js框架随处可见这个方法
function extend(child,parent){
var f = function(){}
f.prototype = parent.prototype;
child.prototype = new f();
child.prototype.constructor=child;
child.uber = parent.prototype; //添加一个指向父级原型的引用
}
(3) 属性copy 第二种继承写法
function extend2(child,parent){
var p = parent.prototype;
var c = child.prototype;
for(var i in p){
c[i] = p[i];
}
c.uber = p;
}
//说缺点?? 提示: 对象类型(函数和数组),都是引用传递, 函数本身不会被再次创建.
var a = function(){};
var b = function(){};
a.prototype.arr = [1,2,3];
extend2(b,a);
b.prototype.arr.push(4,5,6);
console.log(a.prototype.arr); //[1, 2, 3, 4, 5, 6]
//扩展: 浅copy和深copy的继承写法, 成熟的js框架随处可见这个方法
(4) 对象间继承 object() 第三种继承写法
//优秀的常规写法
function extendCopy(p){
var c = {};
for(var i in p){
c[i] = p[i];
}
c.uber = p;
return c;
}
//作者 Douglas Crockford
function object(o){
function f(){};
f.prototype = o;
n = new f();
n.uber = o;
return n;
}
//出处: javascript权威指南 122页 优秀示例
function inherit(p){
if( p === null ) throw TypeError();
if( Object.create ){
return Object.create(p);
}
var t = typeof p;
if( t !== ‘object‘ && t !== ‘function‘ ){ throw TypeError(); }
function f(){};
f.prototype = p;
return new f();
}
//这样写继承好处多多
var a = Object.create({});
(5)多重继承
function multi(){
var n = {};
for(var j=0; j<arguments.length; j++){
var stuff = arguments[j];
for(var i in stuff){
n[i] = stuff[i];
}
}
return n;
}
var a = {aa:‘aa‘,aaa:‘aaa‘};
var b = {bb:‘bb‘,bbb:‘bbb‘};
var c = multi(a,b);
console.log(c); //{aa: "aa", aaa: "aaa", bb: "bb", bbb: "bbb"}
(6)混合继承
function triangle(o,s,h){
function f(){};
f.prototype = o;
n = new f();
n.uber = o;
n.s = s;
n.h = h;
return n;
}
(7)构造器借用继承
//初级玩法
function a(){
this.aa=‘aa‘;
};
function b(){
a.apply(this,arguments);
};
var bb = new b();
console.log(bb.aa); //aa
//高级玩法
function a(){
this.aa=‘aa‘;
};
function b(){
this.extend = function(){
var arg = [].slice.call(arguments,1);
(arguments[0]).apply(this,arg);
};
};
var bb = new b();
bb.extend(a);
console.log(bb.aa); //aa
结束语:
继承写法是可以组合的, 够变态吧!!! js继承有至少几十种写法
function child(){
parent.apply(this,arguments);
}
extend2(child,parent);
命名空间
初始化分支
延迟执行
链式调用
设计模式
单例
工厂
门板
装饰器
观察者
发布订阅
现在再来体会下面这句话: