已阅冴羽大佬文章 | 字数总计: 7.5k | 阅读时长: 31分钟 | 阅读量:
顺便宣传一下:Github来源: | 求星星 ✨ | 欢迎 star,鼓励一下作者。
希望能够帮助更多的小伙伴。加我😚即可交流问题(不是大佬,互相学习,创造良好的学习环境)。以下哪些你不懂呢?
扩展的对象功能
命名一个函数为 createPerson()
,其作用创建了一个对象:
1 2 3 4 5 6 function createPerson(name, age) { return { name: name, age: age }; }
当对象的一个属性名称与本地变量名相同时,ES6:
1 2 3 4 5 6 function createPerson(name, age) { return { name, age }, }
当对象字面量中的属性只有名称时, JS 引擎会在周边作用域查找同名变量。若找到,该变量 的值将会被赋给对象字面量的同名属性。
es5写法:
1 2 3 4 5 6 var person = { name: 'jeskson', sayName: function() { console.log(this.name); } };
es6写法:
1 2 3 4 5 6 var person = { name: 'jeskson', sayName() { console.log(this.name); } };
示例:
1 2 3 4 5 6 var person = {}, lastName = "last name"; person["first name"] = "da1"; person[lastName] = "da2"; console.log(person["first name"]); // da1 console.log(person[lastName]); // da2
示例中两个属性名包含了空格,不能使用小数点表示法来引用它们,方括号表示法允许将任意字符串用作属性名。
示例优化:
1 2 3 4 var person = { "first name": "jeskson" }; console.log(person["first name"]); // jeskson
1 2 3 4 5 6 7 var lastName = "last name"; var person = { "first name": "da1", [lastName]: "da2" }; console.log(person["first name"]); // "da1" console.log(person[lastName]); // "da2"
对象字面量内的方括号表明该属性名需要计算,结果是一个字符串
示例:
1 2 3 4 5 6 7 var da = " name"; var pserson = { ["first + da ]: "da1", ["last" + da ]: "da2" }; console.log(person["first name"]); // "da1" console.log(person["last name"]); // "da2"
相等运算符( == )
或严格相等运算符( === )
ES6: Object.is()
,返回true,要求二者类型相同并且值也相等
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 console.log(+0 == -0); // true console.log(+0 === -0); // true console.log(Object.is(+0, -0)); // false console.log(NaN == NaN); // false console.log(NaN === NaN); // false console.log(Object.is(NaN, NaN)); // true console.log(5 == 5); // true console.log(5 == "5"); // true console.log(5 === 5); // true console.log(5 === "5"); // false console.log(Object.is(5, 5)); // true console.log(Object.is(5, "5")); // false
混入( Mixin )
是在 JS 中组合对象时最流行的模式。
浅复制,当属性值为对象时,仅复制其引用
1 2 3 4 5 6 function mixin(receiver, supplier) { Object.keys(supplier).forEach(function(key) { receiver[key] = supplier[key]; }); return receiver; }
Object.assign()
方法,该方法 接受一个接收者,以及任意数量的供应者,并会返回接收者。
示例:
1 2 3 4 5 6 "use strict"; var person = { name: "da1", name: "da2" // 在 ES6 严格模式中不会出错 }; console.log(person.name); // "da2"
自有属性的枚举顺序
修改对象的原型
Object.getPrototypeOf()
方法来从任意指定对象中获取其原型
Object.setPrototypeOf()
方法修改任意指定对象的原型
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let person = { getGreeting() { return "hello"; } }; let dog = { getGreeting() { return "hai"; } }; let friend = Object.create(person); console.log(friend.getGreeting()); // "hello" console.log(Object.getPrototypeOf(friend) === person); // true Object.setPrototypeOf(friend, dog); console.log(friend.getGreeting()); // "hai" console.log(Object.getPrototypeOf(friend) === dog); // true
使用 super 引用的简单原型访问
Object.getPrototypeOf()
方法确保了能调用正确的原型,并在其返回结果上附加了一个字符串。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 let person = { getGreeting() { return "hello" } }; let dog = { getGreeting() { return "woof"; } }; let friend = { getGreeting() { return Object.getPrototypeOf(this).getGreeting.call(this) + ", hi!"; } }; Object.setPrototypeOf(friend, person); console.log(friend.getGreeting()); // "hello hi!" console.log(Object.getPrototypeOf(frined) === person); // true Object.setPrototypeOf(friend,dog); console.log(friend,getGreeting()); // "woof, hi!" console.log(Object.getPrototypeOf(friend) === dog); // true
call(this)
,能确保正确设置原型方法内部的this
值
super
是指向当前对象的原型的一个指针
示例:
1 2 3 4 5 6 let friend = { getGreeting() { // Object.getPrototypeOf(this).getGreeting.call(this) return super.getGreeting() + ", hi!"; } }
使用ES6的super
,示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 let person = { getGreeting() { return "hello"; } }; let friend = { getGreeting() { return super.getGreeting() + ", hi!"; }; Object.setPrototypeOf(friend, person); let relative = Object.create(friend); console.log(person.getGreeting()); // "hello" console.log(friend.getGreeting()); // "hello, hi!" console.log(relative.getGreeting()); // "hello, hi!"
深入系列专题 1.JavaScript 深入之从原型到原型链
2.JavaScript 深入之词法作用域和动态作用域
3.JavaScript深入之执行上下文栈
4.JavaScript深入之变量对象
5.JavaScript深入之作用域链
6.JavaScript 深入之从 ECMAScript 规范解读 this
7.JavaScript深入之执行上下文
8.JavaScript深入之闭包
9.JavaScript深入之参数按值传递
10.JavaScript深入之call和apply的模拟实现
11.JavaScript深入之bind的模拟实现
12.JavaScript深入之new的模拟实现
13.JavaScript 深入之类数组对象与 arguments
14.JavaScript深入之创建对象的多种方式以及优缺点
面向对象
ES6 class语法
三要素
UML
类图
初始化npm
环境
安装webpack
安装webpack-dev-server
安装babel
npm init
package.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // package.json // "dev": "wepack --config ./webpack.dev.config.js --mode development" { "name": "design-pattern-text", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server --config ./webpack.dev.config.js --mode development" }, "author": "", "license": "ISC", "devDependencies": { "html-webpack-plugin": "", "webpack": "", "webpack-cli": "", "webpack-dev-server": "" } }
npm install webpack webpack-cli --save-dev
webpack.dev.config.js
1 2 3 4 5 6 7 8 // webpack.dev.config.js module.exports = { entry: './src/index.js‘, output: { path: __dirname, filename: './release/bundle.js' } }
npm run dev
npm install webpack-dev-server html-webpack-plugin --save-dev
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 // webpack.dev.config.js const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js‘, output: { path: __dirname, filename: './release/bundle.js' }, module: { rules: [{ test: /\.js?$/, exclude: /(node_modules)/, loader: 'babel-loader' // es6语法转es5语法 }] }, glugins: [ new HtmlWebpackPlugin({ template: './index.html' }) ], devServer: { contentBase: path.jon(__dirname,'./release'), // 根目录 open: true, // 自动打开浏览器 port: 8080 // 端口 } }
解析es6
npm install babel-core babel-loader babel-polyfill babel-preset-es2015 babel-preset-latest --save-dev
1 2 3 4 5 // 根目录.babelrc { "presets": ["es2015", "latest"], "plugins": [] }
什么是面向对象
概念
三要素:继承,封装,多态
JS的应用举例
面向对象的意义
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 // 类 class People { constructor(name,age) { this.name = name this.age = age } eat() { alert(`${this.name} eat something`) } speak() { alert(`My name is ${this.name}, age ${this.age}`) } }
1 2 3 4 5 6 7 8 9 10 // 对象(实例) // 创建实例 let da1 = new Perople('jeskson1', 12) da1.eat() da1.speak() // 创建实例 let da2 = new People('jeskson2', 13) da2.eat() da2.speak()
继承,封装,多态
继承,子类继承父类
封装,数据的权限和保密
多态,同一接口不同实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // 继承 class People { constructor(name,age) { this.name = name this.age = age } eat() { alert(`${this.name} eat something`) } speak() { alert(`My name is ${this.name}, age ${this.age}`) } } // 子类继承父类 class Student extends People { constructor(name, age, number) { super(name, age) this.number = number } study() { alert(`${this.name} study`) } }
1 2 3 4 5 // 实例 let jeskson1 = new Student('da1', 10, '01') jeskson1.study() console.log(jeskson1.number) jeskson1.eat()
继承可将共功方法抽离出来,提高复用
封装(public
完全开发,protected
对子类开放,private
对自己开放)
使用typescript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // 封装 父类 class People { public name private age protected weight constructor(name, age) { this.name = name this.age = age this.weight = 223 } eat() { alert(`${this.name} eat something`) } speak() { alert(`My name is ${this.name}, age ${this.age}`) } }
1 2 3 4 5 6 7 8 9 10 11 12 // 子类 class Student extends People { number private grilfriend constructor(name, age, number) { super(name,age) this.number = number this.girlfriend = '小舞' } study() {} getWeight() {} }
减少耦合,不该外露的不外露;利用数据,接口的权限管理;一般_
开头的属性是private
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 // 保持子类的开放性和灵活性 class People { constructor(name) { this.name = name } say() {} } class A extends People { constructor(name) { super(name) } say() {console.log('A dadaqianduan.cn')} } class B extends People { constructor(name) { super(name) } say() {console.log('B dadaqianduan.cn')} } let a = new A('a') a.say() let b = new b('b') b.say()
UML类图
15.JavaScript深入之继承的多种方式和优缺点
JavaScript专题 1.JavaScript专题之跟着underscore学防抖
在前端开发中会遇到一些频繁的事件触发,如:
window 的 resize、scroll
mousedown、mousemove
keyup、keydown
2.JavaScript专题之跟着 underscore 学节流
3.JavaScript专题之数组去重
4.JavaScript专题之类型判断(上)
5.JavaScript专题之类型判断(下)
在 ES6 前,JavaScript 共六种数据类型
1 Undefined 、Null 、Boolean 、Number 、String 、Object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [object Number] [object String] [object Boolean] [object Undefined] [object Null] [object Object] [object Array] [object Date] [object Error] [object RegExp] [object Function] [object Math] [object JSON] [object Arguments]
1 2 3 4 5 6 7 8 // jquery: type: function(obj) { if(obj == null) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[toString.call(obj) ] || "object" : typeof obj; }
6.JavaScript专题之深浅拷贝
对象:对象通过两种形式定义:1,声明形式;2,构造形式
1 2 3 var myObj = {...}; var myObj = new Object();
类型:对象是JavaScript的基础。6种主要类型:
string
number
boolean
null
undefined
object
简单基本类型,string, number, boolean, null, undefined
本身不是对象,null
执行typeof null
时会返回字符串object
,实际上,null
本身是基本类型。
函数就是对象的一个子类型,JavaScript中的函数是“一等公民”,因为它们本质上和普通的对象一样,所以可以像操作其他对象一样操作函数。
常见内置对象:
String
Number
Boolean
Object
Function
Array
Date
RegExp
Error
ES6定义了Object.assign(...)
方法来实现浅复制。
Object.assign(...)
方法的第一个参数是目标对象,之后还可以跟一个或多个源对象。它会遍历一个或多个源对象的所有可枚举的自有键并把它们复制到目标对象,最后返回目标对象
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function anotherFunction() { /*..*/ } var anotherObject = { c: true }; var anotherArray = []; var myObject = { a: 2, b: anotherObject, // 引用,不是复本! c: anotherArray, // 另一个引用! d: anotherFunction }; anotherArray.push( anotherObject, myObject ); var newObj = Object.assign( {}, myObject ); newObj.a; // 2 newObj.b === anotherObject; // true newObj.c === anotherArray; // true newObj.d === anotherFunction; // true
属性描述符
1 2 3 4 5 6 7 8 9 10 11 12 13 var myObject = { a: 2 }; Object.getOwnPropertyDescriptor(myObject, "a"); // { // value: 2, // writable: true, // enumerable: true, // configurable: true, // } // writable可写 // enumerable可枚举 // configurable可配置
1 2 3 4 5 6 7 8 var myObject = {}; Object.defineProperty(myObject, "a", { value: 2, writable: true, configurable: true, enumerable: true }); myObject.a; // 2
使用defineProperty(...)
给myObject
添加了一个普通的属性并显式指定了一些特性。
示例:
1 2 3 4 5 6 7 8 9 10 11 var myObject = {}; Object.defineProperty(myObject,"a",{ value: 2, writable: false, // 不可写 configurable: true, enumerable: true }); myObject.a = 3; myObject.a; // 2
configurable
,只要属性是可配置的,就可以使用defineProperty(...)
方法来修改属性描述符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var myObject = { a: 2 }; myObject.a = 3; myObject.a; // 3 Object.defineProperty(myObject, "a", { value: 4, writable: true, configurable: false, // 不可配置 enumerable: true }); myObject.a; // 4 myObject.a = 5; myObject.a; //5 Object.defineProperty(myObject, "a", { value: 6, wirtable: true, configurable: true, enumerable: true }); // TypeError
enumerable
,控制的是属性是否会出现在对象的属性枚举中。
1 2 3 4 5 6 7 // 创建一个真正的常量属性,不可修改,重定义,删除 var myObject = {}; Object.defineProperty(myObject, "a", { value: 1, writable: false, configurable: false });
1 2 3 4 5 6 7 8 // 禁止扩展,使用Object.preventExtensions(...) // 禁 止 一 个 对 象 添 加 新 属 性 并 且 保 留 已 有 属 性 var myObject = { a: 2 }; Object.preventExtensions(myObject); myObject.b = 3; myObject.b; // undefined
密封:Object.seal(...)
会创建一个“密封”的对象,这个方法实际上会在一个现有对象上调用Object.preventExtensions(...)
并把所有现有属性标记为configurable:false
(虽然可以 修改属性的值)。
冻结:Object.freeze(..)
会创建一个冻结对象,这个方法实际上会在一个现有对象上调用 Object.seal(..)
并把所有“数据访问”属性标记为 writable:false
,这样就无法修改它们的值。
getter
,setter
getter
是一个隐藏函数,会在获取属性值 时调用
setter
是一个隐藏 函数,会在设置属性值时 调用
存在性
示例:
1 2 3 4 5 6 7 var myObject = { a: 2 }; ("a" in myObject); // true ("b" in myObject); // false myObject.hasOwnProperty("a"); // true myObject.hasOwnProperty("b"); // false
in
操作符会检查属性是否在对象及其[[Prototype]]
原型链中
hasOwnProperty(...)
只会检查属性是否在myObject
对象中,不会检查[[Prototype]]
链
枚举
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var myObject = {}; Object.defineProperty( myObject, "a", { enumerable: true, value: 2 } ); Object.defineProperty( myObject, "b", { enumerable: false, value: 3} ); myObject.b; // 3 ("b" in myObject); // true myObject.hasOwnProperty("b"); // true for(var k in myObject) { console.log(k, myObject[k]); } // "a" 2
检查属性是否可枚举:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var myObject = {}; Object.defineProperty( myObject, "a", {enumerable: true, value: 2} ); Object.defineProperty( myObject, "b", {enumerable: false, value:3} ); myObject.propertyIsEnumerable("a"); // true myObject.propertyIsEnumerable("b"); // false Object.keys(myObject); // ["a"] Object.getOwnPeropertyNames(myObject); // ["a", "b"]
propertyIsEnumerable(...)
会检查给定的属性名是否直接存在于对象中,并满足enumerable: true
Object.keys(...)
会返回一个数组,包含所有可枚举属性
Object.getOwnPropertyNames(...)
会返回一个数组,包含所有属性,无论它们是否可枚举
in
和hasOwnProperty(...)
的区别在于是否查找[[Prototype]]
链
Object.keys(...)
和Object.getOwnPropertyNames(...)
都只会查找对象直接包含的属性
可以使用 Object.preventExtensions(..)、Object.seal(..) 和 Object.freeze(..)
来设置对象的不可变性级别。
遍历
ES6
方法:forEach()
,every()
,some()
forEach(...)
会遍历数组中的所有值并忽略回调函数的返回值
every(...)
会一直运行直到回调函数返回false
some(...)
会一直运行直到回调函数返回true
ES6
中新增加了一种用来遍历数组的for...of
循环语法:
示例:
1 2 3 4 5 6 7 var myArray = [1,2,3]; for(var v of myArray) { console.log(v); } // 1 // 2 // 3
7.JavaScript 专题之从零实现 jQuery 的 extend
8.JavaScript 专题之如何求数组的最大值和最小值
1 2 3 4 5 var arr = [ 2,34,5,8]; function max(prev, next) { return Math.max(prev, next); } console.log(arr.reduce(max));
1 2 arr.sort(function(a,b){return a-b;}); console.log(arr[arr.length-1]);
1 2 3 4 5 var max = eval("Math.max(" + arr + ")"); Math.max.applly(null, arr); Math.max(...arr);
9.JavaScript 专题之数组扁平化
10.JavaScript专题之学underscore在数组中查找指定元素
11.JavaScript专题之jQuery通用遍历方法each的实现
12.JavaScript 专题之如何判断两个对象相等
构造函数,类的继承,混入
构造函数:类实例是由一个特殊的类方法构造的,这个方法名通常和类名相同,称为构造函数。这个方法的任务就是 初始化实例需要的所有信息。
类的继承:在面向类的语言中,你可以先定义一个类,然后定义一个继承前者的类。后者通常被称为“子类”,前者通常被称为“父类”。
混入:在继承或者实例化时,JavaScript的对象机制并不会自动执行复制行为。简单来说,JavaScript中只有对象,并不存在可以被实例化的“类”复制行为,在JavaScript中模拟类的复制行为,这个方法就是混入。
两种类型的混入:1,显式;2,隐式
示例:
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 function mixin( sourceObj, targetObj ) { for (var key in sourceObj) { // 只会在不存在的情况下复制 if(!(key in targetObj)) { targetObj[key] = sourceObj[key]; } } return targetObj; } var Vehicle = { engines: 1, ignition: function() { console.log("truing on my engine"); }, drive: function() { this.ignition(); console.log("steering and moving forward!"); } }; var Car = mixin(Vehicle, { wheels: 4, drive: function() { Vehicle.drive.call(this); // 多态 console.log( "Rolling on all" + this.wheels + "wheels" }; } });
寄生继承
显式混入模式的一种变体被称为“寄生继承”,它既是显式的又是隐式的。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function Vehicle() { this.engines = 1; } Vehicle.prototype.ignition = function() { console.log("turning on my engine"); }; Vehicle.prototype.drive = function() { this.ignition(); console.log("steering and moving forward"); }; // 寄生类Car function Car() { var car = new Vehicle(); car.wheels = 4; var vehDrive = car.drive; // 重写 car.drive = function() { vehDrive.call(this); console.log("rolling on all" + this.wheels + "wheels"); return car; } myCar.drive();
隐式混入
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var Something = { cool: function() { this.greeting = "hello world"; this.count = this.count ? this.count + 1 : 1; } }; Something.cool(); Something.greeting; / "hello world" Something.count; // 1 var Another = { cool: function() { // 隐式把Something 混入Another Something.cool.call(this); } }; Another.cool(); Another.greeting; // "hello world" Another.count; // 1 (count不是共享状态)
W3C标准事件流 W3C标准事件流: 包含3个阶段,捕获阶段,目标阶段,冒泡阶段。
在捕获阶段 ,事件对象通过目标的祖先从窗口传播到目标的父级。
在目标阶段 ,事件对象到达事件对象的事件目标。
在冒泡阶段 ,事件对象以相反的顺序通过目标的祖先传播,从目标的父级开始,到窗口结束。
先从顶层对象 window
开始一路向下捕获,直到达到目标元素,其后进入目标阶段。
目标元素 div 接收到事件后开始冒泡到顶层对象 window
。
单击了<div>
元素,则首先会进行事件捕获,此时事件按 window→document→<html>→<body>
的顺序进行传播
当事件对象传到 <div>
时进入目标阶段,接着事件对象又从目标对象传到 body
,从而进入事件的冒泡阶段
事件对象按 <body>→<html>→document→window
的顺序传播事件。
13.JavaScript 专题之函数柯里化
14.JavaScript 专题之惰性函数
15.JavaScript专题之函数组合
16.JavaScript 专题之函数记忆
17.JavaScript专题之递归
18.JavaScript专题之乱序
19.JavaScript专题之解读 v8 排序源码
原型
JavaScript中的对象有一个特殊的[[Prototype]]
内置属性,其实就是对于其他对象的引用。几乎所有的对象在创建时[[Prototype]]
属性都会被赋予一个非空的值。
使用in
操作符来检查属性在对象中是否存在时,同样会查找对象的整条原型链。
示例:
1 2 3 4 5 6 7 8 9 10 var anotherObject = { a: 2 }; // 创建一个关联到anotherObject的对象 var myObject = Object.create(anthorObject); for(var k in myObject) { console.log("found:" + k); } // found:a ("a" in myObject); // true
Object.prototype
所有普通的 [[Prototype]]
链最终都会指向内置的 Object.prototype
所有的函数默认都会拥有一个名为 prototype
的公有并且不可枚举的属性,它会指向另一个对象
1 2 3 4 function Foo() { // ... } Foo.prototype; // { }
这个对象通常被称为 Foo 的原型,因为我们通过名为 Foo.prototype 的属性引用来访问它
1 2 3 var a = new Foo(); Object.getPrototypeOf( a ) === Foo.prototype; // true
new Foo()
会生成一个新对象,这个新对象的内部链接 [[Prototype]]
关联 的是 Foo.prototype
对象
Object.create(...)
会创建一个新对象并把它关联到我们指定的对象,Object.create(null)
会创建一个拥有空链接的对象,这个对象无法进行委托。
由于这个对象没有原型链,所以instanceof
操作符无法进行判断,因此总是会返回false。这些特殊的空[[Prototype]]
对象通常被称为“字典”,它们完全不会受到原型链的干扰,非常适合用来存储数据。
示例:
1 2 3 4 5 6 7 8 // polyfill 代码 if(!Object.create) { Object.create = function(o) { function F(){} F.prototype = o; return new F(); // 构造一个新对象进行关联 }; }
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var anotherObject = { a: 2 }; var myObject = Object.create( anotherObject, { b: { enumerable: false, writable: true, configurable: false, value: 3 }, c: { enumerable: true, writable: false, configurable: false, value: 4 } }); myObject.hasOwnProperty( "a" ); // false myObject.hasOwnProperty( "b" ); // true myObject.hasOwnProperty( "c" ); // true myObject.a; // 2 myObject.b; // 3 myObject.c; // 4
示例:
1 2 3 4 5 6 7 8 9 10 var anotherObject = { cool: function() { console.log("cool"); } }; var myObject = Object.create(anotherObject); myObject.doCool = function() { this.cool(); // 内部委托 }; myObject.doCool(); // "cool"
使用new
调用函数时会把新对象的.prototype
属性关联到“其他对象”。带new
的函数调用通常被称为“构造函数调用”。
对象之间是通过内部的[[Prototype]]
链关联的。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Task { id; // 构造函数Task() Task(ID) { id = ID; } outputTask() {output(id); } } class XYZ inherits Task { label; // 构造函数 XYZ() XYZ(ID,Label) { super( ID ); label = Label; } outputTask() { super(); output( label ); } } class ABC inherits Task { // ... }
推荐代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Task = { setID: function(ID) { this.id = ID; }, outputID: function() { console.log( this.id ); } }; // 让 XYZ 委托 Task XYZ = Object.create( Task ); XYZ.prepareTask = function(ID,Label) { this.setID( ID ); this.label = Label; }; XYZ.outputTaskDetails = function() { this.outputID(); console.log( this.label ); }; // ABC = Object.create( Task );
面向对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function Foo(who) { this.me = who; } Foo.prototype.identify = function() { return "I am " + this.me; }; function Bar(who) { Foo.call( this, who ); } Bar.prototype = Object.create( Foo.prototype ); Bar.prototype.speak = function() { alert( "Hello, " + this.identify() + "." ); }; var b1 = new Bar( "b1" ); var b2 = new Bar( "b2" ); b1.speak(); b2.speak();
对象关联:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Foo = { init: function(who) { this.me = who; }, identify: function() { return "I am " + this.me; } }; Bar = Object.create( Foo ); Bar.speak = function() { alert( "Hello, " + this.identify() + "." ); }; var b1 = Object.create( Bar ); b1.init( "b1" ); var b2 = Object.create( Bar ); b2.init( "b2" ); b1.speak(); b2.speak();
更简洁的设计
示例:
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 // 父类 function Controller() { this.errors = []; } Controller.ptototype.showDialog(title,msg) { // 给用户显示标题和消息 }; Controller.prototype.success = function(msg) { this.showDialog("Success", msg); }; Controller.prototype.failure = function(err) { this.errors.push(err); this.showDialog("Error", err); }; // 子类 function LoginController() { Controller.call(this); } // 把子类关联到父类 LoginController.prototype = Object.create(Controller.prototype); LoginController.prototype.getUser = function() { return document.getElementById("login_username").value; }; LoginController.prototype.getPassword = function() { return docuemnt.getElementById("login_password").value; }; LoginController.prototype.validateEntry = function(user, pw) { user = user || this.getUser(); pw = pw || this.getPassword(); if( !(user && pw) ) { return this.failure( "please enter a username & password!" ); } else if( user.length<5) { return this.failuer( "password must be 5+ characters" ); } // 如果执行到这里表示通过验证 return true; }; // 重写failure() LoginController.prototype.failure = function(err) { // "super" 调用 Controller.prototype.failure.call( this, "Login invalid" + err ); }; // 子类 function AuthController(login) { Controller.call(this); // 合成 this.login = login; } // 把子类关联到父类 AuthController.prototype = Object.crate(Controller.prototype); AuthController.prototype.server = function(url, data) { return $.ajax({ url: url, data: data }); }; AuthController.prototype.checkAuth = function() { var user = this.login.getUser(); var pw = this.login.getPassword(); if (this.login.validateEntry(user.pw)) { this.server( "/check-auth",{ user: user, pw: pw } ) .then( this.success.bind( this ) ) .fail( this.failure.bind( this ) ); } }; // 重写基础的 success() AuthController.prototype.success = function() { //“super”调用 Controller.prototype.success.call( this, "Authenticated!" ); }; // 重写基础的 failure() AuthController.prototype.failure = function(err) { //“super”调用 Controller.prototype.failure.call( this, "Auth Failed: " + err ); }; var auth = new AuthController(); auth.checkAuth( // 除了继承,我们还需要合成 new LoginController() );
对象关联:
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 var LoginController = { errors: [], getUser: function() { return document.getElementById( "login_username" ).value; }, getPassword: function() { return document.getElementById( "login_password" ).value; }, validateEntry: function(user,pw) { user = user || this.getUser(); pw = pw || this.getPassword(); if (!(user && pw)) { return this.failure( "Please enter a username & password!" ); } else if (user.length < 5) { return this.failure( "Password must be 5+ characters!" ); } // 如果执行到这里说明通过验证 return true; }, showDialog: function(title,msg) { // 给用户显示标题和消息 }, failure: function(err) { this.errors.push( err ); this.showDialog( "Error", "Login invalid: " + err ); } }; // 让 AuthController 委托 LoginController var AuthController = Object.create( LoginController ); AuthController.errors = []; AuthController.checkAuth = function() { var user = this.getUser(); var pw = this.getPassword(); if (this.validateEntry( user, pw )) { this.server( "/check-auth",{ user: user, pw: pw } ) .then( this.accepted.bind( this ) ) .fail( this.rejected.bind( this ) ); } }; AuthController.server = function(url,data) { return $.ajax( { url: url, data: data } ); }; AuthController.accepted = function() { this.showDialog( "Success", "Authenticated!" ) }; AuthController.rejected = function(err) { this.failure( "Auth Failed: " + err ); };
更好的语法
示例:
1 class Foo { methodName() { /* .. */ } }
个人专题 📚力扣 (LeetCode)题目
📚掘金文章
❤️关注+点赞+收藏+评论+转发❤️
点赞、收藏和评论 我是Jeskson
(达达前端),感谢各位人才的:点赞、收藏和评论 ,我们下期见!(如本文内容有地方讲解有误,欢迎指出☞谢谢,一起学习了 )
我们下期见!
文章持续更新,可以微信搜一搜「 程序员哆啦A梦 」第一时间阅读,回复【资料】有我准备的一线大厂资料,本文 https://www.1024bibi.com 已经收录
github
收录,欢迎Star
:https://github.com/webVueBlog/WebFamily