面向对象的程序设计

理解对象

Object.defineProperty(操作对象, 操作属性, 属性类型) IE8及以下不要使用
Object.defineProperties(操作对象, {}) 同事可以定义多个属性 支持IE9+
Object.getOwnPropertyDescriptor(操作对象, 属性)

属性类型

  • [[configurable]]: 是否可以配置, 能够通过delete删除属性, 修改其属性特性(可以理解为修改属性名), 默认true
  • [[enumerable]]: 表示能否通过for-in遍历, 默认true
  • [[writable]]: 表示能否修改属性的值
  • [[value]]: 属性的数据值, 默认undefined
1
2
3
4
5
6
7
8
9
10
var obj = {}
Object.defineProperty(obj, "name", {
writable: false,
value: "hello"
});
console.log(obj)//Object {name: "hello"}
obj.name = 'world'
console.log(obj)//Object {name: "hello"}
// 一下就配置了writable和value, 没有配置configurable和enumerable 那么这两个值默认为false了
delete obj.name //false

访问器属性

getter setter

  • [[configurable]]: 是否可以配置, 能够通过delete删除属性, 修改其属性特性(可以理解为修改属性名), 默认true
  • [[enumerable]]: 表示能否通过for-in遍历, 默认true
  • [[get]]: 在读取属性时调用的函数, 默认undefined
  • [[set]]: 在写入属性时调用的函数, 默认undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var obj = {_age: 20}
//get和set方法 忽略其中一个方法, 说明那方法设置为false
Object.defineProperty(obj, "age", {
get: function() {
return this._age;
},
set: function(newVal) {
if (newVal > 18) {
this._age = 18;
} else {
this._age = newVal;
}
}
});
obj.age = 55 //18
obj.age = 16 //16

创建对象

创建对象的几种方式

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name, age) {
this.name = name;
this.age = age;
this.getName = function() {
return this.name;
}
}
var p1 = new Person('p1', 18);
//--
var obj = new Object();
Person.call(obj, 'p2', 18);
obj.getName() //'p2'

为什么要用原型的方式实例化

原型继承可以共享属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//普通的
function Person(name, age) {
this.name = name;
this.age = age;
//这种方式等价于 new Function("return this.name;"); 当实例多个对象时, 此方法也被实例了多次, 不公用一个方法
this.getName = function() {
return this.name;
}
}

//原型链的
function Person(name, age) {
this.name = name;
this.age = age;
}
//如果使用原型链继承的方式, 就可以共用同一个方法
Person.prototype.getName = function() {
return this.name;
}

获取原型的方法

构造方法.prototype === Object.getPrototypeOf(实例对象)

1
2
3
4
5
6
7
8
9
10
11
function Person() {
}
Person.prototype.getName = function() {
return this.name;
}

ver person = new Person;

Object.getPrototypeOf(person) === Person.prototype //true
//判断是否是某一对象的原型
Person.prototype.isPrototypeOf(person) //true

修改原型上的属性值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Person() {
}
Person.prototype.name = 'hello'
var person = new Person();

//默认使用原型上的值
person.name; //hello
person.hasOwnProperty('name');//false
//覆盖原型上的值
person.name = 'world';
person.name;// world
person.hasOwnProperty('name');//true
//删除自定义的值
delete person.name; //true
//重新指向原型上的值
person.name; //hello
person.hasOwnProperty('name');//false

Object.getOwnPropertyNames() 与 Object.keys()的区别

Object.keys()只能获取可以枚举的key
Object.getOwnPropertyNames() 可以获取所有key(不包括原型链上的key)

使用对象字面量原型继承

使用这种方式会将constructor的指向改变为Object, 因为原型直接被一个对象覆盖

1
2
3
4
5
6
7
8
9
Test.prototype = {
name: 'zhichen'
}

test.constructor == Test //false
test.constructor == Object//true

test instanceof Test //true
test instanceof Object //true

为了避免这种问题, 我们需要手动改变constructor指向, 但是这样会使这个key的枚举性变为true(默认是false)

1
2
3
4
5
6
7
8
9
10
11
Test.prototype = {
constructor: Test,
name: 'zhichen'
}
test.constructor == Test //true
test.constructor == Object//false

test instanceof Test //true
test instanceof Object //true

Object.keys(Test.prototype)// ["constructor", "name"]

所以正确的姿势如下

1
2
3
4
5
6
7
8
Test.prototype = {
name: 'zhichen'
}
Object.defineProperty(Test.prototype, "constructor", {
enumerable: false,
value: Test
});
Object.keys(Test.prototype)//["name"]

原型的动态

由于每个对象当没有找对对应的key时都会去原型链上查找, 所以当我们动态改变原型上的属性, 会有可能直接影响到对象, 即使先实例对象
对象和原型之间的关系, 是用指针链接的, 而不是副本形式

1
2
3
4
5
6
7
8
9
10
Test.prototype = {
constructor: Test,
name: 'zhichen'
}
var test = new Test()
test.sayHi(); //ERROR
Test.prototype.sayHi = function(){
console.log("hello wolrd");
}
test.sayHi()//hello world

使用字面量对象赋值, 会改变构造函数原型指针指向, 重新指向新原型对象, 但是之前实例化的对象还是指向原来的原型对象, 所以无法获取新原型对象的属性

1
2
3
4
5
6
7
8
9
10
function Test(){}
var test = new Test()
Test.prototype = {
constructor: Test,
name: 'zhichen',
sayHi: function() {
console.log("hello world");
}
}
test.sayHi()//ERROR

原型对象的问题

因为原型对象是公用同一个对象, 所以当对对象进行操作时, 会影响到其他对象的结果

1
2
3
4
5
6
7
8
9
function Test(){}
Test.prototype.hobby = [];
var t1 = new Test()
var t2 = new Test()
console.log(t1.hobby)//[]
console.log(t2.hobby)//[]
t1.hobby.push('coding');
console.log(t1.hobby)//["coding"]
console.log(t2.hobby)//["coding"]

组合使用构造函数模式和原型模式

这种模式, 每个实例都有自己的一份实例属性的副本, 但同时共享着对方法的引用, 这样最大限度的节约了内存, 同时构造方法可以接受传参实例化, 也避免了引用类型属性改变引发污染其他对象属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Test(name, age) {
this.name = name;
this.age = age;
this.hobby = [];
}
Test.prototype.sayName = function() {
console.log('my name is ' + this.name)
}
var t1 = new Test('a', 1)
var t2 = new Test('b', 2)
console.log(t1.hobby)//[]
console.log(t2.hobby)//[]
t1.hobby.push('coding');
console.log(t1.hobby)//["coding"]
console.log(t2.hobby)//[]
t1.sayName()//"a"
t2.sayName()//"b"
console.log(t1.sayName === t2.sayName)//true
console.log(t1.hobby === t2.hobby)//false

寄生构造函数模式

与工厂模式类似

1
2
3
4
5
6
7
8
9
10
11
12
function Test(name, age) {
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function() {
console.log(this.name)
}
return o;
}

var test = new Test('test', 1);
test.sayName();//"test"

继承

原型链

需要注意的一点是: property其实是SubType.prototype上的属性, 因为SuperType的实例复制给了SubType.prototype, 而getSuperValue还是在SuperType.prototype上; 因此这样会导致引用类型的值会被共享; 而且无法区分他们是父类还是子类的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function SuperType() {
this.property = true;
this.hobby = [];
}
SuperType.prototype.getSuperValue = function() {
return this.property;
}
function SubType() {
this.subProperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
return this.subProperty;
}
var instance = new SubType();
console.log(instance.getSuperValue())//true
var instance2 = new SubType();
instance2.hobby.push('coding');
console.log(instance.hobby)//["coding"]
console.log(instance2.hobby)//["coding"]
instance instanceof SuperType//true
instance instanceof SubType//true

借用构造函数

解决父类引用类型在继承时共享
在子类中call父类, 这样子类的每个实例都会有父类的属性副本;
还有一个好处就是: 给父类构造函数传参的值可以根据不同的子类实例对象不同而改变;
也能够区别是父类还是子类的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function SuperType(name) {
this.name = name;
this.hobby = [];
}
function SubType(name) {
//继承了SuperType
SuperType.call(this, name);
}
var instance1 = new SubType('hello');
var instance2= new SubType('world');
instance1.hobby.push('coding');
console.log(instance1.hobby)//["coding"]
console.log(instance2.hobby)//[]
console.log(instance1.name)//"hello"
console.log(instance2.name)//"world"
instance1 instanceof SuperType//false
instance1 instanceof SubType//true

原型式继承

它对传入的对象是潜复制, 因此会导致引用属性对象会被共享;
它的功能和Obejct.create()行为相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var obj = {
name: 'hello',
hobby: []
}
var instance1 = object(obj);
var instance2 = object(obj);
instance1.hobby.push('coding');
console.log(instance1.hobby)//["coding"]
console.log(instance2.hobby)//["coding"]
var instance3 = Object.create(obj)
var instance4 = Object.create(obj)
instance3.hobby.push('running');
console.log(instance3.hobby)//["coding", "running"]
console.log(instance4.hobby)//["coding", "running"]

寄生组合式继承

最理想的继承方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function inheritProtoType(subType, superType) {
var prototype = Object.create(superType.prototype);
prototype.constructor = subType;
//子类的原型指向了父类的原型, 当在父类的原型上添加新方法时, 子类也能够调用
subType.prototype = prototype;
}

function SuperType(name) {
this.name = name;
this.colors = ["red"];
}
function SubType(name, age) {
//这里让父类的属性成为自己的副本
SuperType.call(this, name);
this.age = age;
}

inheritProtoType(SubType, SuperType);
SubType.prototype.sayAge = function() {
console.log(this.age);
}

var instance1 = new SubType('hello', 1)
var instance2 = new SubType('world', 2)
instance1.colors.push("green");
instance1.colors;//["red", "green"]
instance2.colors;//["red"]

SuperType.prototype.sayName = function() {
console.log(this.name);
}
instance1.sayName()//"hello"
instance2.sayName()//"world"

引用类型

String对象

slice substr substring方法的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//当只有一个参数时 结果都一样
//第二个参数为正数时
var str = 'hello world';
str.slice(2, 4); //"ll" 第二位标识位置
str.substring(2, 4); //"ll" 第二位标识位置
str.substr(2, 4); //"llo " 第二位标识截取位数

当第二个值为负数
str.slice(2, -4); //"llo w" 倒数第四位
str.substring(2, -4); //"he" 负数会被当成0
str.substr(2, -4); //"" 负数会被当成0

//当只有一个负数时
str.slice(-4); //"orld" 倒数第四位
str.substring(-4); //"hello world" 返回所有字符串
str.substr(-4); //"orld" 倒数第四位

fromCharCode()方法

1
2
3
//可以将编码转换成字符 charCodeAt相反
'a'.charCodeAt()//97
String.fromCharCode(97)//'a'

RegExp正则对象

字符串的模式匹配方法

1
2
var str = "hello world";
str.replace(/(el)/, '$1$1')//"helello world"
字符序列 替换文本
$$ $
$& RegExp.lastMatch
$’ RegExp.leftContext
$` RegExp.rightContext
$n $n(n等于0-9)
$nn $nn(n等于01-99)

单体内置对象

已经被实例化 无所开发再手动实例化 例如 Object, Array, String, Global(window), Math

encodeURI 与 encodeURIComponent 区别

decodeURI decodeURIComponent 功能相反
以上方法 用于替换 escape unescape 此两方法已废弃

1
2
3
var str = 'http://www.test.com/test?hello=wo rld'
encodeURI(str)//"http://www.test.com/test?hello=wo%20rld" 自替换空格
encodeURIComponent(str)//"http%3A%2F%2Fwww.test.com%2Ftest%3Fhello%3Dwo%20rld" 替换所有非字幕数字字符

Vue

Vue对象

  • data 绑定数据

    1
    2
    3
    4
    5
    6
    7
    data () {
    return {
    msg: 'Welcome to Your Vue.js App',
    items: JSON.parse(localStorage.getItem('data')) || [],
    newItem: ''
    }
    },
  • methods vue对象方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    methods: {
    clickEvent: function (item) {
    item.flag = !item.flag
    },
    addNew: function() {
    console.log(this.newItem)
    this.items.push({
    message: this.newItem,
    flag: false
    })
    this.newItem = ''
    }
    }
  • watch 监听某个变量, 当发生变化时, 回调函数

    1
    2
    3
    4
    5
    6
    7
    8
    watch: {
    items: {
    handler: function (val, oldVal) {
    localStorage.setItem('data', JSON.stringify(val))
    },
    deep: true
    }
    },
  • props 注册的属性, 不注册既是传递了属性在 组件里也无法获取

  • component 需要注册的组件, 不注册只引入组件是无效的
    • 在模板里, 组件的名字需要被反驼峰使用MyComponent => <my-component></my-component>

重要指令

  • v-text 渲染数据(不会解析html标签)
  • v-html 渲染数据(会渲染html标签)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <template>
    <div class="hello">
    //两者等价
    <h1>{{ title }}</h1>
    <h1 v-text="title"></h1>
    </div>
    </template>
    <script>
    export default {
    name: 'hello',
    data () {
    return {
    title: 'this is title <div>div</div>'
    }
    }
    }
    </script>
  • v-if 控制显示

  • v-on 绑定事件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <li v-for="item in items" v-on:click="clickEvent(item)">{{item.message}}</li>
    <script>
    export default {
    name: 'hello',
    data () {
    return {
    msg: 'Welcome to Your Vue.js App',
    items: [{message: 'react'}]
    }
    },
    methods: {
    clickEvent: function (item) {
    alert(item.message)
    }
    }
    }
    </script>
  • v-for 循环渲染

  • v-bind 设置属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <li v-for="item in items" v-bind:class="{under: item.flag}">
    {{item.message}}
    </li>
    <script>
    export default {
    name: 'hello',
    data () {
    return {
    msg: 'Welcome to Your Vue.js App',
    items: [{message: 'vue', flag: false}, {message: 'vue', flag: true}]
    }
    }
    }
    </script>
    <style scoped>
    .under {
    text-decoration: line-through;
    }
    </style>
  • v-model 双向数据绑定

    • <input v-model="newItem" v-on:keyup.enter="addNew"> newItem 就是绑定的变量属性, 可以操作此值进行双向绑定
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      <input v-model="newItem" v-on:keyup.enter="addNew">
      <script>
      export default {
      name: 'hello',
      data () {
      return {
      msg: 'Welcome to Your Vue.js App',
      items: [],
      newItem: ''
      }
      },
      methods: {
      clickEvent: function (item) {
      item.flag = !item.flag
      },
      addNew: function() {
      console.log(this.newItem)
      this.newItem = ''
      }
      }
      }
      </script>

监听其他组件事件

  • this.$emit(其他组件监听事件名称, 传递参数) 全局监听事件
  • $dispatch() 事件沿着父链冒泡
  • $broadcast() 广播事件, 事件会向下传递给所有子组件
  • 父级监听方式 <sub-comp on:父级监听事件名称="回调方法"></sub-comp>

canvas

创建canvas

1
2
3
4
//创建canvas对象
var canvasObj = document.getElementById('canvas');
//获取画笔
var canvas = canvasObj.getContext('2d');

fillRect(left, top, width, height) 填充的矩形

1
2
3
4
5
6
canvas.fillStyle = 'blue';
canvas.fillRect(50, 50, 100, 100);

//等价于
canvas.rect(50, 50, 100, 100)
canvas.fill();
  • fillStyle 填充颜色

strokeRect(l, t, w, h) 只有边框的矩形

1
2
3
4
canvas.lineJoin = 'round';
canvas.lineWidth = 10
canvas.strokeStyle = 'red'
canvas.strokeRect(150.5,150.5, 100, 100);
  • lineJoin 边框弧度 round(圆角) bevel(斜角)
  • lineCap 线条边框弧度
  • lineWidth 线宽
  • strokeStyle 线条颜色
  • 建议left和top尽量使用0.5, 不然会多一个像素

clearRect(l, t, w, h) 清除画布

1
canvas.clearRect(0, 0, 300, 300);

画直线

  • moveTo(x, y) 移动画笔到抹点
  • lineTo(x, y) 定一个点
  • stroke() 连接线
  • fill 填充颜色
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    canvas.moveTo(100, 100);
    canvas.lineWidth = 5;
    canvas.lineTo(150, 200);
    canvas.lineTo(200, 200);
    canvas.closePath();
    canvas.stroke();
    canvas.beginPath();
    canvas.moveTo(200, 100);
    canvas.lineTo(300, 200);
    canvas.lineTo(300, 400);
    canvas.stroke();
    canvas.fillStyle = 'green';
    canvas.fill()
    canvas.closePath();

画圆

  • arc(x, y, r, 起始弧度, 结束弧度, 旋转方向)
    • 弧度 = 角度 * Math.PI / 180
    • 旋转方向: true为逆时针, false为瞬时间
    • stroke fill closePath等 这些和画直线功能一样
      1
      2
      canvas.arc(200, 200, 100, 0, 90 * Math.PI / 180, true);
      canvas.stroke();

画弧线

  • arcTo(x1, y1, x2, y2, r)

    1
    2
    3
    canvas.moveTo(100, 200)
    canvas.arcTo(100, 100, 200, 100, 50)
    canvas.stroke()
  • quadraticCurveTo(x1, y1, x2, y2, r)

    • 弧度会趋向moveTo那个点
      1
      2
      3
      4
      //趋向点
      canvas.moveTo(100, 200)
      canvas.quadraticCurveTo(100, 100, 200, 200, 100)
      canvas.stroke()
  • bezierCurveTo(趋向点x1, 趋向点y1, 趋向点x2, 趋向点y2, 终点x, 终点y);

    1
    2
    3
    4
    //起始点
    canvas.moveTo(100, 200)
    canvas.bezierCurveTo(100, 100, 200, 200, 200, 100)
    canvas.stroke()

beginPath 与 endPath

  • beginPath() 开始画新线
  • closePath() 闭合线
  • beginPath和closePath是相对应 相应的作用就会在这闭合区间里生效

save 与 restore

  • 声明的fill填充颜色, lineWidth线条宽度等其他属性 只会在这个范围内生效
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    var canvasObj = document.getElementById('canvas');
    var canvas = canvasObj.getContext('2d');
    canvas.save();
    canvas.fillStyle = 'blue';
    canvas.fillRect(50,50, 100, 100);
    canvas.lineJoin = 'round';
    canvas.lineWidth = 10;
    canvas.strokeStyle = 'red';
    canvas.strokeRect(150.5,150.5, 100, 100);

    canvas.moveTo(100, 100);
    canvas.lineWidth = 5;
    canvas.lineTo(150, 200);
    canvas.lineTo(200, 200);
    canvas.closePath();
    canvas.stroke();
    canvas.restore()
    canvas.beginPath();
    canvas.moveTo(200, 100);
    canvas.lineTo(300, 200);
    canvas.lineTo(300, 400);
    canvas.stroke();
    canvas.fill()

变形

  • traslate(x, y)

    • 改变变化相对位置(默认是0,0 点)
    • 如果需要按图形中心点旋转, 需要使用save, restore, translate, rotate配合使用
      1
      2
      3
      4
      5
      6
      7
      canvas.save()
      canvas.clearRect(0, 0, canvasObj.width, canvasObj.height);
      canvas.rotate(num * Math.PI / 180);
      // canvas.scale(start / 50, start / 50);
      canvas.translate(-50, -50)
      canvas.fillRect(0, 0, 100, 100);
      canvas.restore()
  • rotate(arc)

    • 以弧度为单位旋转
    • 以左上角基准旋转
    • 数值会累加 速度会越来越快 所以用 save和restroe抱起来就可以解决这个问题
  • scale(x, y)
    • 等比缩放

加载图片

  • drwaImage(source, x, y, w, h)
  • createPattern(source, 平铺方式)
    • 平铺方式: repeat, repeat-x, repeat-y, no-repeat

      渐变

  • createLinearGradient(sx, sy, ex, ey)
  • addColorStop(0-1, ‘颜色’)

    1
    2
    3
    4
    5
    var obj = canvas.createLinearGradient(100, 100, 100, 200);
    obj.addColorStop(0, 'red');
    obj.addColorStop(1, 'blue');
    canvas.fillStyle = obj ;
    canvas.fillRect(100, 100, 100, 200);
  • createRadialGradient(sx, sy, sr, ex, ey, er)

    1
    2
    3
    4
    5
    6
    var obj = canvas.createRadialGradient(200, 200, 100, 200, 200, 200);
    obj.addColorStop(0, 'red');
    obj.addColorStop(1, 'blue');
    canvas.fillStyle = obj ;
    canvas.arc(200, 200, 200, 0, 360 * Math.PI / 180, false);
    canvas.fill()

文本

  • strokeText(‘文字’, x, y)
  • fillText(‘文字’, x, y) 填充字
  • font = ‘60px 宋体’
  • textAlign
  • textBaseLine = ‘top/middle/bottom’
  • measureText().width 只有文字宽度, 高度就是文字大小
  • 阴影
    • shadowOffsetX
    • shadowOffsetY
    • shadowColor(r, g, b) 默认透明黑色
    • shadowBlur
      1
      2
      3
      4
      5
      canvas.font = '60px 宋体'
      canvas.shadowOffsetX = 10
      canvas.shadowColor = 'red'
      canvas.shadowBlur = 5
      canvas.strokeText('Hello Wolrd', 200, 200)

默认样式

  • 默认宽300, 高150

贝塞尔曲线

  • context.quadraticCurveTo(double cpx, double cpy, double x, double y)
  • context.bezierCurveTo(double cpx, double cpy, double cp2x, double cp2y, double x, double y)
1
2
3
4
5
6
7
8
9
10
(function() {
context.beginPath();
context.strokeStyle = 'white';
context.fillStyle = 'cornflowerblue';
context.moveTo(300, 300);
context.lineTo(500, 500);
context.quadraticCurveTo(350, 250, 450, 450);
context.fill();
context.stroke();
})();

polygon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(function() {
function drawPolygon(x, y, r, num) {
context.beginPath();
context.moveTo(x + r, y);
var avgArc = 2 * Math.PI / num;
context.strokeStyle = "black"
for (var i = 0; i < num; i++) {
var tmpX = Math.round(r * Math.cos(avgArc * i) + x);
var tmpY = Math.round(r * Math.sin(avgArc * i) + y);
console.log(tmpX, tmpY)
context.lineTo(tmpX, tmpY);
}
context.closePath();
context.stroke();
}

drawPolygon(200, 200, 50, 6);
drawPolygon(300, 300, 50, 4);
})();

webpack

webpack 主要功能

  • 将不同类型的文件打包成一个或多个文件
  • 不同类型的文件, 根据loader配置加载, 没有配置对应的loader就被导致导入报错

    entry

  • 打包文件地址
  • 可以是数组, 引入多个地址.
  • 也可以是对象, 引入多个页面
  • webpack-dev-server默认是不支持html模板刷新的, 可以添加'webpack-dev-server/client?http://localhost:8080/', 实现双向监听, 就可以监听到模板刷新了

ouput

  • 导出地址
  • 格式与entry类似

    支持参数

  • path为目录
  • filename 文件名
    • 当文件名指定时, 将会全部打包到一个文件里
    • 当以js/[name]-[hash]-[chunhash].js时, 会根据输入文件生成对应的hash文件

插件

  • html-webpack-plugin
    • 如果生成的bundle文件带有hash值, 每次都不一样, 那么html页面里就需要每次修改很麻烦, 所以就需要这个插件
    • template参数指定模板
    • inject js插入地方; false就不自动插入生成好的js
    • publicPath 地址前缀, 比如网址
    • 可以使用 <%= htmlWebpackPlugin.option.参数名 %>在模板里替换变量
      1
      2
      3
      4
      5
      6
      plugins: [
      new HtmlwebpackPlugin({
      template: 'index.html',
      inject: 'head'
      })
      ]

实时更新

  • 地址: http://localhost:8080/webpack-dev-server/bundle

问题

  • css图片引入报错
    • 解决办法: 修改正则 将$ 替换成 (?.*$|$)
      1
      2
      3
      4
      { 
      test: /\.(eot|png|gif|jpg|woff|woff2|svg|ttf)([\?]?.*)$/,
      loader: "file-loader"
      },

配置

webpack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
var path = require('path');
var HtmlwebpackPlugin = require('html-webpack-plugin');
//定义了一些文件夹的路径
var ROOT_PATH = path.resolve(__dirname);
var APP_PATH = path.resolve(ROOT_PATH, 'app');
var BUILD_PATH = path.resolve(ROOT_PATH, 'build');

module.exports = {
//项目的文件夹 可以直接用文件夹名称 默认会找index.js 也可以确定是哪个文件名字
entry: [
'webpack-dev-server/client?http://localhost:8080/',
APP_PATH
],
//输出的文件名 合并以后的js会命名为bundle.js
output: {
path: BUILD_PATH,
filename: 'bundle.js'
},
devServer: {
historyApiFallback: true,
hot: true,
inline: true,
// progress: true,
},
module: {
loaders: [
{
test: /\.css$/,
loader: 'style-loader!css-loader'//添加对样式表的处理
},
{
test: /\.(eot|png|gif|jpg|woff|woff2|svg|ttf)([\?]?.*)$/,
loader: "file-loader"
},
]
},
//添加我们的插件 会自动生成一个html文件
plugins: [
new HtmlwebpackPlugin({
template: path.resolve(APP_PATH, 'index.html'),
inject: 'head'
})
]
};

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --hot --inline"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"css-loader": "^0.26.2",
"file-loader": "^0.10.1",
"html-webpack-plugin": "^2.28.0",
"html-withimg-loader": "^0.1.16",
"style-loader": "^0.13.2",
"url-loader": "^0.5.8",
"webpack-dev-server": "^2.4.1"
}
}

css

border

  • border-width, outline, box-shadow, text-shadow等不支持百分比
  • border-width默认medium(3px)
  • chrome/firefox 虚线比例3:1; IE 2:1
  • border-style:dotted 是原型的, 所以利用此功能实现圆形
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .box {
    width: 150px;
    height: 150px;
    /*超出区域隐藏, 只显示一个圆*/
    overflow: hidden;
    }
    .dotted {
    width: 100%;
    height: 100%;
    border: 149px dotted #cd0000;
    }

选择器

包含选择符 与 子选择符的区别

  • 包含选择器只要是后代就生效
  • 子选择必须是儿子(IE7+)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 包含选择器
    div p
    {
    color: red;
    }
    //子选择器
    div > p
    {
    color: red;
    }

相邻选择器

  • 只有相邻才生效(IE7+)
    1
    2
    3
    4
    div + p
    {
    color: blue;
    }

属性选择符:

  • E[attr]、E[attr=“value”]、E[attr~=“value”]、E[attr|=“value”]、E[attr^=“value”]

伪类选择器

  • 可以在目前前面或后面添加内容, 但在dom节点上看不到相应的内容
  • hover这些可以配合before,after使用, 但是必须先申明hover
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    .test:hover::after {
    content: ' hello ';
    color: red;
    }
    // 可以使用自身的属性
    .test:hover::after {
    content: attr(title);
    color: red;
    }
    <div class="test" title="hello">aaa</div>

CSS样式采用的优先顺序:

  • 标有!important关键字声明的属性。
  • html中的CSS样式属性。
  • 作者编辑的CSS文件样式属性。
  • 用户设置的样式。
  • 浏览器默认的样式。

选择符优先级积分:

  • 标签选择符、伪类及伪对象:优先级积分为1。
  • 类选择符、属性选择符:优先级积分为10。
  • ID选择符:优先级积分为100。
  • style属性:优先级积分为1000。
  • 其他选择符,如通配符选择符等:优先级积分为0。

清楚浮动

  1. clear属性–常用clear: both;
  2. 添加额外标签:
  3. 使用 br标签和其自身的 html属性:
  4. 父元素设置: overflow: hidden; *zoom:1; (在IE6中还需要触发 hasLayout ,例如 zoom:1)
  5. 父元素设置: display: table;
  6. 父元素设置 :after 伪类 (推荐):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    .clearFix:after {
    clear: both; /* 清除伪类层以上的浮动 */
    display: block; /* 使生成的元素以块级元素显示,占满剩余空间; */
    visibility: hidden; /* 设置伪类层内容为块级元素且不可见 */
    height: 0;
    line-height: 0; /* 设置伪类层中的高度和行高为0 */
    content: " "; /* 将伪类层中的内容清空 */
    }
    .clearFix {
    zoom: 1; /* 针对IE浏览器产生hasLayout效果清除浮动 */
    }

    /* 更简洁的写法 */
    .clearFix:before,
    .clearFix:after {
    content: "";
    display: table;
    }

    .clearFix:after {
    clear: both;
    }
    .clearFix{
    zoom:1;
    }

滚动条

  • 默认的滚动条是html的 (body的滚动条会与边框相差8个像素)

元素宽度

  • 元素宽度 = width + borderWidth + padding + margin

布局经验

  • 浮动的父级尽量设置高度, 这样不会整体上移
  • 块级元素, 左右居中可以用margin: 0 auto; 但是上下居中只能靠margin/padding调整
  • 当div漂浮起来后, 这行高度就变化了, 不在按这个div高度来算了
  • 如何让文字居中, 设置宽度, 再设置 text-align:center

bootstrap

栅格

  • 要被div.row包裹起来
  • 一行只有12个
  • col-lg col-md col-sm col-xs 这些是根据不同的分辨率展现对应的个数 可以嵌套使用
  • col-lg-offset 向右偏移
  • col-lg-push 向右偏移和offset类似 但不完全一样
  • col-lg-pull 向左偏移
  • visible-lg-block 在对应的分辨率下可见 其他情况隐藏
  • hidden-sm 在对应的像素下隐藏
  • pull-right/left 贴在左边或右边
  • hidden/visible-print-block 打印显示或隐藏

    样式

  • default primary success info warning error
  • btn
    • btn-link 有连接
    • btn-block 独占一行
    • 也有 btn-lg lg md sm xs 样式大小
    • disable 禁用样式
    • active 选中样式
  • btn-group 按钮变为一组
    • btn-group-justified 充满一行 默认只对a标签生效 input和button需要再套一层div.btn-group
    • btn-group-vertical
  • bg
  • text
  • alert
  • panel
    • panel-heading
    • panel-body
  • input
  • form-control
  • caret 下拉箭头
    • dropup 箭头向上

      下拉

  • data-* 跟js有关 data-toggle
    • data-target 操作对象
  • aria-* 残疾人辅助功能
  • divider 分割线
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <div class="container">
    <div class="bg-primary">aaaa</div>
    <div class="dropdown">
    <div class="btn-group dropdown-toggle" data-toggle="dropdown" data-target=".dropdown">
    <div class="btn btn-primary">aaa</div>
    <div class="btn btn-primary"><span class="caret"></span></div>
    </div>
    <ul class="dropdown-menu">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    </ul>
    </div>
    </div>
    <div class="container">
    <div class="bg-primary">aaaa</div>
    <div class="dropdown">
    <div class="btn-group dropdown-toggle" data-toggle="dropdown">
    <div class="btn btn-primary">aaa</div>
    <div class="btn btn-primary"><span class="caret"></span></div>
    </div>
    <ul class="dropdown-menu">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    </ul>
    </div>
    </div>

导航 nav

  • nav
  • nav-tabs
  • nav-jusified 等宽
  • nav-pills
  • nav-stackted 垂直的
  • tab-content 导航内容
  • tab-pane

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <ul class="nav nav-tabs">
    <li class="active"><a href="#a" data-toggle="tab">one</a></li>
    <li><a href="#b" data-toggle="tab">one</a></li>
    <li><a href="#c" data-toggle="tab">one</a></li>
    <li><a href="#d" data-toggle="tab">one</a></li>
    </ul>
    <ul class="tab-content">
    <li class="tab-pane active" id="a">aaa</li>
    <li class="tab-pane" id="b">bbb</li>
    <li class="tab-pane" id="c">ccc</li>
    <li class="tab-pane" id="d">ddd</li>
    </ul>
  • navbar

  • navbar-default narbar-*
  • navbar-inverse 不同的风格
  • navbar-fixed-top/bottom 固定
  • navbar-header

    • navbar-brand
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      <nav class="navbar navbar-default nav-inverse">
      <div class="navbar-header">
      <a href="" class="navbar-brand">logo</a>
      </div>
      <ul class="nav nav-tabs">
      <li class="active"><a href="#a" data-toggle="tab">one</a></li>
      <li><a href="#b" data-toggle="tab">one</a></li>
      <li><a href="#c" data-toggle="tab">one</a></li>
      <li><a href="#d" data-toggle="tab">one</a></li>
      </ul>
      </nav>
  • navbar-left 内容靠左

  • navbar-right
  • navbar-btn
  • navbar-link
  • navbar-text
  • navbar-toggle
  • navbar-collapse 导航折叠

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <nav class="navbar navbar-default nav-inverse">
    <div class="navbar-header">
    <a href="" class="navbar-brand">logo</a>
    <btton class="navbar-toggle" data-toggle="collapse" data-target="#myCollapse">
    <span class="icon-bar"></span>
    <span class="icon-bar"></span>
    <span class="icon-bar"></span>
    </btton>
    </div>
    <div class="collapse navbar-collapse" id="myCollapse">
    <ul class="nav nav-tabs navbar-left">
    <li class="active"><a href="#a" data-toggle="tab">one</a></li>
    <li><a href="#b" data-toggle="tab">one</a></li>
    <li><a href="#c" data-toggle="tab">one</a></li>
    <li><a href="#d" data-toggle="tab">one</a></li>
    </ul>
    <button class="navbar-nav navbar-btn">aa</button>
    <p class="nav navbar-nav navbar-text navbar-right">bbb</p>
    <form action="" class="navbar-form navbar-left">
    <input type="text" class="form-control">
    <input type="text" class="btn btn-primary" value="搜索">
    </form>
    <ul class="nav navbar-nav navbar-right">
    <li><a href="">登录</a></li>
    </ul>
    </div>
    </nav>
  • data-spy=”scroll” 监听滚动条

  • data-target=”#”
  • data-offset=”200px” 偏移距离

Backbone

backbone依赖

  • 依赖jquery库 进行dom操作
  • 依赖underscore 进行数据存储
    1
    2
    3
    <script type="text/javascript" src="jquery-2.0.3.min.js"></script>
    <script type="text/javascript" src="underscore-min.js"></script>
    <script type="text/javascript" src="backbone-min.js"></script>

modelcollection的区别

  • collection是多条model对象的集合
    1
    2
    3
    4
    5
    6
    var collect = new Backbone.Collection();
    var model = new Backbone.Model();
    model.set('name', 'bbb')
    model.set({'age': 18})
    collect.add(model)
    alert(JSON.stringify(collect))

model的扩展

  • 第一个对象是扩展对象方法
  • 第二个对象是扩展静态方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var M = Backbone.Model.extend({
    aaa: function() {
    alert('aaa')
    }
    }, {
    bbb: function() {
    alert('bbb')
    }
    })
    M.bbb();
    var model = new M
    model.aaa();

初始化默认值

  • defaults 默认参数
  • initialize 默认方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var M = Backbone.Model.extend({
    defaults: {
    name: 'lc'
    },
    initialize: function() {
    //当有变化时触发 change后面可以添加参数 指定某个参数变化 触发 如change:name
    this.on('change', function() {
    alert('changed')
    })
    }
    })
    var model = new M();
    alert(model.get('name'))

继承

1
2
3
4
5
6
7
8
var M = Backbone.Model.extend({
defaults: {
name: 'lc'
}
})
var childModel = M.extend();
var model = new childModel();
alert(model.get('name'))

与view结合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var M = Backbone.Model.extend({
defaults: {
name: 'lc'
}
})
var V = Backbone.View.extend({
initialize: function() {
this.listenTo(this.model, 'change', this.show);
},
show: function(model) {
$('body').append('<div>' + model.get('name') + '</div>')
}
})
var m = new M();
var view = new V({model: m})
setTimeout(function() {
m.set({name: 'll'})
}, 1000)

save 与 sync联系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Backbone.sync = function(method, model) {
alert(method + ':' + JSON.stringify(model))
//将method方法改成update
model.id = 1
}
var M = Backbone.Model.extend({
defaults: {
name: 'lc'
},
url: '/url'
})
var model = new M()
model.save()
model.save({name: 'll'})

fetch 获取服务器资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Backbone.sync = function(method, model) {
alert(method + ':' + JSON.stringify(model))
//将method方法改成update
// model.id = 1
}
var C = Backbone.Collection.extend({
initialize: function() {
this.on('reset', function() {
alert(123)
})
},
url: 'http://www.baidu.com'
})
var model = new C()
model.fetch()

Router

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var m = Backbone.Router.extend({
routes: {
'index': 'index',
'getData/:id': 'getData',
'setData/:id/:data': 'setData'
},
index: function() {
alert('index')
},
getData(id) {
alert(id)
},
setData(id, data) {
alert(id + ':' + data )
}
})
var model = new m();
Backbone.history.start()

事件委托

  • 对dom操作
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var V = Backbone.View.extend({
    //模板
    el: $('body'),
    events: {
    //监听事件 dom对象 回调方法
    'click li': 'test'
    },
    test: function() {
    alert('aaa')
    }
    })
    var view = new V

模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script type="text/template" id="template">
<% for (var i = 0; i < 5; i ++) {%>
<div><%= name %></div>
<% } %>
</script>

var M = Backbone.Model.extend({
defaults: {
name: 'lc'
}
})
var V = Backbone.View.extend({
initialize: function() {
this.listenTo(this.model, 'change', this.show);
},
show: function(model) {
//将数据转成json 传递给模板生成
$('body').append(this.template(this.model.toJSON()))
},
// 拿到模板 并获取数据填充
template: _.template($("#template").html())
})
var m = new M();
var view = new V({model: m})
setTimeout(function() {
m.set({name: 'll'})
}, 1000)

Virtual DOM

为什么要使用Vitrul DOM

  • 因为原生dom自带很多属性, 直接操作dom是非常笨重的, 性能效率非常低

Vitrul DOM 原理

  • 因为原生dom过于笨重, 初始化了很多属性, 我们可以将原生dom用js对象来表示, 这个对象里只保存这个dom独有的属性, 省略了很多其他默认的属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    <ul id='list'>
    <li class='item'>Item 1</li>
    <li class='item'>Item 2</li>
    <li class='item'>Item 3</li>
    </ul>
    //上面的js表示如下
    var element = {
    tagName: 'ul', // 节点标签名
    props: { // DOM的属性,用一个对象存储键值对
    id: 'list'
    },
    children: [ // 该节点的子节点
    {tagName: 'li', props: {class: 'item'}, children: ["Item 1"]},
    {tagName: 'li', props: {class: 'item'}, children: ["Item 2"]},
    {tagName: 'li', props: {class: 'item'}, children: ["Item 3"]},
    ]
    }
  • Virturl Dom 会把旧dom和新dom, 用js对象生成两棵树进行比较之间的差异

  • 正如你所预料的,比较两棵DOM树的差异是 Virtual DOM 算法最核心的部分,这也是所谓的 Virtual DOM 的 diff 算法。两个树的完全的 diff 算法是一个时间复杂度为 O(n^3) 的问题。但是在前端当中,你很少会跨越层级地移动DOM元素。所以 Virtual DOM 只会对同一个层级的元素进行对比
  • 在比较过程, 记录每个节点的差异, 比如是节点元素类型变换了, 还是增删改了属性值等等
  • 最后对有变化的dom进行操作

如果dom只是重新排序了? 利用上面的方法, 性能也会很差

  • 这个问题抽象出来其实是字符串的最小编辑距离问题(Edition Distance),最常见的解决算法是 Levenshtein Distance,通过动态规划求解,时间复杂度为 O(M * N)。但是我们并不需要真的达到最小的操作,我们只需要优化一些比较常见的移动情况,牺牲一定DOM操作,让算法时间复杂度达到线性的(O(max(M, N))。具体算法细节比较多,这里不累述,有兴趣可以参考代码

为什么组件上要加上唯一的key标识

  • 因为tagName是可重复的,不能用这个来进行对比。所以需要给子节点加上唯一标识key,列表对比的时候,使用key进行对比,这样才能复用老的 DOM 树上的节点

参考学习

JavaScript实现一些算法

用JavaScript实现的一些算法


寻路算法

demo演示

image

算法原理

  • 首先计算出一个点下一步可走地址, 放到一个数组里保存起来
  • 过滤掉障碍点, 和已经走过的点
  • 利用估值函数算法f(n) = g(n) + h(n)计算出一个点到起始点和到终点和的最短距离
  • 并且把距离大小和上一步位置记录到对应的对象上, 方便后面绘制路径
  • 然后将结果从小到大重新排序, 获取下一步可走点
  • 然后递归循环计算路径
  • 当到达终点时, 开始绘制路径
  • 具体详情请看源代码

寻路算法源代码地址


行列式变换算法

demo演示

image

算法原理

  • 每个元素的索引位置对行的长度取模
  • 根据模的结果, 重新建立数组, 就能实现变换
  • 具体详情请看源代码

爱消除游戏源代码地址


八皇后问题

demo演示

image

算法原理

  • 递归计算是否在同行同列同斜线是否有其他皇后存在
  • 每次递归后, 要应用回溯的方法, 将棋盘恢复, 方面计算其他方法
  • 具体详情请看源代码

八皇后源代码地址


螺旋矩阵

demo演示

image

算法原理

  • 算法原理比较简单, 看代码就明白了
  • 具体详情请看源代码

螺旋矩阵源代码地址


排列和组合算法

算法原理

  • 排列: A(m, n) = m! / (m - n)!
  • 组合: C(m, n) = m! / n! * (m - n)!
  • 具体详情请看源代码

寻路算法

demo演示

image

算法原理

  • 首先计算出一个点下一步可走地址, 放到一个数组里保存起来
  • 过滤掉障碍点, 和已经走过的点
  • 利用估值函数算法f(n) = g(n) + h(n)计算出一个点到起始点和到终点和的最短距离
  • 并且把距离大小和上一步位置记录到对应的对象上, 方便后面绘制路径
  • 然后将结果从小到大重新排序, 获取下一步可走点
  • 然后递归循环计算路径
  • 当到达终点时, 开始绘制路径
  • 具体详情请看源代码

寻路算法源代码地址


行列式变换算法

demo演示

image

###算法原理

  • 每个元素的索引位置对行的长度取模
  • 根据模的结果, 重新建立数组, 就能实现变换
  • 具体详情请看源代码

爱消除游戏源代码地址


八皇后问题

demo演示

image

算法原理

  • 递归计算是否在同行同列同斜线是否有其他皇后存在
  • 每次递归后, 要应用回溯的方法, 将棋盘恢复, 方面计算其他方法
  • 具体详情请看源代码

八皇后源代码地址


螺旋矩阵

demo演示

image

###算法原理

  • 算法原理比较简单, 看代码就明白了
  • 具体详情请看源代码

螺旋矩阵源代码地址


技巧算法

  • 不使用第三个变量交换两个变量的值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    var a = 5;
    var b = 8;
    //第一种
    a = a + b;
    b = a - b;
    a = a - b;

    //第二种
    a = a | b;
    b = a | b;
    a = a | b;

    //当a和b都不是数字的时候
    a = [a, b]
    b = a[0]
    a = a[1]
  • 不适用循环方法 输入 3 返回[1, 2, 3]数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    function test(num) {
    var arr = [];

    arr.push(num);
    if (-- num) {
    arr = test(num).concat(arr);
    }
    return arr
    }
    //利用闭包 公用一个arr
    function test(num) {
    var arr = [];

    return (function() {
    arr.unshift(num);
    if (-- num) {
    arguments.callee(num)
    }
    return arr;
    })()
    }
    //利用正则
    function test(num) {
    var arr = [];
    var resArr = [];
    arr.length = num + 1;
    var str = arr.join('a');
    str.replace(/a/g, function() {
    resArr.unshift(num --);
    })

    return resArr;
    }
  • 利用多种方式获取输入num 当大于100返回100 否则返回num

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
function test(num) {
return num < 100 ? num : 100;
}

function test(num) {
switch(num < 100) {
case true:
return num
case false:
return 100;
}
}

function test(num) {

return Math.min(num, 100);
}

function test(num) {

var tmp = num > 100 && 100;
return tmp || num
}

function test(num) {

var tmp = num + '';
for (var i = 2; i < num.length && num > 0;) {
return 100
}
return num;
}

function test(num) {
var arr = [num, 100];
arr.sort(function(num1, num2) {
return num1 - num2;
})

return arr[0]
}

function test(num) {
var json = {foo: 'bar'}
var tmp = num > 100 || json;
for (var i in tmp) {
return 100
}
return num
}
  • 斐波那契算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function test(num) {
if (num <= 1) {
return 1;
}

return test(num - 1) + test(num - 2)
}

function test(num) {
var num1 = 1;
var num2 = 1;
var num3 = 0;

for (var i = 0; i < num -2; i ++) {
num3 = num1 + num2;
num1 = num2;
num2 = num3;
}

return num3
}

如果觉得不错, 记得点星哦, 谢谢啦. 大家的鼓励才是我继续努力的最大动力

转载请注明出处


斐波那契算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function test(num) {
if (num <= 1) {
return 1;
}

return test(num - 1) + test(num - 2)
}

function test(num) {
var num1 = 1;
var num2 = 1;
var num3 = 0;

for (var i = 0; i < num -2; i ++) {
num3 = num1 + num2;
num1 = num2;
num2 = num3;
}

return num3
}

技巧算法

  • 不使用第三个变量交换两个变量的值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    var a = 5;
    var b = 8;
    //第一种
    a = a + b;
    b = a - b;
    a = a - b;

    //第二种
    a = a | b;
    b = a | b;
    a = a | b;

    //当a和b都不是数字的时候
    a = [a, b]
    b = a[0]
    a = a[1]
  • 不适用循环方法 输入 3 返回[1, 2, 3]数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    function test(num) {
    var arr = [];

    arr.push(num);
    if (-- num) {
    arr = test(num).concat(arr);
    }
    return arr
    }
    //利用闭包 公用一个arr
    function test(num) {
    var arr = [];

    return (function() {
    arr.unshift(num);
    if (-- num) {
    arguments.callee(num)
    }
    return arr;
    })()
    }
    //利用正则
    function test(num) {
    var arr = [];
    var resArr = [];
    arr.length = num + 1;
    var str = arr.join('a');
    str.replace(/a/g, function() {
    resArr.unshift(num --);
    })

    return resArr;
    }
  • 利用多种方式获取输入num 当大于100返回100 否则返回num

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
function test(num) {
return num < 100 ? num : 100;
}

function test(num) {
switch(num < 100) {
case true:
return num
case false:
return 100;
}
}

function test(num) {

return Math.min(num, 100);
}

function test(num) {

var tmp = num > 100 && 100;
return tmp || num
}

function test(num) {

var tmp = num + '';
for (var i = 2; i < num.length && num > 0;) {
return 100
}
return num;
}

function test(num) {
var arr = [num, 100];
arr.sort(function(num1, num2) {
return num1 - num2;
})

return arr[0]
}

function test(num) {
var json = {foo: 'bar'}
var tmp = num > 100 || json;
for (var i in tmp) {
return 100
}
return num
}

如果觉得不错, 记得点星哦, 谢谢啦. 大家的鼓励才是我继续努力的最大动力