您的位置:首页 > 博客中心 > 编程语言 >

javascript基础(第五天)

时间:2022-03-25 03:57

路漫漫其修远兮,吾将上下而求索!

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);

命名空间
初始化分支
延迟执行
链式调用
设计模式
    单例
    工厂
    门板
    装饰器
    观察者
    发布订阅

现在再来体会下面这句话:

路漫漫其修远兮,吾将上下而求索!

js面向对象博大精深,深究内部,将无往而不利,终成一代宗师.

本类排行

今日推荐

热门手游