奇舞 javaScript-变量值与类型- 笔记

Data Type & Values

algorithms within this specification manipulate values each of which has an associated type are exactly those defined in this clause Types are further subclassified into ECMAScript language types and specification types

这里写图片描述

弱类型、强类型、动态类型、静态类型语言的区别是什么?

关于JS 类型的几点说明

  • JavaScript 是动态类型 + 弱类型的语言
  • JavaScript 的变量, 属性在运行期决定类型
  • JavaScript 存在隐士类型转换
  • JavaScript 有一系列识别类型的反射方法

Language Types

An ECMAScript language type corresponds to values that are directly manipulated by an ECMAScript programmer using the ECMAScript language the ECMAScript language types are ,Undefined, Null, Boolean ,String, Symbol ,Number, and Object,An ECMAScript language value is value that is characterized by an ECMAScript language type

    typeof undefined === 'undefined'
    typeof true === 'boolean'
    typeof 123 === 'number'
    typeof 'username' === 'string'
    typeof { team: '75team' } === 'object'
    typeof Symbol() === 'symbol'

    typeof null === 'object'

    typeof function() {} === 'function'

function

a primitive value is a member of one of the following built-in types:undefined ,Null, Boolean, Number, String, and Symbol; an object is a member of the builtin type Object ;and a function is a callable object

Undefined
Null
Number
String
Symbol
Object < function

变量声明

根据规范, JavaScript 有三种变量声明的方法:

  • var -声明一个变量, 可选择将其初始化为一个值
  • let -声明一个块级作用域变量, 可选择将其初始化为一个值
  • const - 声明一个块级作用域只读的常量

使用 var 的注意事项

  • var 不支持块级作用域
  • var 存在变量提升 (Variable hoisting)
    console.log(a === undefined); //true
    var a = 10;

    function foo() {
        var a = 20;

        for (var i = 0; i < a; i++) {
            //do sth.
        }
        console.log([a, i]) //[20, 20]
    }
    foo()

使用 let 的注意事项

  1. 块级作用域
  2. 同一作用域不允许重复声明
  3. 暂存死区(Temporal dead zone)
  4. 浏览器兼容性

块级作用域和重复声明

    {
        let x = 16;
        console.log('x is' + x); //x is16
    }
    console.log(typeof x) //  undefined

    let i = 20;
    for (let i = 0;i < 10; i++) {
       console.log(i) // 0 1 2 3 4 5 6 7 8 9
    }
    var y = 3 ;
    var y = 4 ;
    console.log(y); //4 

    let z = 3;
    var z = 4;
    console.log(z)  //SyntaxError: Identifier 'z' has already been declared 重复声明
    let x = 10;
    function foo() {
        console.log(x); //ReferenceError: x is not defined
        let x = 20; //如果变成var 会怎样?
        return x * x;
    }
    console.log(foo())
    let x = 10;

    function foo() {
        console.log(x); // undefined
        var x = 20;
        return x * x;
    }
    console.log(foo()) //400

    let x = 10;

    function foo() {
        console.log(typeof x); //ReferenceError: x is not defined
        let x = 20; //如果变成var 会怎样?
        return x * x;
    }
    console.log(foo())
  let x = 10;
    function foo() {
        console.log(typeof x); // undefined
        var x = 20; //如果变成var 会怎样?
        return x * x;
    }
    console.log(foo()) //400

循环(let 的词法作用域)

    <button type="">点我</button>
    <button type="">点我</button>
    <button type="">点我</button>
    <button type="">点我</button>
    <button type="">点我</button>
    <button type="">点我</button>

    var buttons = document.querySelectorAll('button')
    console.log(buttons);
    for (var i = 0; i < buttons.length; i++) {
        buttons[i].onclick = evt => console.log('点击了第' + i + '个按钮')
    }
    // 无论点击哪个按钮都会打印 点击了第6个按钮
    var buttons = document.querySelectorAll('button')
    console.log(buttons);
    for (let i = 0; i < buttons.length; i++) {
        buttons[i].onclick = evt => console.log('点击了第' + i + '个按钮')
    }
    //会提示打印点击了对应的按钮
//通过闭包形成块级作用域
    var buttons = document.querySelectorAll('button')
    console.log(buttons);
    for (var i = 0; i < buttons.length; i++) {
       (function (i) {
          buttons[i].onclick = evt => console.log('点击了第' + i + '个按钮')
       })(i)
    }

使用const 的注意事项

  • const 声明的标识符所绑定的值不可以再次改变
  • ES6 const 的其它行为和 let 一样
    const BUFFER_SIZE = 1024;

    let buffer = new ArrayBuffer(BUFFER_SIZE);
    let data = new Uint16Array(buffer);
    let data2 = new Uint8Array(buffer);
    data[0] = 0xff0f;

    console.log(data2[0], data2[1]) //6 255
BUFFER_SIZE= 111 //TypeError: Assignment to constant variable.

var A = Object.freeze({a:1})
A.a = 2
console.log(A) //{a: 1}

不声明直接用会怎样?

  • 非严格模式
  • 严格模式

    不声明直接使用

    (function() {
        'use strict';
        var x = y = 0;

        //do sth.
    })();
    console.log([typeof x, typeof y]);
    // ReferenceError: y is not defined
    (function f(j = 0) {
        'use strict';
        var x = i = 0;

        //do sth.
    })();
    console.log([typeof x, typeof y]);
    // SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list
    (function f(j) {
        'use strict';
        var x, i = 0;

        //do sth.
    })();
    console.log([typeof x, typeof y]); //["undefined", "undefined"]
    (function f(j=007) {
        'use strict';
        var x, i;

        //do sth.
    })();
    console.log([typeof x, typeof y]);
    // SyntaxError: Illegal 'use strict' directive in function with non-simple parameter list

抽象相等

严格相等与非严格相等

  • null==undefined, null!== undefined
  • 非严格相等的类型转换
  • NaN与任何值(包括自身)都不想等
console.log([null !==undefined,null==undefined]) // [true, true]

console.log(['1'==1, [] ==0, ''==0, 0==false, 1==true]) //[true, true, true, true, true]

console.log([NaN!=NaN]) // [true, true]

Boolean 类型

  • true 和false
  • 0, ”, null, undefined, 被隐式转换为false,其它转为true
  • 建议采用严格比较,可以通过!! 将非boolean 值转为boolean
  • 布尔操作符 && 和 || 并不会转换类型
  • && 和 || 的短路特性
  • 比较操作符总是返回boolean类型
var a = []
if(a){console.log('a')} //a
console.log(!![]) //true
    var result = 1 && 2 ;  //2
    console.log([result,!!result]); //  [2, true]

    var list = [1,,2,,,4,5,0,9];
    list =list.filter(item => item)

    console.log(list); // [1, 2, 4, 5, 9]

    function showTip(tip) {
        tip = tip || "This is a tip";
        console.log(tip);
        var label = document.createElement('label');
        label.className = 'tip';
        label.innerHTML = tip;

        document.body.appendChild(label);
    }

    document.querySelector('button').onclick = showTip.bind(null, '');
    <div class="ball"></div>

    .ball{
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background-color: red;
    }

function applyAnimate(el, duration, options, easing) {
    var startTime = Date.now();
    if (typeof el === 'string') {
        el = document.querySelector(el);
    }
    duration = duration || 1000;
    options = options || {
        property: 'x',
        distance: 100
    };
    easing = easing || function(p) { return p; };

    requestAnimationFrame(function update() {
        var now = Date.now();
        var p = (now - startTime) / duration;
        var ep = easing(p)

        if (typeof options !== 'function') {
            var attr = options.property,
                distance = options.distance;
            var translate = [];
            if (attr.indexOf('x') >= 0) {
                translate.push('translateX(' + distance * ep + 'px)');
            }

            if (attr.indexOf('y') >= 0) {
                translate.push('translateY(' + distance * ep + 'px)');
            }
            el.style.transform = translate.join(' ');
        }else {

            options(el, ep, p);
        }
        if (p <= 1) {
            requestAnimationFrame(update);
        }
    });
}

document.querySelector('.ball').onclick = function(){
    applyAnimate('.ball');
}

Number

  • 数值范围

    • 整数 -2^53 ~ 2^53
    • 小数精度 Number.EPSILON
    • Infinity, Number.MAX_VALUE , Number.MIN_VALUE
  • 浮点数精度问题

  • 二进制,八进制, 十进制, 十六进制
  • +0和-0
//Integer 整数
Number.MAX_VALUE; //1.7976931348623157e+308
Number.MIN_VALUE; //5e-324
var bigInteger = Number.MAX_SAFE_INTEGER + 1; //9007199254740992
1234567890000000000000000000 //科学计算法  1.23456789e+27
bigInteger; //9007199254740992
bigInteger + 1; //9007199254740992
bigInteger + 2 ; //9007199254740994
Math.pow(2, 53) === bigInteger; // true
Number.isSafeInteger(bigInteger); //false
Number.isSafeInteger(bigInteger - 1); //true
Number.MAX_VALUE //1.7976931348623157e+308
Number.MIN_VALUE //5e-324
Number.MAX_VALUE + 1; // 1.7976931348623157e+308
Number.MAX_SAFE_INTEGER + 2; // 9007199254740992
Number.EPSILON; //2.220446049250313e-16
0.99 - 1e-17 === 0.99;  //true
0.99 - Number.EPSILON === 0.99; // false

浮点数精度

console.log(0.2 + 0.4); // 0.6000000000000001
console.log(((0.2+ 0.4)+ 100).toPrecision(2)); // 1.0e+2
console.log(((0.2+ 0.4)+ 100).toFixed(2)); // 100.60

二 八 十六进制

function foo() {
    var oNum = 1011,
        num = 256;

    console.log([oNum, num.toString(8), num.toString(16)]); // [1011, "400", "100"]
}
foo()

二进制数与位操纵

https://leetcode.com/problems/power-of-four/description/


var isPowerOfFour = function(num) {
    return num > 0 && (num & (num-1)) ===0
                   && (num & 0xAAAAAAAA) ===0
};

console.log(isPowerOfFour(65536)) //true

String

  • 引号规范
  • 转义字符
  • 字符串字符
  • 字符串与类型转换
  • 常用字符串操作
  • 模版字符串

    引号规范与转移

    var text = 'This is a text'; //建议使用单引号 方便字符串拼接

    var html = '<p class="sth">This is a <em>paragraph</em></p>';

    console.log(text);
    console.log(html);

    var text2 = '我做的煎饼\n是全天下\n最好吃的';

    console.log(text2);

    var text3 = 'if(a){\n\tconsole.log(b);\n}';

    console.log(text3);

    var text4 = '\u5947\u821e\u56e2';

    console.log(text4);

处理字符

    var str = 'my string';

    console.log(str.charAt(5)); // 5 

    var charArray = Array.from(str) //str.split('')

    console.log(charArray); // ) ["m", "y", " ", "s", "t", "r", "i", "n", "g"]

    console.log(str.charCodeAt(5), str.charCodeAt(6)) // 114 105

    console.log(String.fromCharCode(114, 105)); //ri

    console.log(String.fromCharCode(...charArray.map(c => c.charCodeAt(0)))) //my string

字符串类型转换

        console.log([1+2,'1'+2, '1'-2]) // [3, "12", -1]

        console.log(parseInt('100abc',2),Number('0b100')); //转整数 4 4

        console.log(parseFloat('12.3e10xx')) //转浮点数  123000000000

        var foo = { //对象的toString 方法
            toString(){
                return 'foo';
            }
        };
        console.log(foo+ ' bar') //foo bar

字符串常用操作

       const a = 'hello';
       const b = 'WORLD';
       const c = '!';

       console.log(a + ' ' + b + c); //hello WORLD!

       console.log(a.toUpperCase() + ' ' + b.toLowerCase() + c) //转大小写 HELLO world!

       console.log(a.split('').reverse().join('')) //逆转字符串  olleh

       console.log(a.slice(2, 3), a.substr(2, 3)) // 截取子串 l llo

       const  d = a + ' ' + b + c;  

       console.log(d.indexOf(b)); //字符串查找 6

       console.log(d.replace(a, a.toUpperCase())); //字符串替换 前面第一个参数可以是正则表达式 HELLO WORLD!

模版字符串(ES6)

    const tpl1 = `我所做的馅饼
     是全天下
     最好吃的`;

    console.log(tpl1, typeof tpl1);
    // 我所做的馅饼
    // 是全天下
    // 最好吃的 string 

    {
        let who = '月影',
            what = '月饼';

        const tpl2 = `${who}所做的${what}
            是全天下
            做好吃的    
          `;

        console.log(tpl2);

        // 月影所做的月饼
        //     是全天下
        //     做好吃的  

    }

模版字符串高级用法

    let output = (a, b) => `${a} + ${b} is ${a + b}`;

    console.log(output(3, 5)); // 3 + 5 is 8


    let formatedList = (data) => `
      <ul>
        ${data.map(item => `
             <li>
             <span> 姓名:${item.name}</span> <span>年龄: ${item.age}</span>
             </li>
            `).join('')}
      </ul>
     `;

    let data = [
        { name: 'Akira', age: 22 },
        { name: 'Jame', age: 32 },
        { name: 'Jhon', age: 66 },
    ];

    console.log(formatedList(data));


      <ul>

             <li>
             <span> 姓名:Akira</span> <span>年龄: 22</span>
             </li>

             <li>
             <span> 姓名:Jame</span> <span>年龄: 32</span>
             </li>

             <li>
             <span> 姓名:Jhon</span> <span>年龄: 66</span>
             </li>

      </ul>

Object

  • 对象的属性
  • 值和引用
  • 类型与构造器
  • 内置类型
  • 对象的高级属性
  • class- 这个放在后续专门的章节去讲

对象的属性

  • 属性名规则:可以有效字符串或者任意可以转换有效字符串的类型
  • 属性的访问了遍历

    对象创建

    //创建对象 
    {
        let myObj = new Object();

        myObj.name = 'akira';
        myObj.birthday = '12-12';

        console.log(myObj);
    }
    // 然而上面写的是菜鸟 ,普通青年这么写

    {
        let myObj = {
            name: 'akira',
            birthday: '12-12'
        };

        console.log(myObj);
    }
    // 有些二逼青年:
    {
        let myObj = Object.create({
            name: 'akira',
            birthday: '12-12'
        });

        console.log(myObj);
    }

属性访问

    //对象属性是有效字符串颗,可以通过. 和[]
    {
        let myObj = new Object();

        myObj.name = 'akira';
        myObj.birthday = '12-12';

        console.log(myObj.name, myObj['birthday']);
    }
    // [] 属性访问的好处是可以计算

    {
        const conf = {
            adapter: 'sqlite',
            db: {
                sqlite: {
                    //...
                },
                mysql: {
                    //...
                }
            }
        }
        let daSetting = conf.db[conf.adapter];
    }


{
        // 在ES6 中字面量的key 也支持属性计算

    let process = {env: {}};

    const ENV = process.env.JSBIN_ENV || 'development'; 

    const conf = {
        [ENV]: true
    };

    console.log([conf.development, conf.production]) //[true, undefined]
}

值和引用

   let x = 20, y = 30;

   function foo(a, b) {
        a++;
        b++;
        console.log([a, b]); //21 31
    } 

   foo(x, y);

   console.log([x, y]); //20 30

 const obj = {x: 20, y: 30}

   function foo2(obj) {
     obj.x++;
     obj.y++;
     console.log(obj); //{x: 21, y: 31}
   }
   foo2(obj);

   console.log(obj); //{x: 21, y: 31}

基本类型和包装类

 var str = "Hello World";
 var strObj = new String(str);

 console.log(str, strObj); // Hello World String {"Hello World"}
 console.log([typeof str, typeof strObj]); // ["string", "object"]
 console.log([str instanceof String, strObj instanceof String, strObj instanceof Object]); // [false, true, true]


 var n = new Number(10);

 console.log([typeof n , typeof ++n]); // ["object", "number"]
  console.log(Object.prototype.toString.call(10)); //[object Number]

对象的拷贝

let conf = {
    adapter: 'sqlite',
    db: {
        sqlite: {
            name: 'xxx.sqlite'
        },
        mysql: {
            name: 'xxx',
            username: 'work',
            password: '******'
        }
    }
};

//直接引用

let conf2 = conf;
conf2.adapter = 'mysql';

console.log(conf.adapter); // mysql

// ES5 浅拷贝

conf.adapter = 'sqlite';

let copied = Object.assign({}, conf);
copied.adapter = 'mysql';

console.log(conf.adapter);
console.log(copied.adapter);

copied.db.mysql.name = '123';

console.log(conf.db.mysql.name);

//深拷贝

function deepCopy(des, src) {
    for (var key in src) {
        let prop = src[key]
        if (typeof prop === "object") {
            des[key] = des[key] || {};
            deepCopy(des[key], prop)
        } else {
            des[key] = src[key];
        }
    }
    return des;
}

let deepCopied = deepCopy({} , conf);
deepCopied.db.sqlite.name='zzz.sqlite';

console.log([deepCopied.db.sqlite.name, conf.db.sqlite.name]);

对象的类型与构造器

  • new和constructor
  • prototype
  • instancoOf
  • ES6 class

    对象的构造器

// 假设js没有‘new’ 操作符 我们该如何实现创建对象

function defineClass(initializer, proto) {
    return function f(...args) {
        let obj = Object.create(proto);

        //f.prototype = proto; just let instaceof make sense

        obj.constructor = initializer;
        obj.constructor(...args);
        return obj;
    }
}

var Point = defineClass(function(x, y) {
    this.x = x;
    this.y = y;
}, {
    getLength: function() {
        let { x, y } = this;
        return Math.sqrt(x * x  + y * y);
    }
});

var p = Point(3, 4);

console.log([p.getLength(), p instanceof Point, p instanceof Object]);

//[5, false, true]

原型链

// 使用__proto__ 暴力构建原型链

var a = { x: 1 },
    b = { y: 2 },
    c = { z: 3 }

b.__proto__ = a;
c.__proto__ = b;

console.log(c); //{x:1, y=2, z=3}

// 使用Object.create 构建原型链

var a = { x: 1 };
var b = Object.create(a);
b.y = 2;
var c = Object.create(b);
c.z = 3;

console.log(c); // //{x:1, y=2, z=3}

// 使用构造器方式 
function A() {
    this.x = 1;
};

function B() {
    this.y = 2;
}

B.prototype = new A();

function C() {
    this.z = 3;
}
C.prototype = new B();

var c = new C();

console.log(c);

问题: 额外的构造器调用?

// 原型继承
/*
 * abstract point
 */

function Point(components) {
    console.log('Point constructor called');
    this.components = components;
}

Point.prototype = {
    getDimension: function() {
        return this.components.length;
    },
    getLength: function() {
        var sum = 0,
            components = this.components;
        for (var i = 0; i < components.length; i++) {
            sum += Math.pow(components[i], 2);
        }
        return Math.sqrt(sum);
    }
}

function Point2D(x, y) {
    Point.call(this, [x, y]);
}

Point2D.prototype = new Point();


Point2D.prototypegetXY = function() {
    var components = this.components;

    return {
        x: components[0],
        y: components[1]
    };
};

var p = new Point2D(3, 4);

console.log(p);


console.log([p + '', p.getLength(), p instanceof Point]); 

// Point constructor called
// Point constructor called
// ["[object Object]", 5, true]
Point2D.prototype = new Point();
//修改为
Point2D.prototype = Object.create(Point.prototype);
//或者
var PointProto = function(){}
PointProto.prototype = Point.prototype;
Point2D.prototype = new PointProto()

这里写图片描述

高级属性

  • getter 和 setter
  • 属性描述符号

    从为什么不建议修改Object.prototype 和Array.prototype 讲起
    在类型(或对象) 上添加方法的代码

Array.prototype.remove = function(item) {
    var idx = this.indexOf(item);

    if (idx > 0) {
        return this.splice(idx, 1)[0]
    }
    return null;
}

var arr = [1, 2, 3];

arr.remove(2);

console.log(arr);

for (var i in arr) {
    if (!Number.isNaN(i - 0)) {
        console.log(i + ':' + arr[i]); //0:1  1:3

    } else {
        console.log(i + '是什么鬼?'); // remove是什么鬼?
    }
}

解决这一问题的方法

  • 禁止使用for…in 操作数组,只能用for 或者Array.prototype.forEach
  • 禁止网数组上随便添加方法
  • …禁止1 +2 (防止自己和防止别人)
  • …使用ES5 新特性
Object.defineProperty(Array.prototype, 'remove', {
    value: function(item) {
        var idx = this.indexOf(item);

        if (idx > 0) {
            return this.splice(idx, 1)[0]
        }
        return null;
    },
    // enumerable: true
})
var arr = [1, 2, 3];

arr.remove(2);

console.log(arr);

for (var i in arr) {
    if (!Number.isNaN(i - 0)) {
        console.log(i + ':' + arr[i]); //0:1  1:3

    } else {
        console.log(i + '是什么鬼?'); // remove是什么鬼?
    }
}

//让enumerable 为false  不可枚举

getter / setter

function Point2D(x, y) {
    this.x = x;
    this.y = y;
}

Object.defineProperty(Point2D.prototype, 'length', {
    get: function() {
        let { x, y } = this;
        return Math.sqrt(x * x + y * y);
    },
    set: function(len) {
        let arc = Math.atan2(this.y, this.x);
        this.x = len * Math.cos(arc);
        this.y = len * Math.sin(arc);
    }
});
Object.defineProperty(Point2D.prototype, 'arc', {
    get: function() {
        let { x, y } = this;
        return 180 * Math.atan2(y, x) / Math.PI;
    },
    set: function(arc) {
        arc = Math.PI * arc / 180;
        let len = this.length;
        this.x = len * Math.cos(arc);
        this.y = len * Math.sin(arc);
    }
});

let p = new Point2D(1, 1);
console.log([p.length, p.arc]); // [1.4142135623730951, 45]
p.length *= 2;
console.log([p.x, p.y]); // [2.0000000000000004, 2]
p.arc = 90;;
console.log([p.x, p.y]); // [1.7319121124709868e-16, 2.8284271247461903]

数据绑定视图

// geter/setter 与数据双向绑定

const view = {
    nameEl: document.getElementById('name'),
    ageEl: document.getElementById('age'),
    submitBtn: document.getElementById('confirm')
};

view.submitBtn.addEventListener('click', function() {
    console.log('你要提交的数据是' + [user.name])
});

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

User.prototype.bind = function(view) {
    view.nameEl.addEventListener('change', evn => {
        this.name = evn.target.value;
    });
    view.ageEl.addEventListener('change', evn => {
        this.age = evn.target.value;
    })
}

Object.defineProperty(User.prototype, 'name', {
    set: function(name) {
        view.nameEl.value = name;
    },
    get: function() {
        return view.nameEl.value;
    }
});

Object.defineProperty(User.prototype, 'age', {
    set: function(age) {
        view.ageEl.value = age;
    },
    get: function() {
        return view.ageEl.value;
    }
})


var user = new User('akira', '80后');

user.bind(view);

其它高级用法

MDN Object.defineProperty()

Symbol

  • ES6 新类型
  • 生成唯一标示
  • 用作对象的key
  • Symbol.for
  • Symbol 的基本用法
  • 系统内置 Symbol

    扩展阅读
    MDN:Symbol

总结
这节课讲了什么?
变量的声明
javaScript 的内置类型 包括:

null, undefined, boolean, number, string, object, symbol

作业

阅读
MDN javaScript指南, javaScript 参考文档(一个月内完成)

完成几个 javaScript 小练习

练习1

在电商购物网站上经常有购物卡出售,购物卡是一种可以充值的卡片,上面通常有20位密码,为了方便阅读以连字符分割, 例如: 3EFU8-RT67F-E420P-8RPOL

要求:用javaScript 实现一个函数, 读取用户输入的字符串,替换掉连字符,将小写字符转化为大些字母, 然后判断是否是20位,若是, 将转换为的字符串返回,否则抛出格式异常错误。

示例输入:3efu8-rt67g-e42op-8rpol
函数结果:返回: 3EFU8RT67FE420P8RPOL

示例输入:hello world
函数结果:异常: 无效的密码格式

练习2

网站上让用户给出要一组兴趣爱好选项,是以半角逗号分割的字符串,例如:’游泳, 健身, 舞蹈 ,阅读’

为了确保输入重复的项目, 要求实现一个函数, 对字符串中兴趣的内容去重

示例输入:’游泳,健身,篮球,游泳,篮球,阅读’

输入: ‘游泳,健身,篮球,阅读’

练习3

运行的同学策划一个活动,2017年2月的那个星期三10点整点都做促销秒杀,从下载开始倒计时

要求实现一个函数, 返回一个数组, 内容是2017年2月的每个星期三是2月几号,它门距离今天还有几天

示例输入:

[{
        data: '2017/2/1',
        daysBefore: 40
    },
    {
        data: '2017/2/1',
        daysBefore: 40
    }
]

练习4

https://leetcode.com/ 上练习题

自选5道题独立完成, 并简单写下思路颗心得总结,参考

https://www.h5jun.com/post/counting-bits.html

练习5

自学使用JS操作DOM的基本方法

对之前自己写的3-5 个页面的小网站增加一些js交互

要求不用任何框架,用原生JS写 ,支持最新浏览器即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值