├── README.md ├── call & apply & bind详解.md ├── javascript自定义事件 ├── event.js ├── 事件流.html ├── 自定义事件.html └── 鼠标跟随.html ├── js-对象深拷贝.js ├── js-闭包.js ├── js中传递类型.png ├── js代码重构方案.doc ├── js思维导图 ├── jsDOM操作.gif ├── js函数基础.gif ├── js变量.gif ├── js字符串函数.gif ├── js数组.gif ├── js正则表达式.gif ├── js流程语句.gif └── js运算符.gif ├── js数组去重复.js ├── js知识点1.js ├── js知识点2.js ├── js继承方式.js ├── 基于jQuery的插件开发.js └── 拖拽div ├── dialog.html ├── drag.js └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # javascript-core-base 2 | 日常工作和学习过程中汇总的一些JS核心知识点。 -------------------------------------------------------------------------------- /call & apply & bind详解.md: -------------------------------------------------------------------------------- 1 | 2 | call()方法的作用和apply()方法类似,只有一个区别,就是call()方法接受的是若干参数的列表,而apply()方法接受的是一个包含多个参数的数组。 3 | 4 | ## Function.prototype.call() 5 | 6 | call()方法在使用一个指定this值和若干个指定的参数值的前提下调用某个函数或方法。 7 | 8 | ### 语法 9 | 10 | ``` 11 | fun.call(thisArg[, arg1[, arg2[, ...]]]) 12 | ``` 13 | 14 | ### 参数 15 | **thisArg** 16 | 17 | 在fun函数运行时指定的this值。指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。 18 | 19 | **arg1, arg2** 20 | 21 | 指定的参数列表。 22 | 23 | ### 描述 24 | 当调用一个函数时,可以赋值一个不同的this对象。this引用当前对象,即call方法的第一个参数。 25 | 26 | 通过call方法,可以在一个对象上借用另一个对象上的方法,如Object.prototype.toString.call([]),就是一个Array对象借用了Object对象上的方法。 27 | 28 | ### 示例 29 | #### 使用call方法调用父构造函数 30 | 在一个子构造函数中,你可以通过调用父构造函数的call方法来实现继承,类似于java中的写法。下例中,使用Food和Toy构造函数创建的对象实例都会拥有在Product构造函数中添加的name属性和price属性,但category属性是各自的构造函数中定义的。 31 | 32 | ``` 33 | function Product(name, price) { 34 | this.name = name; 35 | this.price = price; 36 | 37 | return this; 38 | } 39 | 40 | function Food(name, price) { 41 | Product.call(this, name, price); 42 | this.category = 'food'; 43 | } 44 | 45 | Food.prototype = Object.create(Product.prototype); 46 | Food.prototype.constructor = Food; 47 | 48 | function Toy(name, price) { 49 | Product.call(this, name, price); 50 | this.category = 'toy'; 51 | } 52 | 53 | Toy.prototype = Object.create(Product.prototype); 54 | Toy.prototype.constructor = Toy; 55 | 56 | var cheese = new Food('feta', 5); 57 | var fun = new Toy('robot', 10); 58 | ``` 59 | 60 | #### 使用call方法调用匿名函数 61 | 在下例的for循环体内,我们创建了一个匿名函数,然后通过调用该函数的call方法,将每个数组元素作为指定的this值执行了那个匿名函数。这个匿名函数的主要目的是给每个元素对象添加一个print方法。这里不是必须得让数组元素作为this的值传入那个匿名函数。 62 | 63 | ``` 64 | var animals = [ 65 | { 66 | speicies: 'Lions', 67 | name: 'king' 68 | }, 69 | { 70 | speicies: 'Whale', 71 | name: 'Fail' 72 | } 73 | ]; 74 | 75 | for(var i = 0, len = animals.length; i < len; i++) { 76 | (function(i) { 77 | this.print = function() { 78 | console.log('#' + i + ' ' + this.species + ' ' + this.name); 79 | } 80 | this.print(); 81 | }).call(anmials[i], i); 82 | } 83 | ``` 84 | 85 | #### 使用call方法调用匿名函数并且指定上下文的this 86 | 在下面的例子中,当调用greet方法时,该方法的this值会绑定到i对象。 87 | 88 | ``` 89 | function greet() { 90 | var reply = [this.person, 'Is An Aesome', this.role]; 91 | console.log(reply); 92 | } 93 | 94 | var i = { 95 | person: 'Douglas', 96 | role: 'JS' 97 | }; 98 | 99 | greet.call(i); 100 | ``` 101 | 102 | ## Function.prototype.apply() 103 | 104 | apply()方法在指定this值和参数(参数以数组或类数组对象的形式存在)的情况下调用某个函数。 105 | 106 | ### 语法 107 | ``` 108 | fun.apply(thisArg[, argsArray]) 109 | ``` 110 | 111 | ### 参数 112 | **thisArg** 113 | 114 | 在fun函数运行时指定的this值。指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定为null或undefined时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字、字符串、布尔值)的this会指向该原始值的自动包装对象。 115 | 116 | **argsArray** 117 | 118 | 一个数组或者类数组对象,其中的数组元素将作为单独的参数传给fun函数。如果该参数的值为null或undefined,则表示不需要传入任何参数。从ES5开始,可以使用类数组对象。 119 | 120 | ### 描述 121 | 在调用一个存在的函数时,你可以为其指定一个this对象。this指当前对象,也就是正在调用这个函数的对象。使用apply,你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。 122 | 123 | apply可以使用数组字面量,如fun.apply(this, ['eat', 'ban']),或数组对象,如fun.apply(this, new Array('eat', 'ban'))。也可以使用arguments对象作为argsArray参数。arguments是一个函数的局部变量。它可以被用作调用对象的所有未指定的参数。这样,在使用apply函数的时候就不需要知道被调用对象的所有参数。可以使用arguments来把所有参数传递给被调用对象。 124 | 125 | ### 示例 126 | #### 使用apply来链接构造器 127 | 可以使用apply来给一个对象链接构造器,类似于Java。 128 | 129 | ``` 130 | Function.prototype.construct = function(aArgs) { 131 | var oNew = Object.create(this.prototype); 132 | this.apply(oNew, aArgs); 133 | return oNew; 134 | } 135 | ``` 136 | 137 | 可以使用下面的方式替换create方法。 138 | 139 | ``` 140 | Function.prototype.construct = function(aArgs) { 141 | var fc = this, fNewConstr = function() { 142 | fc.apply(this, aArgs); 143 | }; 144 | fNewConstr.prototype = fc.prototype; 145 | return new fNewConstr(); 146 | } 147 | ``` 148 | 149 | #### 使用apply和内置函数 150 | apply用法允许你在某些本来需要写成遍历数组变量的任务中使用内建的函数。 151 | 152 | ``` 153 | var numbers = [5, 2, 9, 10, 1]; 154 | 155 | var max = Math.max.apply(null, numbers); 156 | var min = Math.min.apply(null, numbers); 157 | ``` 158 | 159 | 如果数组很大,可以继续优化: 160 | 161 | ``` 162 | function minOfArray(arr) { 163 | var min = Infinity; 164 | var QUANTUM = 32768; 165 | 166 | for(var i = 0, len = arr.length; i < len; i++) { 167 | var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len))); 168 | min = Math.min(submin, min); 169 | } 170 | 171 | return min; 172 | } 173 | 174 | var min = minOfArray(numbers); 175 | ``` 176 | 177 | ## Function.pototype.bind() 178 | 179 | bind()方法会创建一个新函数,当这个函数被调用时,它的this值是传递给bind()的第一个参数,它的参数是 bind()的其它参数和其它原本的参数。 180 | 181 | ### 语法 182 | ``` 183 | fun.bind(thisArg[, arg1[, arg2[, ...]]]) 184 | ``` 185 | 186 | ### 参数 187 | **thisArg** 188 | 189 | 当绑定函数被调用时,该参数会作为原函数运行时的this指向。当使用new操作符调用绑定函数时,该参数无效。 190 | 191 | **arg1, arg2, ...** 192 | 193 | 当绑定函数被调用时,这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数。 194 | 195 | ### 描述 196 | bind()函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体。当目标函数被调用时this值绑定到bind()的第一个参数,该参数不能被重写。绑定函数被调用时,bind()也接受预设的参数提供给原函数。一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的this值被忽略,同时调用时的参数被提供给模拟函数。 197 | 198 | ### 示例 199 | #### 创建绑定函数 200 | bind()函数最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值。 201 | 202 | ``` 203 | this.x = 10; 204 | var module = { 205 | x: 80, 206 | getX: function() { 207 | return this.x; 208 | } 209 | } 210 | 211 | module.getX(); //80 212 | 213 | var retrieveX = module.getX; 214 | retrieveX(); //10 215 | 216 | var boundGetX = retrieveX.bind(module); 217 | boundGetX(); //80 218 | ``` 219 | 220 | #### 分离函数 221 | bind()另一个用法是使一个函数拥有预设的初始参数。这些参数作为bind的第二个参数跟在this后面,之后它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面。 222 | 223 | ``` 224 | function list() { 225 | return Array.prototype.slice.call(arguments); 226 | } 227 | 228 | var list1 = list(1, 2, 3); //[1, 2, 3] 229 | 230 | var leadingList = list.bind(undefined, 30); 231 | 232 | var list2 = leadingList(); //[37] 233 | var list3 = leadingList(1, 2, 3); // [37, 1, 2, 3] 234 | ``` 235 | 236 | #### 配合setTimeout 237 | 默认情况下,使用window.setTimeout()时,this关键字会指向window对象。当使用类的方法时,需要this引用类的实例,需要显式地把this绑定到回调函数以便继续使用实例。 238 | 239 | ``` 240 | function LateBloomer() { 241 | this.petalCount = Math.ceil(Math.random()*12) + 1; 242 | } 243 | 244 | LateBloomer.prototype.bloom = function() { 245 | window.setTimeout(this.declare.bind(this), 1000); 246 | }; 247 | 248 | LateBloomer.prototype.declare = function() { 249 | console.log('I am a beautiful flower width ' + this.petalCount + ' petals'); 250 | }; 251 | 252 | var flower = new LateBloomer(); 253 | flower.bloom(); 254 | ``` 255 | 256 | #### 快捷调用 257 | 需要为一个特定的this值的函数创建一个捷径的时候,bind()方法很好用。 258 | 259 | 可以用Array.prototype.slice来将一个类似于数组的对象转成一个真正的数组。 260 | 261 | ``` 262 | var slice = Array.prototype.slice; 263 | slice.apply(arguments); 264 | ``` 265 | 266 | 用bind()可以使这个过程变得简单。slice是Function.prototype的call()方法的绑定函数,并且将Array.prototype的slice()方法作为this的值。 267 | 268 | ``` 269 | var unboundSlice = Array.prototype.slice; 270 | var slice = Function.prototype.call.bind(unboundSlice); 271 | 272 | slice(arguments); 273 | ``` 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | -------------------------------------------------------------------------------- /javascript自定义事件/event.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 包含事件监听、移动和模拟事件触发的事件机制,支持链式调用 3 | */ 4 | //插件方式 5 | (function(window, undefined) { 6 | var Ev = window.Ev = window.$ = function(element) { 7 | return new Ev.fn.init(element); 8 | }; 9 | 10 | /*EV对象构建*/ 11 | Ev.fn = Ev.prototype = { 12 | init: function(element) { 13 | this.element = (element && element.nodeType === 1) ? element : document; 14 | }, 15 | 16 | /* 17 | 添加事件监听 18 | 19 | */ 20 | add: function(type, callback) { 21 | var that = this; 22 | if(that.element.addEventListener) { 23 | //支持Modern和IE9浏览器 24 | that.element.addEventListener(type, callback, false); 25 | } else if(that.element.attachEvent) { 26 | //支持IE5+ 27 | if(type.indexOf('custom') !== -1) { 28 | if(isNaN(that.element[type])) { 29 | that.element[type] = 0; 30 | } 31 | 32 | var fnEv = function(event) { 33 | event = event ? event : window.event; 34 | if(event.propertyName === type) { 35 | callback.call(that.element); 36 | } 37 | }; 38 | that.element.attachEvent('onpropertychange', fnEv); 39 | 40 | //在元素上存储绑定的propertychange的回调,方便移除事件绑定 41 | if(!that.element['callback' + callback]) { 42 | that.element['callback' + callback] = fnEv; 43 | } 44 | } else { 45 | that.element['on' + type] = callback; 46 | } 47 | } else { 48 | //其他浏览器 49 | that.element['on' + type] = callback; 50 | } 51 | return that; 52 | }, 53 | remove: function(type, callback) { 54 | var that = this; 55 | if(that.element.removeEventListener) { 56 | that.element.removeEventListener(type, callback, false); 57 | } else if(that.element.detachEvent) { 58 | //自定义事件处理,支持IE5+ 59 | if(type.indexOf('custom') !== -1) { 60 | //移除对相应的自定义属性的监听 61 | that.element.detachEvent('onpropertychange', that.element['callback' + callback]); 62 | that.element['callback' + callback] = null; 63 | } 64 | } else { 65 | that.element.detachEvent('on' + type, callback); 66 | } 67 | return that; 68 | }, 69 | /** 70 | 模拟触发事件 71 | */ 72 | trigger: function(type) { 73 | var that = this; 74 | try { 75 | //现代浏览器 76 | if(that.element.dispatchEvent) { 77 | //创建事件 78 | var evt = document.createEvent('Event'); 79 | //定义事件类型 80 | evt.initEvent(type, true, true); 81 | //触发事件 82 | that.element.dispatchEvent(evt); 83 | //IE 84 | } else if(that.element.fireEvent) { 85 | if(type.indexOf('custom') != -1) { 86 | that.element[type] ++; 87 | } else { 88 | that.element.fireEvent('on' + type); 89 | } 90 | } 91 | } catch(e) { 92 | 93 | } 94 | return that; 95 | } 96 | } 97 | Ev.fn.init.prototype = Ev.fn; 98 | })(window); 99 | 100 | //对象字面量方式 101 | var Event = { 102 | listener: {}, 103 | addEvent: function(type, fn) { 104 | if(typeof this.listener[type] === 'undefined') { 105 | this.listener[type] = []; 106 | } 107 | if(typeof fn === 'function') { 108 | this.listener[type].push(fn); 109 | } 110 | return this; 111 | }, 112 | triggerEvent: function(type) { 113 | var arrayEvent = this.listener[type]; 114 | if(arrayEvent instanceof Array) { 115 | for(var i = 0, len = arrayEvent.length; i < len; i++) { 116 | if(typeof arrayEvent[i] === 'function') { 117 | arrayEvent[i]({ 118 | type: type 119 | }); 120 | } 121 | } 122 | } 123 | return this; 124 | }, 125 | removeEvent: function(type, fn) { 126 | var arrayEvent = this.listener[type]; 127 | if(typeof type === 'string' && arrayEvent instanceof Array) { 128 | if(typeof fn === 'function') { 129 | for(var i = 0, len = arrayEvent.length; i < len; i++) { 130 | if(arrayEvent[i] === fn) { 131 | this.listener[type].splice(i, 1); 132 | break; 133 | } 134 | } 135 | } else { 136 | delete this.listener[type]; 137 | } 138 | } 139 | return this; 140 | } 141 | }; 142 | 143 | //原型方式 144 | var EventTarget = function() { 145 | this.listener = {}; 146 | }; 147 | 148 | EventTarget.prototype = { 149 | constructor: this, 150 | addEvent: function(type, fn) { 151 | if(typeof type === 'string' && typeof fn === 'function') { 152 | if(typeof this.listener[type] ==='undefined') { 153 | this.listener[type] = [fn]; 154 | } else { 155 | this.listener[type].push(fn); 156 | } 157 | } 158 | return this; 159 | }, 160 | addEvents: function(obj) { 161 | obj = typeof obj === 'object' ? obj : {}; 162 | for(var type in obj) { 163 | if(type && typeof obj[type] === 'function') { 164 | this.addEvent(type, obj[type]); 165 | } 166 | } 167 | return this; 168 | }, 169 | triggerEvent: function(type) { 170 | if(type && this.listener[type]) { 171 | var events = { 172 | type: type, 173 | target: this 174 | }; 175 | for(var len = this.listener[type].length, start = 0; start < len; start += 1) { 176 | this.listener[type][start].call(this, events); 177 | } 178 | } 179 | return this; 180 | }, 181 | triggerEvents: function(array) { 182 | if(array instanceof Array) { 183 | for(var i = 0, len = array.length; i < len; i += 1) { 184 | this.triggerEvent(array[i]); 185 | } 186 | } 187 | return this; 188 | }, 189 | removeEvent: function(type, callback) { 190 | var listeners = this.listener[type]; 191 | if(listeners instanceof Array) { 192 | if(typeof callback === 'function') { 193 | for(var i = 0, len = listeners.length; i < len; i += 1) { 194 | if(listeners[i] === callback) { 195 | listeners.splice(i, 1); 196 | break; 197 | } 198 | } 199 | } else if(callback instanceof Array) { 200 | for(var lis = 0, keyLen = callback.length; lis < keyLen; lis += 1) { 201 | this.removeEvent(type, callback[lis]); 202 | } 203 | } else { 204 | delete this.listener[type]; 205 | } 206 | } 207 | return this; 208 | }, 209 | removeEvents: function(types) { 210 | if(types instanceof Array) { 211 | for(var i =0, len = types.length; i < len; i += 1) { 212 | this.removeEvent(types[i]); 213 | } 214 | } else if(typeof types === 'object') { 215 | for(var type in types) { 216 | this.removeEvent(type, types[type]); 217 | } 218 | } 219 | return this; 220 | } 221 | }; 222 | 223 | //DOM/伪DOM方式 224 | var $$ = function(element) { 225 | return new _$(element); 226 | }; 227 | 228 | var _$ = function(element) { 229 | this.element = (element && element.nodeType ===1 ) ? element : document; 230 | }; 231 | 232 | _$.prototype = { 233 | constructor: this, 234 | addEvent: function(type, fn, capture) { 235 | var element = this.element; 236 | if(window.addEventListener) { 237 | element.addEventListener(type, fn, capture); 238 | 239 | var evt = document.createEvent('HTMLEvents'); 240 | evt.initEvent(type, capture || false, false); 241 | //在元素上存储创建的事件,方便自定义触发 242 | if(!element['ev' + type]) { 243 | element['ev' + type] = evt; 244 | } 245 | } else if(window.attachEvent) { 246 | element.attachEvent('on' + type, fn); 247 | if(isNaN(element['cu' + type])) { 248 | //自定义属性,触发事件用 249 | element['cu' + type] = 0; 250 | } 251 | 252 | var fnEv = function(event) { 253 | if(event.propertyName === 'cu' + type) { 254 | fn.call(element); 255 | } 256 | }; 257 | 258 | el.attachEvent('onpropertychange', fnEv); 259 | 260 | //在元素上存储帮的propertychange事件,方便删除 261 | if(!element['ev' + type]) { 262 | element['ev' + type] = [fnEv]; 263 | } else { 264 | element['ev' + type].push(fnEv); 265 | } 266 | } 267 | return this; 268 | }, 269 | triggerEvent: function(type) { 270 | var element = this.element; 271 | if(typeof type === 'string') { 272 | if(document.dispatchEvent) { 273 | if(element['ev' + type]) { 274 | element.dispatchEvent(element['ev' + type]); 275 | } else if(document.attachEvent) { 276 | //改变对应自定义属性,触发自定义事件 277 | element['cu' + type]++; 278 | } 279 | } 280 | } 281 | return this; 282 | }, 283 | removeEvent: function(type, fn, capture) { 284 | var element = this.element; 285 | if(window.removeEventListener) { 286 | element.removeEventListener(type, fn, capture || false); 287 | } else if(window.detachEvent) { 288 | element.detachEvent('on' + type, fn); 289 | var arrEv = element['ev' + type]; 290 | if(arrEv instanceof Array) { 291 | for(var i = 0, len = arrEv.length; i < len; i += 1) { 292 | //删除该方法名下所有绑定的propertychange事件 293 | element.detachEvent('onpropertychange', arrEv[i]); 294 | } 295 | } 296 | } 297 | return this; 298 | } 299 | }; 300 | -------------------------------------------------------------------------------- /javascript自定义事件/事件流.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
A
5 |
B
6 |
C
7 | Parent 8 |
9 |
10 | 75 | -------------------------------------------------------------------------------- /javascript自定义事件/自定义事件.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |

7 | 8 | 9 | 10 |

11 | 12 |

13 | 14 | 15 | 16 |

17 | 18 | 104 | -------------------------------------------------------------------------------- /javascript自定义事件/鼠标跟随.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | Flower Me!!! 4 |
5 | 6 | 26 | -------------------------------------------------------------------------------- /js-对象深拷贝.js: -------------------------------------------------------------------------------- 1 | /*对象深拷贝*/ 2 | /** 3 | 判断obj的类型 4 | */ 5 | var isClass = function(obj) { 6 | if(obj === null) { 7 | return 'Null'; 8 | } 9 | if(obj === undefined) { 10 | return 'Undefined'; 11 | } 12 | return Object.prototype.toString.call(obj).slice(8, -1); 13 | }; 14 | 15 | /*实现对象深拷贝一*/ 16 | var deepClone = function(obj) { 17 | if(typeof obj !== 'object') { 18 | return obj; 19 | } 20 | var classType = isClass(obj); 21 | if(classType === 'Object') { 22 | var newObj = {}; 23 | for(var key in obj) { 24 | newObj[key] = arguments.callee(obj[key]); 25 | } 26 | return newObj; 27 | } else if(classType === 'Array') { 28 | var newArr = []; 29 | for(var i = 0, len = obj.length; i < n; i++) { 30 | newArr.push(obj[i]); 31 | } 32 | return newArr; 33 | } 34 | } 35 | 36 | /*实现对象深拷贝二*/ 37 | function deepClone(obj){ 38 | var result,oClass=isClass(obj); 39 | //确定result的类型 40 | if(oClass==="Object"){ 41 | result={}; 42 | }else if(oClass==="Array"){ 43 | result=[]; 44 | }else{ 45 | return obj; 46 | } 47 | for(key in obj){ 48 | var copy=obj[key]; 49 | if(isClass(copy)=="Object"){ 50 | result[key]=arguments.callee(copy);//递归调用 51 | }else if(isClass(copy)=="Array"){ 52 | result[key]=arguments.callee(copy); 53 | }else{ 54 | result[key]=obj[key]; 55 | } 56 | } 57 | return result; 58 | } -------------------------------------------------------------------------------- /js-闭包.js: -------------------------------------------------------------------------------- 1 | /*闭包:当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。 2 | 作用:1、可以读取函数内部的变量; 3 | 2、让这些变量的值始终保持在内存中。 4 | 应该注意的问题: 5 | 1、由于闭包会使得函数中的变量都保存在内存中,因此对内存消耗很大, 6 | 不能滥用闭包,否则会造成网页性能问题; 7 | 2、闭包会在父函数外部,改变父函数内部变量的值。*/ 8 | 9 | /*闭包详细解析: 10 | function a() { 11 | var i = 0; 12 | function b() { 13 | console.log(++i); 14 | } 15 | return b; 16 | } 17 | var c = a(); 18 | c(); 19 | 涉及到的几个概念:函数的执行环境(excution context),活动对象(call object),作用域(scope),作用域链(scope chain); 20 | 1、当定义函数a的时候,js解释器会将函数a的作用域链设置为定义a时a所在的环境,如果a是一个全局函数,则scope chain中只有window对象; 21 | 2、当执行函数a的时候,a会进入相应的执行环境; 22 | 3、在创建执行环境过程中,首先会给a添加一个scope属性,即a的作用域,其值就为window; 23 | 4、然后执行环境会创建一个活动对象。活动对象也是一个拥有属性的对象,但它不具有原型而且不能通过javascript代码直接访问。 24 | 创建完活动对象后,把活动对象添加到a的作用域链的最顶端。此时a的作用域包含两个对象:a的活动对象和window对象; 25 | 5、在活动对象上添加arguments属性,它保存着调用函数a时所传递的参数; 26 | 6、把函数a的形参和内部函数b的引用也添加到a的活动对象上,在这一步中,完成了b的定义,函数b的作用域链被设置为b所定义的环境,即a的作用域。 27 | 执行b时b的作用域链包含了三个对象:b的活动对象,a的活动对象和window对象。 28 | 29 | 总结:函数的作用域是在定义函数时候就已经确定,而不是在执行的时候确定。 30 | JS垃圾回收机制: 31 | 在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。 32 | 因为函数a被函数b引用,b又被a外的c引用,这就是为什么函数a执行后不会被删除的原因。 33 | */ 34 | /*题目一*/ 35 | var name = 'The Window'; 36 | var Person = { 37 | name:'My Name', 38 | getName:function() { 39 | return function() { 40 | return this.name; 41 | } 42 | } 43 | } 44 | console.log(Person.getName()()); //The Window 45 | 46 | /*题目二*/ 47 | var result = []; 48 | var copyArray = function() { 49 | for(var i = 0; i < 3; i++) { 50 | result[i] = function() { 51 | console.log(i); 52 | } 53 | } 54 | } 55 | copyArray(); 56 | result[0](); //3 57 | result[1](); //3 58 | result[2](); //3 59 | //修改上面的方法,使其输出期望的值 60 | var result = []; 61 | var copyArray = function() { 62 | for(var i = 0; i < 3; i++) { 63 | result[i] = (function(j) { 64 | return function() { 65 | console.log(j); 66 | } 67 | })(i) 68 | } 69 | } 70 | copyArray(); 71 | result[0](); //0 72 | result[1](); //1 73 | result[2](); //2 -------------------------------------------------------------------------------- /js中传递类型.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/js中传递类型.png -------------------------------------------------------------------------------- /js代码重构方案.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/js代码重构方案.doc -------------------------------------------------------------------------------- /js思维导图/jsDOM操作.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/js思维导图/jsDOM操作.gif -------------------------------------------------------------------------------- /js思维导图/js函数基础.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/js思维导图/js函数基础.gif -------------------------------------------------------------------------------- /js思维导图/js变量.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/js思维导图/js变量.gif -------------------------------------------------------------------------------- /js思维导图/js字符串函数.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/js思维导图/js字符串函数.gif -------------------------------------------------------------------------------- /js思维导图/js数组.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/js思维导图/js数组.gif -------------------------------------------------------------------------------- /js思维导图/js正则表达式.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/js思维导图/js正则表达式.gif -------------------------------------------------------------------------------- /js思维导图/js流程语句.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/js思维导图/js流程语句.gif -------------------------------------------------------------------------------- /js思维导图/js运算符.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/js思维导图/js运算符.gif -------------------------------------------------------------------------------- /js数组去重复.js: -------------------------------------------------------------------------------- 1 | /*************************JS数组去除重复********************************************/ 2 | /*数组去重复,基于原型扩展*/ 3 | Array.prototype.removeDuplicate = function() { 4 | var arrObj = {}, 5 | newArr = [], 6 | len = this.length; 7 | for(var i = 0; i < len; i++) { 8 | var value = this[i], 9 | type = (typeof value) + value; 10 | if(arrObj[type] === undefined) { 11 | newArr.push(value); 12 | arrObj[type] = len; 13 | } 14 | } 15 | return newArr; 16 | } 17 | 18 | var s = [1, 1, 2, 3, 4, 5, 4, 3, 4, 4, 5, 5, 6, 7]; 19 | s.removeDuplicate(); //[1, 2, 3, 4, 5, 6, 7] 20 | 21 | /*去除重复后数组为字符串*/ 22 | var removeDuplicate = function(array) { 23 | array = array || []; 24 | var arrObj = {}, 25 | len = array.length; 26 | for(var i = 0; i < len; i++) { 27 | var data = array[i]; 28 | if(typeof(arrObj[data]) === 'undefined') { 29 | arrObj[data] = 1; 30 | } 31 | } 32 | array.length = 0; 33 | for(var arr in arrObj) { 34 | array[array.length] = arr; 35 | } 36 | return array; 37 | } 38 | 39 | var s = [1, 1, 2, 3, 4, 5, 4, 3, 4, 4, 5, 5, 6, 7]; 40 | removeDuplicate(s); //["1", "2", "3", "4", "5", "6", "7"] 41 | 42 | /*去除重复后数组为数字*/ 43 | var removeDuplicate = function(array) { 44 | var str = []; 45 | for(var i = 0, len = array.length; i < len; i++) { 46 | !RegExp(array[i], 'g').test(str.join(',')) && (str.push(array[i])); 47 | } 48 | return str; 49 | } 50 | 51 | var s = [1, 1, 2, 3, 4, 5, 4, 3, 4, 4, 5, 5, 6, 7]; 52 | removeDuplicate(s); //[1, 2, 3, 4, 5, 6, 7] 53 | 54 | /*hashtable的结构记录已有的元素,这样就可以避免内层循环*/ 55 | var removeDuplicate = function(array) { 56 | var hash = {}, 57 | newArr = []; 58 | for(var i = 0, elem; (elem = array[i]) != null; i++) { 59 | if(!hash[elem]) { 60 | newArr.push(elem); 61 | hash[elem] = true; 62 | } 63 | } 64 | return newArr; 65 | } 66 | 67 | var s = [1, 1, 2, 3, 4, 5, 4, 3, 4, 4, 5, 5, 6, 7]; 68 | removeDuplicate(s); //[1, 2, 3, 4, 5, 6, 7] -------------------------------------------------------------------------------- /js知识点1.js: -------------------------------------------------------------------------------- 1 | /*正则表达式*/ 2 | //由数字、字母和加号组成,但加号不能再首位。 3 | ^(?!^\+)(?!.*\+$)[\d+a-z]{1,8}$ 4 | 5 | //整数或正浮点数 6 | ^([1-9]\d*|0)(\.\d{1,2})?$ 7 | 8 | //不能输入重复的字母 9 | ^(?:(?!([a-zA-Z]).*?\1)[A-Za-z])+$ 10 | 11 | /*基础知识点*/ 12 | if(!('a' in window)) { 13 | var a = 1; 14 | } 15 | console.log(a); //undefined 16 | 17 | /*函数声明会覆盖变量声明,但不会覆盖变量赋值*/ 18 | function value() { 19 | return 1; 20 | } 21 | var value; 22 | console.log(typeof value); //function 23 | 24 | function value() { 25 | return 1; 26 | } 27 | var value = 0; 28 | console.log(typeof value); // number 29 | 30 | var a = 1, 31 | b = function a(x) { 32 | x && a(--x); 33 | } 34 | console.log(a); //1 35 | 36 | function a(x) { 37 | return x*2; 38 | } 39 | var a; 40 | console.log(a); //a函数 41 | 42 | function b(x, y, z) { 43 | arguments[2] = 10; 44 | console.log(z); 45 | } 46 | b(1, 2, 3); //10 47 | 48 | function a() { 49 | console.log(this); 50 | } 51 | a.call(null); //window 52 | 53 | /*给string定义一个toUpperCase方法,该方法不需要参数, 54 | 将字符串中字符索引(从0开始)为奇数的字母变为大写,然后返回该字符串。 55 | 例如,输入:console.log(‘xyz’.toUpperCase()),输出:xYz*/ 56 | String.prototype.toUpperCase = String.prototype.toUpperCase || function() { 57 | if('' === this || null === this) { 58 | return ''; 59 | } 60 | var arrayStr = this.split(''); 61 | var resultStr = ''; 62 | for(var i = 0, n = arrayStr.length; i < n; i++) { 63 | if(i % 2 !== 0) { 64 | resultStr += arrayStr[i].toUpperCase(); 65 | } else { 66 | resultStr += arrayStr[i]; 67 | } 68 | } 69 | return resultStr; 70 | }; 71 | console.log('xyz'.toUpperCase()); 72 | 73 | /*typeof instanceof contructor的区别及用法: 74 | 1、typeof:javascript的一元操作符,用于以字符串的形式返回变量的原始类型; 75 | 注意:typeof null也会返回object,大多数的对象类型(数组Array,时间Date等)也都会返回object; 76 | 2、contructor:内部原型属性,可以通过代码重写; 77 | 3、instanceof:javascript操作符,会在原型链中的构造器中搜索,找到返回true,否则返回false。 78 | */ 79 | var arr = [1, 2, 3]; 80 | typeof arr; //object 81 | arr instanceof Array; // true 82 | arr.constructor(); //[] 83 | 84 | /*从数组中随机获取成员*/ 85 | var items = [12, 23, 'abc', 567, 119,'bzn']; 86 | var randomItem = items[Math.floor(Math.random()*items.length)]; 87 | 88 | /*获取指定范围内的随机数 89 | 用处:生成测试用的假数据时候特别有用,如介与指定范围的工资数。 90 | */ 91 | var randomNum = Math.floor(Math.random() * (max - min + 1)) + min; 92 | 93 | /*翻转字符串,abc24fg ---> gf42cba*/ 94 | var testStr = 'abc24fg'; 95 | testStr.split('').sort( 96 | function() { 97 | return 1; 98 | }).join(''); 99 | 100 | /*打乱数字数组的顺序*/ 101 | var numbers = [3,5,75,90,120]; 102 | numbers = numbers.sort(function() { 103 | return Math.random() - 0.5; 104 | }); 105 | //更好的实现 106 | function shuffle(array) { 107 | var tmp, current, top = array.length; 108 | 109 | if(top) while(--top) { 110 | current = Math.floor(Math.random() * (top + 1)); 111 | tmp = array[current]; 112 | array[current] = array[top]; 113 | array[top] = tmp; 114 | } 115 | 116 | return array; 117 | } 118 | 119 | /*生成随机字母数字字符串*/ 120 | var generateRandomAlphaNum = function(len) { 121 | var rdmString = ''; 122 | for( ; rdmString.length < len; rdmString += Math.random().toString(36).substr(2)); 123 | return rdmString.substr(0, len); 124 | } 125 | 126 | /*追加一个数组到另一个数组中*/ 127 | var array1 = [1, 3, 'bai', {name:'bzn'}, -345]; 128 | var array2 = [2, 6, 90, 'bbb', {age: 15}]; 129 | Array.prototype.push.apply(array1, array2); 130 | 131 | /*对象转为数组 待验证 ?????*/ 132 | var argArray = Array.prototype.slice.call(arguments); 133 | 134 | /*验证是否是数字 135 | isFinite() 函数用于检查其参数是否是无穷大 136 | */ 137 | var isNumber = function(n) { 138 | return !isNaN(parseFloat(n)) && isFinite(n); 139 | } 140 | 141 | /*获取数组中最大值和最小值*/ 142 | var numbers = [1, 2, 34, -2, 45, 56, 100, 78, 90]; 143 | var maxInNumbers = Math.max.apply(Math, numbers); 144 | var minInNumbers = Math.min.apply(Math, numbers); 145 | 146 | /*从数组中删除元素 147 | 1、不要使用delete或remove删除元素:对数组使用delete,其实并没有删除掉元素,只是将元素置为undefined; 148 | 2、数组元素删除应使用splice; 149 | 3、删除对象的属性可以使用delete。 150 | */ 151 | var items = [1, 2, 34, -2, 45, 56, 100, 78, 90]; 152 | items.length; //9 153 | delete items[3]; 154 | items.length; //9 155 | //items 的结果为:[1, 2, 34, undefined, 45, 56, 100, 78, 90] 156 | 157 | //正确的应该是: 158 | var items = [1, 2, 34, -2, 45, 56, 100, 78, 90]; 159 | items.length; //9 160 | items.splice(3,1); 161 | items.length; //8 162 | //items 的结果为:[1, 2, 34, 45, 56, 100, 78, 90] 163 | 164 | /**保留指定的小数位数 165 | toFixed() 方法可把 Number 四舍五入为指定小数位数的数字 166 | */ 167 | var num = 2.445566; 168 | num = num.toFixed(2); //2.45 169 | 170 | /*call 和 apply 171 | call和apply在作用上是相同的:更改对象的内部指针,即改变对象的this指向的内容; 172 | call和apply第一个参数意义一样,第二个参数不同: 173 | apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入; 174 | call作为参数传入。 175 | 使用apply的好处:可以直接将函数的arguments对象作为第二个参数传入。 176 | */ 177 | 178 | /*题目一*/ 179 | var Person = function() { 180 | this.value = 'Person对象'; 181 | } 182 | var value = 'Global变量'; 183 | var Student = function() { 184 | console.log(this.value); 185 | } 186 | window.Student(); //Global变量 187 | Student.call(window); //Global变量 188 | Student.call(new Person()); //Person对象 189 | 190 | /*题目二*/ 191 | var Person = new function() { 192 | this.key = 'Person'; 193 | } 194 | var Teacher = function(name) { 195 | var key = 'Teacher'; 196 | console.log(this.key); //Person 197 | console.log(name); //新对象 198 | } 199 | Teacher.apply(Person, ['新对象']); 200 | 201 | /*JS中的关键字this:指代函数上下文,取决于函数是怎样被调用的,而不是 202 | 怎样被定义的。*/ 203 | 204 | /*普通对象与函数对象 205 | 函数对象预定义的属性是prototype; 206 | 普通对象预定义属性为__proto__属性 或 [[prototype]] 207 | 原型对象其实就是普通对象(Function.prototype除外,它是函数对象,但它没有prototype属性) 208 | 209 | */ 210 | function f() {} 211 | var o = new f(); 212 | typeof Object ; //function 213 | typeof o ; //object 214 | 215 | /******************JS原生面试题目**************************/ 216 | //获取页面上的checkbox,不使用第三方框架 217 | var domList = document.getElementsByTagName('input'), 218 | domLen = domList.length, 219 | checkboxList = []; 220 | while(domLen --) { 221 | var checkbox = domList[domLen]; 222 | if(checkbox.type === 'checkbox') { 223 | checkboxList.push(checkbox); 224 | } 225 | } 226 | 227 | //设置一个已知ID的DIV的html内容为travesty,字体颜色设为黑色,不使用第三方库 228 | var div = document.getElementById('ID'); 229 | div.innerHTML = 'travelsky'; 230 | div.style.color = '#000'; 231 | 232 | //当一个DOM节点被点击时候,我们希望执行一个函数,应该怎么做 233 | 1、直接在DOM里绑定事件:
234 | 2、在JS里通过onclick绑定:xxx.onclick = test(); 235 | 3、通过事件添加进行绑定:addEventListener(xxx, 'click', test); 236 | 237 | 那么问题来了,javascript的事件绑定模型都有什么? 238 | 1、事件冒泡:事件开始由最具体的元素接收,然后逐机向上传播; 239 | 2、事件捕捉:事件由最不具体的节点先接收,然后逐级向下,一直到具体的; 240 | 3、DOM事件流:三个阶段(事件捕捉,目标阶段,事件冒泡) 241 | 242 | //已知数组 var strArray = ['Hello', 'World', '!'], 输出Hello World ! 243 | strArray.join(''); 244 | 245 | //已知有字符串var str = get-element-by-tag-name,写一个函数转成驼峰表示法“getElementByTagName” 246 | function convert(val) { 247 | var arr = val.split('-'); 248 | for(var i = 1, n = arr.length; i < n; i++) { 249 | arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substr(1, arr[i].length-1); 250 | } 251 | val = arr.join(''); 252 | return val; 253 | } 254 | convert('get-element-by-tag-name'); 255 | 256 | //var numberArr = [3, 6, 2, 4, 1]; 257 | //1、实现对该数组的倒序,输出[1, 4, 2, 6, 3] 258 | //2、实现该数组的降序排列,输出[6, 4, 3, 2, 1] 259 | numberArr.sort(function(){ 260 | return 1; 261 | }); 262 | 263 | numberArr.sort(function(a,b){ 264 | return a , & , " 进行转义 279 | function escapeHtml(str) { 280 | return str.replace(/[<>"&]/g, function(match) { 281 | switch(match) { 282 | case '<': 283 | return '<'; 284 | case '>': 285 | return '>'; 286 | case '&': 287 | return '&'; 288 | case '\"': 289 | return '"'; 290 | } 291 | }); 292 | } 293 | 294 | /* 295 | 有这样一个URL:http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e, 296 | 请写一段JS程序提取URL中的各个GET参数(参数名和参数个数不确定), 297 | 将其按key-value形式返回到一个json结构中, 298 | 如{a:’1′, b:’2′, c:”, d:’xxx’, e:undefined} 299 | */ 300 | function serilizeUrl(url) { 301 | var getParams = url.split('?')[1], 302 | params = getParams.split('&'), 303 | result = {}; 304 | for(var i = 0, n = params.length; i < n; i++) { 305 | var param = params[i]; 306 | keyValue = param.split('='); 307 | result[keyValue[0]] = keyValue[1]; 308 | } 309 | return result; 310 | } 311 | serilizeUrl('http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e'); 312 | 313 | /* 314 | javascript中callee和caller的作用 315 | caller是返回一个函数的引用,该函数调用了当前函数; 316 | callee是返回正在执行的function函数,也就是所指定的function对象的正文。 317 | */ 318 | 319 | /*callee应用: 320 | 如果一对兔子每月生一对兔子;一对新生兔,从第二个月起就开始生兔子; 321 | 假定每对兔子都是一雌一雄,试问一对兔子,第n个月能繁殖成多少对兔子? 322 | */ 323 | var result = []; 324 | function fn(n) { //斐波那契数列 325 | if(n === 1) { 326 | return 1; 327 | } else if(n === 2) { 328 | return 2; 329 | } else { 330 | if(result[n]) { 331 | return result[n]; 332 | } else { 333 | //argument.callee()表示fn() 334 | result[n] = argument.callee(n-1) + argument.callee(n-2); 335 | return result[n]; 336 | } 337 | } 338 | } -------------------------------------------------------------------------------- /js知识点2.js: -------------------------------------------------------------------------------- 1 | /* 2 | 实现一个函数clone,可以对JavaScript中的5种主要的数据类型 3 | (包括Number、String、Object、Array、Boolean)进行值复制 4 | 5 | 考察知识点: 6 | 考察点1:对于基本数据类型和引用数据类型在内存中存放的是值还是指针这一区别是否清楚 7 | 考察点2:是否知道如何判断一个变量是什么类型的 8 | 考察点3:递归算法的设计 9 | */ 10 | //方法一 11 | Object.prototype.clone = function() { 12 | var obj = this.constructor === Array ? [] : {}; 13 | for(var o in this) { 14 | obj[o] = typeof this[o] === 'object' ? this[o].clone() : this[o]; 15 | } 16 | return obj; 17 | }; 18 | 19 | //方法二 20 | function clone(obj) { 21 | var buf; 22 | if(obj instanceof Array) { 23 | buf = []; 24 | var i = obj.length; 25 | while(i--) { 26 | buf[i] = clone(obj[i]); 27 | } 28 | return buf; 29 | } else if(obj instanceof Object) { 30 | buf = {}; 31 | for(var k in obj) { 32 | buf[k] = clone(obj[k]); 33 | } 34 | return buf; 35 | } else { 36 | return obj; 37 | } 38 | } 39 | 40 | //定义一个log方法,可以替代console.log 41 | function log() { 42 | console.log.apply(console, arguments); 43 | } 44 | 45 | //扩展:定义一个log方法,打印出的内容需要加[travelsky]前缀,比如hello,需要打印出[travelsky]hello 46 | function log() { 47 | //为了使用unshift数组方法 48 | var argus = Array.prototype.slice.call(arguments); 49 | argus.unshift('[travelsky]'); 50 | console.log.apply(console, argus); 51 | } 52 | log('hello'); 53 | 54 | /*上下文*/ 55 | var User = { 56 | count: 1, 57 | getCount: function() { 58 | return this.count; 59 | } 60 | }; 61 | console.log(User.getCount()); //1 62 | var func = User.getCount; 63 | console.log(func()); //undefined 64 | 65 | //如何保证User总是访问到func的上下文呢,即正确返回1 66 | var func = User.getCount.bind(User); 67 | console.log(func()); //1 68 | 69 | //解决bind的兼容性 70 | Function.prototype.bind = Function.prototype.bind || function(context) { 71 | var self = this; 72 | return function() { 73 | return self.apply(context, arguments); 74 | } 75 | } -------------------------------------------------------------------------------- /js继承方式.js: -------------------------------------------------------------------------------- 1 | /*********************Javascript继承*******************************/ 2 | //【方式一:构造继承】把父类的构造函数当成一个普通的方法,放到子类的构造函数中去执行 3 | var Animal = function() { 4 | this.run = function() { 5 | console.log('I can run'); 6 | } 7 | } 8 | var People = function(name) { 9 | //这里传入的就是父类的构造方法,然后执行父类的构造方法,就可以使用父类的方法了 10 | this.father = Animal; 11 | this.father(); 12 | //要删除,否则在子类添加和父类相同名称的方法时,会修改到父类 13 | delete this.father; 14 | this.name = name; 15 | this.say = function() { 16 | console.log('My name is ' + name); 17 | } 18 | } 19 | var Girl = function(name, age) { 20 | this.father = People; 21 | this.father(name); 22 | delete this.father; 23 | this.age = age; 24 | this.introduce = function() { 25 | console.log('My name is ' + name + ', I am ' + age); 26 | } 27 | } 28 | 29 | //测试 30 | var animal = new Animal(); 31 | animal.run(); 32 | var people = new People('baizn'); 33 | people.run(); 34 | people.say(); 35 | var girl = new Girl('lan', 22); 36 | girl.run(); 37 | girl.say(); 38 | girl.introduce(); 39 | 40 | /*构造继承缺点:指定父类,声明父类对象,然后删除临时变量, 41 | 一旦忘记delete,还要承担父类被修改的风险,针对这个,我们可以用call和apply改进*/ 42 | //【方式二:使用call和apply改造构造继承】 43 | var Animal = function() { 44 | this.run = function() { 45 | console.log('I can run'); 46 | } 47 | } 48 | var People = function(name) { 49 | //这里传入的就是父类的构造方法,然后执行父类的构造方法,就可以使用父类的方法了 50 | this.father = Animal; 51 | this.father.call(this, name); 52 | this.name = name; 53 | this.say = function() { 54 | console.log('My name is ' + name); 55 | } 56 | } 57 | var Girl = function(name, age) { 58 | this.father = People; 59 | this.father.apply(this, new Array(name)); 60 | this.age = age; 61 | this.introduce = function() { 62 | console.log('My name is ' + name + ', I am ' + age); 63 | } 64 | } 65 | console.log(girl instanceof Animal); // false 66 | /*总结:构造继承的优点是支持多继承;缺点是只是通过调用父类的构造方法复制父类的属性和方法到子类中, 67 | 其他什么都没做,严格来说都不能称为继承;不支持instanceof。*/ 68 | 69 | //【方式三:原型继承】 70 | var Point = function(dimension) { 71 | this.dimension = dimension; 72 | this.test = function() { 73 | console.log('dimension:' + dimension); 74 | } 75 | }; 76 | 77 | var Point2D = function(x, y) { 78 | this.x = x; 79 | this.y = y; 80 | }; 81 | 82 | Point2D.prototype = new Point(2); 83 | //测试 84 | var point2D = new Point2D(3,4); 85 | point2D.test(); //dimension:2 86 | console.log(point2D instanceof Point); // true 87 | 88 | //【方式四:混合继承】:构造继承和原型继承 89 | var People = function(name) { 90 | this.name = name; 91 | this.sayName = function() { 92 | console.log('My Name is :' + name); 93 | } 94 | } 95 | 96 | var Girl = function(name, age) { 97 | //构造继承 98 | this.father = People; 99 | this.father(name); 100 | delete this.father; 101 | this.introduce = function() { 102 | console.log('My name is ' + name + ', I am ' + age); 103 | } 104 | } 105 | //原型继承 106 | Girl.prototype = new People(); 107 | 108 | //测试 109 | var girl = new Girl('xuan', 22); 110 | console.log(girl instanceof People); 111 | girl.sayName(); 112 | girl.introduce(); 113 | 114 | //【方式五:实例继承法】:只用于核心对象的继承 115 | var ExtendingError = function(msg) { 116 | var errorInstance = new Error(msg); 117 | errorInstance.errorMsg = function() { 118 | console.log('ErrorInfo is:' + msg); 119 | } 120 | return errorInstance; 121 | }; 122 | 123 | //测试 124 | var errorInfo = new ExtendingError('number is less than 0'); 125 | errorInfo.errorMsg(); 126 | console.log(errorInfo.toString()); 127 | 128 | //【方式六:拷贝继承】:将对象的属性和方法一一复制 129 | Function.prototype.Extend = function(obj) { 130 | for(var pro in obj) { 131 | this.prototype[pro] = obj[pro]; 132 | } 133 | } 134 | 135 | function Animal() {} 136 | function People() {} 137 | People.Extend(new Animal()); 138 | /*缺点: 139 | 1、将对象的属性方法一一复制的时候,其实用的就是反射,反射对效率影响很大; 140 | 2、和原型继承一样,必须初始化父类对象,当确定继承关系时,但参数还不确定就不适用。 141 | */ 142 | 143 | /*经典javascript构造器*/ 144 | function Rectangle(width, height) { 145 | this.width = width; 146 | this.height = height; 147 | } 148 | Rectangle.prototype.getArea = function() { 149 | return this.width * this.height; 150 | } 151 | Rectangle.prototype.getPerimeter = function() { 152 | return 2 * (this.width + this.height); 153 | } 154 | Rectangle.prototype.toString = function() { 155 | return this.constructor.name + 'a = ' + this.getArea() + 'p = ' + this.getPerimeter(); 156 | } 157 | 158 | function Square(side) { 159 | this.width = side; 160 | this.height = side; 161 | } 162 | //Square继承Rectangle 163 | Square.prototype = Object.create(Rectangle.prototype, { 164 | constructor:{ 165 | value:Square 166 | } 167 | }); 168 | Square.prototype.getPerimeter = function() { 169 | return this.width * 4; 170 | } 171 | 172 | /*纯原型继承*/ 173 | //定义Rectangle原型 174 | var Rectangle = { 175 | name:'Rectangle', 176 | getArea: function() { 177 | return this.width * this.height; 178 | }, 179 | getPerimeter: function() { 180 | return 2 * (this.width + this.height); 181 | }, 182 | toString: function() { 183 | return this.name + ' a = ' + this.getArea() + ' p = ' + this.getPerimeter(); 184 | } 185 | }; 186 | 187 | //定义Square子对象覆盖一些属性来改变行为 188 | var Square = Object.create(Rectangle); 189 | Square.name = 'Square'; 190 | Square.getArea = function() { 191 | return this.width * this.height; 192 | } 193 | Square.getPerimeter = function() { 194 | return this.width * 4; 195 | } 196 | 197 | //创建对象 198 | var rect = Object.create(Rectangle); 199 | rect.width = 6; 200 | rect.height = 4; 201 | var square = Object.create(Square); 202 | square.width = 5; 203 | console.log(rect.toString()); 204 | console.log(square.toString()); 205 | 206 | /*对象工厂 207 | 创建对象最受欢迎的方法之一是使用工厂函数。区别在于以前使用共享函数产生原型对象 208 | 再创建这些对象的实例,现在是调用一个函数来返回对象实例。 209 | */ 210 | function Controllor(model, view) { 211 | view.update(model.value); 212 | return { 213 | up: function(evt) { 214 | model.value ++; 215 | view.update(model.value); 216 | }, 217 | down: function(evt) { 218 | model.value --; 219 | view.update(model.value); 220 | }, 221 | save: function(evt) { 222 | model.save(); 223 | view.close(); 224 | } 225 | }; 226 | } 227 | 228 | var on = Controllor({ 229 | value: 5, 230 | save: function() { 231 | console.log('Saving value ' + this.value + 'someWhere'); 232 | } 233 | },{ 234 | update: function(newValue) { 235 | console.log('View now has ' + newValue); 236 | }, 237 | close: function() { 238 | console.log('Now hiding view'); 239 | } 240 | }); 241 | setTimeout(on.up, 100); 242 | setTimeout(on.down, 200); 243 | setTimeout(on.save, 300); 244 | 245 | //输出 246 | View now has 5 247 | View now has 6 248 | View now has 5 249 | Saving value 5 somewhere 250 | Now hiding view -------------------------------------------------------------------------------- /基于jQuery的插件开发.js: -------------------------------------------------------------------------------- 1 | /* 2 | 基于jQuery的插件开发: 3 | 1、类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法, 4 | jQuery的全局函数就是属于jQuery命名空间的函数; 5 | 1.1添加一个新的全局函数: 6 | jQuery.sum = function(a, b) { 7 | return a + b; 8 | } 9 | 调用时:jQuery.sum(1, 2) 或 $.sum(1, 2); 10 | 1.2增加多个全局函数: 11 | jQuery.sum = function(a, b) { 12 | return a + b; 13 | }; 14 | jQuery.dup = function(a, b) { 15 | return a - b; 16 | }; 17 | 调用时同上。 18 | 1.3使用jQuery.extend(object): 19 | jQuery.extend({ 20 | sum:function(a, b) { 21 | return a + b; 22 | }, 23 | dup:function(a, b) { 24 | return a - b; 25 | } 26 | }); 27 | 1.4使用命名空间: 28 | 为了避免函数名及变量名与其他jQuery插件冲突,我们可以添加自定义命名空间。 29 | jQuery.String = { 30 | sum:function(a, b) { 31 | return a + b; 32 | }, 33 | dup:function(a, b) { 34 | return a - b; 35 | } 36 | }; 37 | 采用命名空间的函数仍然是全局函数,调用时采用的方法:$.String.sum(1, 2)。 38 | 2、对象级别的插件开发,即给jQuery对象添加方法。 39 | 2.1形式一: 40 | (function($) { 41 | $.fn.extend({ 42 | sum:function(opt, callback) { 43 | 44 | } 45 | }) 46 | })(jQuery); 47 | 2.2形式二: 48 | (function($) { 49 | $.fn.sum = function() { 50 | 51 | }; 52 | })(jQuery); 53 | 2.3接收options参数以控制插件的行为 54 | $.fn.sum = function(options) { 55 | var defaults = { 56 | foreground:'red' 57 | }; 58 | var opts = $.extend(defaults, options); 59 | //插件具体功能 60 | 61 | } 62 | 2.4暴露插件的默认设置 63 | $.fn.sum = function(options) { 64 | var opts = $.extend({}, $.fn.sum.defaults, options); 65 | //插件的具体实现 66 | 67 | }; 68 | $.fn.sum.defaults = { 69 | foreground:'red' 70 | }; 71 | 使用者可以这样调用:$.fn.sum.defaults.foreground = 'blue'; 72 | 这个只需要调用一次,且不需要在ready块中调用。 73 | $('#id').sum(); 74 | 也可以通过传递配置参数给插件的方法来覆盖缺省设置: 75 | $('#blue').sum({ 76 | foreground:'blue' 77 | }); 78 | 2.5适当的暴露一些函数 79 | $.fn.sum = function(options) { 80 | return this.each(function() { 81 | var $this = $(this); 82 | //具体实现代码 83 | 84 | var markup = $this.html(); 85 | markup = $.fn.sum.format(markup); 86 | $this.html(markup); 87 | }); 88 | }; 89 | //定义format函数 90 | $.fn.sum.format = function(txt) { 91 | return '' + txt + ''; 92 | } 93 | 2.6保持私有函数的私有性 94 | (function($) { 95 | //插件定义 96 | $.fn.sum = function(options) { 97 | debug(this); 98 | //具体实现 99 | ... 100 | }; 101 | 102 | //私有函数定义 103 | var debug = function($obj) { 104 | if(window.console && window.console.log) { 105 | window.console.log('selection count:' + $obj.size()) 106 | } 107 | }; 108 | })(jQuery); 109 | */ 110 | ;(function($) { 111 | //插件的定义 112 | $.fn.hilight = function(options) { 113 | debug(this); 114 | var opts = $.extend({}, $.fn.hilight.defaults, options); 115 | return this.each(function() { 116 | var $this = $(this); 117 | var o = $.meta ? $.extend({}, opts, $this,data()) : opts; 118 | //更新元素样式 119 | $this.css({ 120 | backgroundColor:o.backround, 121 | color:o.foreground 122 | }); 123 | var markup = $this.html(); 124 | markup = $.fn.format(markup); 125 | $this.html(markup); 126 | }); 127 | }; 128 | //私有函数 129 | var debug = function($obj) { 130 | if(window.console && window.console.log) { 131 | window.console.log('selection count:' + $obj.size()) 132 | } 133 | }; 134 | 135 | //定义暴露函数format 136 | $.fn.hilight.format = function(txt) { 137 | return '' + txt + ''; 138 | }; 139 | 140 | //插件的defaults 141 | $.fn.hilight.defaults = { 142 | foreground:'red', 143 | background:'yellow' 144 | }; 145 | })(jQuery); -------------------------------------------------------------------------------- /拖拽div/dialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test 5 | 58 | 59 | 60 |
61 | 62 | 63 | 64 |
65 | 66 |
Dialog
67 |
68 | 69 |
70 |
71 | 72 | 109 | 110 | 117 | 118 | 144 | 145 | 157 | 158 | -------------------------------------------------------------------------------- /拖拽div/drag.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/拖拽div/drag.js -------------------------------------------------------------------------------- /拖拽div/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baizn/javascript-core-base/49ea0458072e0e0725d05c4b8a2ae61879f074c7/拖拽div/index.html --------------------------------------------------------------------------------