實例練習

//1做一個循環,計算累加到300需要的次數---------------------------------------------------------

// var num = 1;
// var times = 0;
//1 
// var realdo = true;
// for (var i = 1; realdo; i++) {
//     num += i;
//     times++;
//     // num > 300 && console.log(times);
//     if (num > 300) {
//         console.log(times);
//         realdo = false;
//     }
// }

//2 
//for (var i = 1; i < 1000; i = i + 1) {
//     num += i;
//     times++;
//     if (num > 300) {
//         console.log(times);
//         i = 1000;
//     }
// }

//3 
// for (var i = 1; num <= 300; i++) {
//     num += i;
//     times++;
// }
// console.log(times);

// 4 
for (; num <= 300;) { // --------  num 小於等於 300 嗎? 是,執行下面語句 不是跳出循環  結果爲循環後的值
    num += ++times;
}
console.log(times);

// 5  
while (num <= 300) {
    num += ++times; //++times:0,1,2,3,4
    // num 是累加的和 去加上 調節數++times
}


//2求2的n次方--------------------------------------------------------------------------------

var n = parseInt(window.prompt());
var num = 2;
if (n == 0) {
    console.log(1);
}
// else if (n == 1) { console.log(2);}
else {
    for (var i = 0; i < n - 1; i++) {
        num *= 2;
    }
    console.log(num);
}

// for (var i = 0; i < 99;) {} // 99次循環
// for (var i = 1; i <= 99;) {} // 99次循環




//3階乘-----------------------------------------------------------------------------------------

//方法1
var a = parseInt(window.prompt());
var num = 1;
if (a == 0 || a == 1) console.log(1);
else {
    for (var i = 1; i <= a; i++) {
        num *= i;
    }
    console.log(num);
}


//方法2
// var num = a;
// for (var i = a - 1; i > 0; i--) {
//     num = num * i;
// }
// console.log(num);




//4斐波那契數列-----------------------------------------------------------------------------

var n = parseInt(window.prompt());
// 1    1    2     3   5 8 13 21
// f    s
//         l=f+s
//      f    s    
//                 l
//           f     s
//                     l
var f = 1;
var s = 1;
var last = 0;
if (n == 1 || n == 2) console.log(1);
else {
    for (var i = 0; i < n - 2; i++) { // 做循環次數,不影響循環體內容,我只負責循環幾次
        last = f + s;
        f = s; // 後一位的值賦值給前一位, s --> f
        s = last; // l --> s
    }
    console.log(last);
}


//5輸入三個數,輸出最大值-------------------------------------------------------------------------------

// var a = parseInt(window.prompt());
// var b = parseInt(window.prompt());
// var c = parseInt(window.prompt());

// var max = a;
// if (max < b) max = b;
// if (max < c) max = c;
// console.log(max);


var max = 0;
for (var i = 0; i < 5; i++) {
    var currValue = parseInt(window.prompt());
    if (max < currValue) {
        max = currValue;
    }
}
console.log(max);



//6輸入一組數字,反向輸出-------------------------------------------------------------------------------

var num = parseInt(window.prompt());
var g, s, b;
g = num % 10;
s = (num - g) / 10 % 10;
b = (num - g - s * 10) / 100;
num = g * 100 + s * 10 + b;
console.log(num);



//7輸出100以內的質數------------------------------------------------------------------------------------

var count = 0;
for (var i = 1; i <= 100; i++) { // 把1-100個拿出來
    for (var j = 1; j <= i; j++) { // 每拿出來一個數就對應的計算
        if (i % j == 0) {
            count++;
        }
    }
    if (count == 2) {
        console.log(i); //當循環結束後,計數器爲2表示質數
    }
    count = 0; // 輪到下一個數計數器清零
}

//8 break語句練習---------------------------------------------------------------------------------------

for (var i = 0; i < 100; i++) {
    for (var j = 0; j < 100; j++) {
        console.log(j);
        if (j == 10) {
            break;
        }
    }
}


//9 contintue語句練習---------------------------------------------------------------------------------

for (var i = 0; i < 100; i++) {
    if (i % 5 == 0) {
        continue;
    }
    console.log(i);
}


//10  死循環-------------------------------------------------------------------------------------------

var times = 0;
while (true) {
    times++;
    var num = Math.floor(Math.random() * 100);
    if (num == 33) {
        break;
    }
}
console.log(times);



// 隨機生成數字符合 11 * i 需要的次數
for (var i = 1; i < 10; i++) {
    var times = 0;
    var selfNum = 11 * i;
    while (true) {
        times++;
        var num = Math.floor(Math.random() * 100);
        if (num == selfNum) {
            break;
        }
    }
    console.log(selfNum + ':' + times);
}


//11 單純拼接代碼------------------------------------------------------------------------------------------

var person = {
    name: 'nike',
    age: 18
}
var property = 'age';
console.log(person['property']);
console.log(person[property]);
// 沒有任何意義,單純的字符串拼接,像一個拼圖,property就是 'age'
// 而兩者的區別是,第一個訪問失敗,因爲對象裏沒有'property'屬性
// 而第二句,就是person['age']
//property = 'age'   person[property] = person['age']



//12 把八進制30427轉換成二進制------------------------------------------------------------------------------

var a = parseInt(30427, 8); // 8 -> 10
var b = a.toString(2); // 10 -> 2


//13 遞歸求函數階乘-----------------------------------------------------------------------------------------

// 遞歸  1找規律  2找出口
// 10! = 10*9!
// n * (n-1)!
// ft(n) = n * ft(n - 1);

function ft(n) {
    if (n >= 0) {
        n = parseInt(n);
        if (n == 0 || n == 1) {
            return 1;
        }
        return n * ft(n - 1);
        //     5 * ft(4)
        //           4  *  ft(3)
        //                   3  *  ft(2)
        //                           2  *  ft(1)
    } else {
        return 'false';
    }
}

//14 遞歸求斐波那契數列(盡力避免使用遞歸)--------------------------------------------------------------------------------

//  1  1  2   3   5  8   13   21 
//  1  2  3   4   5  6    7   8
//            6
//           5   +   4
//         4 + 3    3 + 2
//       3 + 2  2 + 1  2 + 1  

function ft(n) {
    if (n == 1 || n == 2) { return 1 };
    return ft(n - 1) + ft(n - 2);
    //   ft(4) +  ft(3)
    //  ft(3) + ft (2)  ft(2) + ft(1)
    //   ft(2) + ft(1) + ft(2) + ft(2) + ft(1)
}

//15 有100個臺階,每次可以走一步或兩步,問走完有多少種情況?-----------------------------------------------------

function stair(n) {
    if (n <= 0) { return 0 };
    if (n == 1) { return 1 };
    if (n == 2) { return 2 };
    return stair(n - 1) + stair(n - 2);
}
console.log('走完100個臺階有:' + stair(10) + '情況');

// 問題本質上是斐波那契數列,假設只有一個臺階,那麼只有一種跳法,那就是一次跳一級,f(1)=1;
// 如果有兩個臺階,那麼有兩種跳法,第一種跳法是一次跳一級,第二種跳法是一次跳兩級,f(2)=2。
// 如果有大於2級的n級臺階,那麼假如第一次跳一級臺階,剩下還有n-1級臺階,
// 有f(n-1)種跳法,假如第一次條2級臺階,剩下n-2級臺階,有f(n-2)種跳法。
// 這就表示f(n)=f(n-1)+f(n-2)。


//16 作用域鏈----------------------------------------------------------------------------------------------



var global = 300;

function test() {
    console.log(global); // AO: undefined
    var global = 400;
    console.log(global); // 400
}
test();

//-----------------------------------

var global = 100;

function test() {
    console.log(global); // AO :沒有global  GO:100
    global = 200; //不是變量聲明  
    console.log(global); // 200
}
test();
console.log(global); // 200

//----------------------------------

show();
var a;
a = 234;

function show() {
    console.log(b); // undefined
    if (a) {
        var b = 10; // 是否考慮前面的條件語句,還是隻要引擎看到var就提升
    }
    console.log(b); // undefined
}


// ---------------------------------

function bar() {
    return foo;
    foo = 10;

    function foo() {}
    var foo = 11;
}
console.log(bar()); // 11

function bar() {
    foo = 10;

    function foo() {}
    var foo = 11;
    return foo;
}
console.log(bar()); // 11

//17 閉包--------------------------------------------------------------------------------

function a() {
    function b() {
        var bbb = 234;
        document.write(aaa);
    }
    var aaa = 123;
    return b;
}

var glob = 100;
var demo = a();
demo();


//--------------------

function add() {
    var num = 0;

    function get() {
        num++;
        console.log(num);
    }
    return get; //-----
} //     ------get函數被保存到外部,它的作用域鏈scope chain -> {0:getAO,1:addAO,2:GO}
var outerGet = add(); // ----
outerGet(); // 1   
outerGet(); // 2
outerGet(); // 3  一直操作的是作用域鏈當中的num值,即 接着上一次的num運算結果
//    每次執行,使用的都是同一個AO, AO沒有被銷燬

//----------------------------------

function add() {
    var num = 0;
    num++;
    console.log(num);
}
add(); // 每次執行會創建一個新的AO
add();
add();


//18閉包------------------------------------------------------------------------------------------------

function eater() { // GO -> {}
    var food = ''; // 位置1存檔1:eaterAO -> {food :'orange',obj:object,}
    // 位置2存檔1:eaterAO -> {food :'',}
    var obj = {
        eat: function() {
            console.log('i am eating ' + food) // eatAO/pushAO -> { myFood:orange }
        },
        push: function(myFood) {
            food = myFood;
        }
    }
    return obj;
}
var eater1 = eater(); //存檔(存位置1),讀檔
eater1.push('orange'); //買了一件新裝備
eater1.eat(); //賣了一件新裝備

var eater2 = eater(); //存檔(存位置2),讀檔
eater2.eat(); //所以在此運行,輸出空串


//19閉包,立即執行函數------------------------------------------------------------------------------------------

var a = [];
for (var i = 0; i < 10; i++) {
    a[i] = function() {
        console.log(i); // i在GO中
    }
}
a[0](); // 10
a[1](); // 10


//--------------------------------

var a = []; //定義了一個數組,每次循環都會向數組各索引存儲一個輸出函數
for (var i = 0; i < 10; i++) {
    (function(i) { // [[scope]] -> {0:nAO -> {i:0} 1:GO -> {}} 保存到外部,形成閉包,存檔
        a[i] = function() { // a[i].[[scope]] -> {0:a[i]AO,1:nAO,2:GO}  a[i]AO每次執行完銷燬
                console.log(i);
            }
            // return  因爲將函數存到了全局的數組當中,相當於將函數return到外部
    })(i);
}

a[1](); // 產生閉包,立即執行函數不會被銷燬,相當於普通函數
a[9](); // 每一次循環,將i=1~9傳入函數


//20 臨時對象 包裝類-----------------------------------------------------------------------------------------

var str = 'cst';
str.name = 'ccc';
console.log(str.name + 'aaa'); // undefinedaaa


//21 包裝類--------------------------------------------------------------------------------------------------

function check(str) {
    // adsf哈哈
    var count = 0;
    for (var i = 0; i < str.length; i++) {
        var a = str.charCodeAt(i);
        console.log(a);
        if (a < 255) {
            count += 1;
        } else {
            count += 2;
        }
    }
    return count;
}


//22 原型---------------------------------------------------------------------------------------------------


Person.prototype.name = 'sunny';

function Person() {}
var oPerson = new Person();
Person.prototype.name = 'cherry';
console.log(oPerson.name); // cherry


//======================================


Person.prototype.name = 'sunny';

function Person() {}
Person.prototype.name = 'cherry';
var oPerson = new Person();
console.log(oPerson.name); // cherry


//======================================


Person.prototype.name = 'sunny';

function Person() {}
var oPerson = new Person();
Person.prototype = {
    name: 'cherry'
};
console.log(oPerson.name); // sunny

//=======================================

Person.prototype.name = 'sunny';

function Person() {}
Person.prototype = {
    name: 'cherry'
};
var oPerson = new Person();
console.log(oPerson.name); // cherry


//23 原型鏈-------------------------------------------------------------------------------------------------

GrandFather.prototype.lastName = 'yang';

function GrandFather() {
    this.bike = 1;
}
Father.prototype = new GrandFather();

function Father() {
    this.fortune = {
        money: 999999,
        house: 4
    }
    this.name = 'jaja'
}
Son.prototype = new Father();

function Son() {
    this.name = 'heihei',
        this.age = 20
}

var oSon = new Son();
console.log(oSon.lastName);

oSon.fortune.house += 1; //訪問fortune對象的屬性並賦值,改變相同地址的引用值, 相當於改變原型上的屬性
oSon.fortune = {}; //將fortune屬性指向另一個對象地址,換了一個引用值, 相當於給oSon自己添加屬性

var oSon2 = new Son();
console.log(oSon2.fortune.house); //  5  這個是引用值,後續會受影響  


//24 call apply----------------------------------------------------------------------------------------------

function Person(name, age) {
    this.name = name;
    this.age = age;
}

function Student(name, age, myClass, myGrade) {
    Person.call(this, name, age); // Studnet函數調用Person函數,保證Person函數的參數
} // call(name,age)->Student(name,age)->Student(實參)
// this是當前調用的函數Student
new Student('cst', 18, 2, 4); //構造函數會在內部隠式創建this對象並返回,
//原因是構造函數本身就是用於創建對象並初始化
//構造函數身份象徵:new

var numObj = {
    x: 1,
    y: 2
}

function add(a, b) {
    console.log(this.x + a + this.y + b);
}
add(); // NaN
add.call(numObj, 3, 4); // 10



//25聖盃繼承-----------------------------------------------------------------------------------------------------


var inherit = (function() {
    var Cache = function() {}; //緩存函數,每次執行都需要創建一個,沒有必要,寫入閉包
    return function(Target, Origin) {
        Cache.prototype = Origin.prototype; //下游不影響上游
        Target.prototype = new Cache();
        Target.prototype.constructor = Target; // 手動更改構造函數
        Target.prototype.uber = Origin;
    }
})();

// 立即執行函數執行完成後返回一個函數,賦值給inherit.由於函數被保留到外部,形成閉包。
// 相當於我把新建緩存的函數存儲到了執行期上下文裏,隨手就用


//26屬性訪問-----------------------------------------------------------------------------------------------------


var obj = {
    number1: haha,
    number2: lala,
    roc: function(num) {
        document.writes('這個數字是' + this['number' + num]);
    }
}

//==============================

var person = {
    name: 'nike',
    age: 18
}
var property = 'age';
person['property'];
person[property];
// 沒有任何意義,單純的字符串拼接,像一個拼圖,property就是 'age'
// 而兩者的區別是,第一個訪問失敗,因爲對象裏沒有'property'屬性
// 而第二句,就是person['age']


//==============================

var o = { x: 1, y: 2, z: 3 };
o.propertyIsEnumerable('toString');
for (p in o)
    console.log(p, o[p], o.hasOwnProperty(p));



//27 this-----------------------------------------------------------------------------------------------------

var name = '222';
var a = {
    name: '111',
    say: function() {
        console.log(this.name);
    }
}
var b = {
    name: '333',
    say: function(fun) {
        fun();
        // a.say();
        // function(){console.log(this.name}}  相當於沒有對象顯式調用,this是window
    }
}
a.say(); //111
b.say(a.say); //222     把函數a.say當做參數傳入,傳入後執行
b.say = a.say;
b.say(); //333    把東西更改,但是執行上下文根據所在環境



//-------

var foo = '123';

function print() {
    this.foo = '234';
    console.log(foo);
};
print(); //234
new print(); //123 AO{this:{foo}}   構造函數創建this對象,相當於foo是對象內部屬性,平行關係,無法訪問foo



//28 clone--------------------------------------------------------------------------------------------------

var mrChen = {
    name: 'cst',
    age: 18,
    sex: 'man',
    height: 183,
    girl: {
        name: 'zly',
        age: 28,
        house: {
            name: 'ai'
        }
    }
}

var obj = {};

function clone(target, origin) {
    for (var prop in origin) {
        target[prop] = origin[prop];
    }
}
clone(obj, mrChen);

//淺層克隆,有引用值就不好用了

function clone(target, origin) {
    var str = '[object Array]'; //數組身份
    var toString = Object.prototype.toString; //對象方法toString
    for (var prop in origin) {
        if (origin.hasOwnProperty(prop)) {
            if (origin[prop] == target) { //防止循環引用,判斷如果對象的屬性值是目標函數,跳過此次循環
                continue;
            }
            if (typeof origin[prop] == 'object') {
                if (toString.call(origin[prop]) === str) { // 判斷數組
                    target[prop] = []; // 讓這個值等於一個新數組
                } else {
                    target[prop] = {};
                }
                clone(target[prop], origin[prop]); //剝開數組和對象,循環引用函數本身
            } else {
                target[prop] = origin[prop];
            }
        }
    }
}

//深層克隆 遞歸 注意防止循環引用

var obj = {};

var obj2 = {
    name: obj
}
obj.name = obj2.name;

if (origin[prop] == target);
continue;

//純函數  pure function :函數執行後對外界不會有任何影響(引用值的事)
//當函數操作引用值時,可能會對其值改變,保證函數是純函數,可以創建新引用值並返回或使用深度克隆
//說白了,無論是垂直的繼承還是水平的克隆,都是因爲引用值的原因。聖盃繼承和深度克隆。這兩種方式提供純函數


//29 test() 和 new test()--------------------------------------------------------------------------------------

var a = 5;

function test() { //   AO {a:undefind -> 0}    GO {this:window}
    //AO{a:0}
    a = 0; //    關鍵,在以test()方式執行時,是賦值給AO.a
    alert(a); // 0     
    alert(this.a); // window.this.a    ->  5     
    var a;
    alert(a); // 0     
}

test()

function test() {
    // var this = {}
    a = 0;
    alert(a); //0
    //this.a = a
    alert(this.a); // undefined     a有值,但是this裏沒有a屬性 ,不會想當然的的賦值
    var a;
    alert(a); //0
    // return this
}

new test()


//30 構造函數執行-----------------------------------------------------------------------------------------------

function employee(name, code) {
    this.name = 'wangli';
    this.code = 'A001';
}
newemp = new employee('zhangming', 'A002');
document.write('僱員姓名:' + newemp.name + ' <br> '); // wangli
document.write('僱員代號:' + newemp.code + ' <br> ') //A001


//31 函數執行-------------------------------------------------------------------------------------------------

function test(a) {
    // AO{a:undefined,b:undefined,c:undefined}
    // AO{a:44,b:undefined,c:function,this:window}
    console.log(this); //window
    var b = 10;

    function c() {

    }
    var c = 20;
}

test(44); // window.test.call(window,44)

//----普通函數----

var obj = {
    name: 'hah',
    show: function test() {}
        //{this:obj}
}

obj.test(44) //obj.test.call(obj,44)

//----方法調用----

new test(); // Object.create(test.prototype).test.call(Object.create(test.prototype))
// 高能! var this = Object.create(test.prototype);  就是創建一個新對象和原型

//----構造函數----


// call & apply 可以改變this指向




//32 bind()---------------------------------------------------------------------------------------------------


//1.創建綁定函數

this.a = 1;

var module = {
    a: 2,
    getA: function() {
        return this.a;
    }
};
console.log(module.getA()); //2

var getA1 = module.getA;
// getA在外部調用,此時的this指向了全局對象
console.log(getA1()); //1

// 再把getA1方法綁定到module環境上

var getA2 = getA1.bind(module);
console.log(getA2()); //2

// 將函數綁定到指定對象上   func.bind(obj);   func.bind(this,arg1,arg2); 
//bind()方法創建一個新的函數,叫做綁定函數,這個方法會在this的環境下執行
//當我們調用某些方法要在特定的環境下才能調用到,就是使用bind把函數綁定到特定的所需的環境下


//2.讓函數擁有預設的參數

function list() {
    // 讓類數組arguments擁有數組的方法slice,這個函數實現了簡單把類數組轉換成數組
    return Array.prototype.slice.call(arguments);
}

list(1, 2, 3); //[1,2,3]

//給list綁定一個預設參數4 
var list1 = list.bind(undefined, 4);

list1(); //[4]
list1(1, 2, 3); //[4,1,2,3]



//33 作用域------------------------------------------------------------------------------------------------

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

//34 逗號運算符-------------------------------------------------------------------------------------------

var num = (1, 2);
console.log(num); //2

var f = (function h() { return '1' }, function g() { return 2 })();

console.log(typeof f);
//返回後面的值



//35 括號可以把一個函數變成表達式

var x = 1;
if (function f() {}) { //判斷布爾值,函數是對象,不是空對象都是真值,這裏相當於一個立即執行函數,判斷完銷燬
    x += typeof f;
}
console.log(x); // 1undefined



//36 arr.push()、pop()、unShift()、shift()實現-----------------------------------------------------------------------------------------

var arr = [1, 2, , , 3];
// arr.push(2, 3, 4, 5);
Array.prototype.myPush = function() {
        for (var i = 0; i < arguments.length; i++) { //0-4
            this[this.length] = arguments[i] //數組的最後一位等於實參列表的第一位
        }
        return this.length;
    }
    //arr.myPush(1, 2, 3, 4, 'ig');


Array.prototype.myPop = function() {
    var val = this[this.length - 1]; // 數組的最後一位
    this.length -= 1; // 干預數組長度,使其自動截斷
    return val; // 返回val
}

var arr = [1, 2, 3];

Array.prototype.myUnshift = function() {
        var a = [];
        var b = arguments.length;
        // console.log(b); 2
        var c = this.length;
        // console.log(c); 3
        for (var i = 0; i < b; i++) {
            a[i] = arguments[i];
        }
        for (var j = 0; j < c; j++) {
            a[b + j] = this[j];
        }
        // console.log(a);
        for (var k = 0; k < b + c; k++) {
            this[k] = a[k];
        }
        return this.length;
    }
    // arr.myUnshift(9, 8); // [9,8,1,2,3]



Array.prototype.myShift = function() {
    // [1,2,3] -> [2,3]   return 1
    var val = this[0];
    var b = [];
    for (var i = 0; i < this.length - 1; i++) {
        b[i] = this[i + 1];
        // console.log(b);
    }
    for (var j = 0; j < b.length; j++) {
        this[j] = b[j];
        this.length = b.length;
        // console.log(this)
    }
    return val;
}


//37 類數組------------------------------------------------------------------------------------------------------

//1 屬性名是連續數字
//2 有length屬性
//3 必須有push方法和splice方法

var obj = {
    //[ , ,'a','b']  
    2: 'a',
    3: 'b',
    length: 2, //長度是2 ,push源碼是利用this[this.length] = arguments[length] 
    push: Array.prototype.push,
    splice: Array.prototype.splice
}
obj.push('c');
obj.push('d');
console.log(obj); // [undefined,undefined,'c','d']

//38 數組去重----------------------------------------------------------------------------------------------------

var arr = [10, 8, 9, 2, 8, 9, 10, 1, 2, 3, 1, 2, 2, 9, 9, 10, 3, 5, 5];
Array.prototype.unique = function() {
    var obj = {};
    var newArr = [];
    for (var i = 0; i < this.length; i++) {
        if (!obj[this[i]]) { // 把數組裏的值當做對象的屬性名,第一次出現對象當中沒有這個屬性,取非進入循環
            newArr.push(this[i]); //把這個進入循環的數推入新數組
            obj[this[i]] = true; // 做標記,再出現時無法進入循環
        }
    }
    return newArr;
}
var newArr = arr.unique();

//39 try catch------------------------------------------------------------------------------------------------

//錯誤類型     ReferenceError 使用一個變量,變量還沒有沒定義聲明
//            RangeError  數值越界,遞歸沒有出口
//            SyntaxError  語法解析錯誤   多寫少寫括號
//            TypeError   類型錯誤   類型調用本身沒有的動作

try {
    console.log(a);
    a = 10;
} catch (e) {
    console.log(e);
    //ReferenceError: a is not defined
    //at test.html:15
    console.log(e.name, e.message);
    //ReferenceError a is not defined
} finally {
    console.log('over');
}






發佈了44 篇原創文章 · 獲贊 2 · 訪問量 5030
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章